You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

330 lines
8.2 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. 'use strict';
  2. /* eslint-disable @typescript-eslint/no-var-requires */
  3. const fs = require('fs');
  4. const path = require('path');
  5. const glob = require('glob');
  6. const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
  7. const { CleanWebpackPlugin: CleanPlugin } = require('clean-webpack-plugin');
  8. const CircularDependencyPlugin = require('circular-dependency-plugin');
  9. const CspHtmlPlugin = require('csp-html-webpack-plugin');
  10. // const ESLintPlugin = require('eslint-webpack-plugin');
  11. const ForkTsCheckerPlugin = require('fork-ts-checker-webpack-plugin');
  12. const HtmlExcludeAssetsPlugin = require('html-webpack-exclude-assets-plugin');
  13. const HtmlInlineSourcePlugin = require('html-webpack-inline-source-plugin');
  14. const HtmlPlugin = require('html-webpack-plugin');
  15. const ImageminPlugin = require('imagemin-webpack-plugin').default;
  16. const MiniCssExtractPlugin = require('mini-css-extract-plugin');
  17. const TerserPlugin = require('terser-webpack-plugin');
  18. module.exports = function (env, argv) {
  19. env = env || {};
  20. env.analyzeBundle = Boolean(env.analyzeBundle);
  21. env.analyzeDeps = Boolean(env.analyzeDeps);
  22. env.production = env.analyzeBundle || Boolean(env.production);
  23. env.optimizeImages = Boolean(env.optimizeImages) || (env.production && !env.analyzeBundle);
  24. if (!env.optimizeImages && !fs.existsSync(path.resolve(__dirname, 'images/settings'))) {
  25. env.optimizeImages = true;
  26. }
  27. return [getExtensionConfig(env), getWebviewsConfig(env)];
  28. };
  29. function getExtensionConfig(env) {
  30. /**
  31. * @type any[]
  32. */
  33. const plugins = [
  34. new CleanPlugin({ cleanOnceBeforeBuildPatterns: ['**/*', '!**/webviews/**'] }),
  35. // new ESLintPlugin({
  36. // context: path.resolve(__dirname, 'src'),
  37. // files: '**/*.ts',
  38. // lintDirtyModulesOnly: true
  39. // })
  40. new ForkTsCheckerPlugin({
  41. async: false,
  42. eslint: true,
  43. useTypescriptIncrementalApi: true,
  44. }),
  45. ];
  46. if (env.analyzeDeps) {
  47. plugins.push(
  48. new CircularDependencyPlugin({
  49. cwd: __dirname,
  50. exclude: /node_modules/,
  51. failOnError: false,
  52. onDetected: function ({ module: webpackModuleRecord, paths, compilation }) {
  53. if (paths.some(p => p.includes('container.ts'))) return;
  54. compilation.warnings.push(new Error(paths.join(' -> ')));
  55. },
  56. }),
  57. );
  58. }
  59. if (env.analyzeBundle) {
  60. plugins.push(new BundleAnalyzerPlugin());
  61. }
  62. return {
  63. name: 'extension',
  64. entry: './src/extension.ts',
  65. mode: env.production ? 'production' : 'development',
  66. target: 'node',
  67. node: {
  68. __dirname: false,
  69. },
  70. devtool: 'source-map',
  71. output: {
  72. libraryTarget: 'commonjs2',
  73. filename: 'extension.js',
  74. chunkFilename: 'feature-[name].js',
  75. },
  76. optimization: {
  77. minimizer: [
  78. new TerserPlugin({
  79. cache: true,
  80. parallel: true,
  81. sourceMap: true,
  82. terserOptions: {
  83. ecma: 8,
  84. // Keep the class names otherwise @log won't provide a useful name
  85. // eslint-disable-next-line @typescript-eslint/camelcase
  86. keep_classnames: true,
  87. module: true,
  88. },
  89. }),
  90. ],
  91. splitChunks: {
  92. cacheGroups: {
  93. vendors: false,
  94. },
  95. chunks: 'async',
  96. },
  97. },
  98. externals: {
  99. vscode: 'commonjs vscode',
  100. },
  101. module: {
  102. rules: [
  103. {
  104. exclude: /\.d\.ts$/,
  105. include: path.resolve(__dirname, 'src'),
  106. test: /\.tsx?$/,
  107. use: {
  108. loader: 'ts-loader',
  109. options: {
  110. experimentalWatchApi: true,
  111. transpileOnly: true,
  112. },
  113. },
  114. },
  115. ],
  116. },
  117. resolve: {
  118. alias: {
  119. 'universal-user-agent': path.resolve(__dirname, 'node_modules/universal-user-agent/dist-node/index.js'),
  120. },
  121. extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
  122. symlinks: false,
  123. },
  124. plugins: plugins,
  125. stats: {
  126. all: false,
  127. assets: true,
  128. builtAt: true,
  129. env: true,
  130. errors: true,
  131. timings: true,
  132. warnings: true,
  133. },
  134. };
  135. }
  136. function getWebviewsConfig(env) {
  137. const clean = ['**/*'];
  138. if (env.optimizeImages) {
  139. console.log('Optimizing images (src/webviews/apps/images/settings/*.png)...');
  140. clean.push(path.resolve(__dirname, 'images/settings/*'));
  141. }
  142. const cspPolicy = {
  143. 'default-src': "'none'",
  144. 'img-src': ['vscode-resource:', 'https:', 'data:'],
  145. 'script-src': ['vscode-resource:', "'nonce-Z2l0bGVucy1ib290c3RyYXA='"],
  146. 'style-src': ['vscode-resource:'],
  147. };
  148. if (!env.production) {
  149. cspPolicy['script-src'].push("'unsafe-eval'");
  150. }
  151. /**
  152. * @type any[]
  153. */
  154. const plugins = [
  155. new CleanPlugin({ cleanOnceBeforeBuildPatterns: clean }),
  156. // new ESLintPlugin({
  157. // context: path.resolve(__dirname, 'src/webviews/apps'),
  158. // files: '**/*.ts',
  159. // lintDirtyModulesOnly: true
  160. // }),
  161. new ForkTsCheckerPlugin({
  162. tsconfig: path.resolve(__dirname, 'tsconfig.webviews.json'),
  163. async: false,
  164. eslint: true,
  165. useTypescriptIncrementalApi: true,
  166. }),
  167. new MiniCssExtractPlugin({
  168. filename: '[name].css',
  169. }),
  170. new HtmlPlugin({
  171. excludeAssets: [/.+-styles\.js/],
  172. excludeChunks: ['welcome'],
  173. template: 'settings/index.html',
  174. filename: path.resolve(__dirname, 'dist/webviews/settings.html'),
  175. inject: true,
  176. inlineSource: env.production ? '.css$' : undefined,
  177. cspPlugin: {
  178. enabled: true,
  179. policy: cspPolicy,
  180. nonceEnabled: {
  181. 'script-src': true,
  182. 'style-src': true,
  183. },
  184. },
  185. minify: env.production
  186. ? {
  187. removeComments: true,
  188. collapseWhitespace: true,
  189. removeRedundantAttributes: false,
  190. useShortDoctype: true,
  191. removeEmptyAttributes: true,
  192. removeStyleLinkTypeAttributes: true,
  193. keepClosingSlash: true,
  194. minifyCSS: true,
  195. }
  196. : false,
  197. }),
  198. new HtmlPlugin({
  199. excludeAssets: [/.+-styles\.js/],
  200. excludeChunks: ['settings'],
  201. template: 'welcome/index.html',
  202. filename: path.resolve(__dirname, 'dist/webviews/welcome.html'),
  203. inject: true,
  204. inlineSource: env.production ? '.css$' : undefined,
  205. cspPlugin: {
  206. enabled: true,
  207. policy: cspPolicy,
  208. nonceEnabled: {
  209. 'script-src': true,
  210. 'style-src': true,
  211. },
  212. },
  213. minify: env.production
  214. ? {
  215. removeComments: true,
  216. collapseWhitespace: true,
  217. removeRedundantAttributes: false,
  218. useShortDoctype: true,
  219. removeEmptyAttributes: true,
  220. removeStyleLinkTypeAttributes: true,
  221. keepClosingSlash: true,
  222. minifyCSS: true,
  223. }
  224. : false,
  225. }),
  226. new HtmlExcludeAssetsPlugin(),
  227. new CspHtmlPlugin(),
  228. new ImageminPlugin({
  229. disable: !env.optimizeImages,
  230. externalImages: {
  231. context: path.resolve(__dirname, 'src/webviews/apps/images'),
  232. sources: glob.sync('src/webviews/apps/images/settings/*.png'),
  233. destination: path.resolve(__dirname, 'images'),
  234. },
  235. cacheFolder: path.resolve(__dirname, 'node_modules', '.cache', 'imagemin-webpack-plugin'),
  236. gifsicle: null,
  237. jpegtran: null,
  238. optipng: null,
  239. pngquant: {
  240. quality: '85-100',
  241. speed: env.production ? 1 : 10,
  242. },
  243. svgo: null,
  244. }),
  245. new HtmlInlineSourcePlugin(),
  246. ];
  247. return {
  248. name: 'webviews',
  249. context: path.resolve(__dirname, 'src/webviews/apps'),
  250. entry: {
  251. 'main-styles': ['./scss/main.scss'],
  252. settings: ['./settings/index.ts'],
  253. welcome: ['./welcome/index.ts'],
  254. },
  255. mode: env.production ? 'production' : 'development',
  256. devtool: env.production ? undefined : 'eval-source-map',
  257. output: {
  258. filename: '[name].js',
  259. path: path.resolve(__dirname, 'dist/webviews'),
  260. publicPath: '#{root}/dist/webviews/',
  261. },
  262. module: {
  263. rules: [
  264. {
  265. exclude: /\.d\.ts$/,
  266. include: path.resolve(__dirname, 'src'),
  267. test: /\.tsx?$/,
  268. use: {
  269. loader: 'ts-loader',
  270. options: {
  271. configFile: 'tsconfig.webviews.json',
  272. experimentalWatchApi: true,
  273. transpileOnly: true,
  274. },
  275. },
  276. },
  277. {
  278. test: /\.scss$/,
  279. use: [
  280. {
  281. loader: MiniCssExtractPlugin.loader,
  282. },
  283. {
  284. loader: 'css-loader',
  285. options: {
  286. sourceMap: true,
  287. url: false,
  288. },
  289. },
  290. {
  291. loader: 'sass-loader',
  292. options: {
  293. sourceMap: true,
  294. },
  295. },
  296. ],
  297. exclude: /node_modules/,
  298. },
  299. ],
  300. },
  301. resolve: {
  302. extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
  303. modules: [path.resolve(__dirname, 'src/webviews/apps'), 'node_modules'],
  304. symlinks: false,
  305. },
  306. plugins: plugins,
  307. stats: {
  308. all: false,
  309. assets: true,
  310. builtAt: true,
  311. env: true,
  312. errors: true,
  313. timings: true,
  314. warnings: true,
  315. },
  316. };
  317. }