278 lines
9.3 KiB

  1. 'use strict';
  2. const fs = require('fs');
  3. const path = require('path');
  4. const glob = require('glob');
  5. const webpack = require('webpack');
  6. const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
  7. const CleanPlugin = require('clean-webpack-plugin');
  8. const CircularDependencyPlugin = require('circular-dependency-plugin');
  9. const HtmlExcludeAssetsPlugin = require('html-webpack-exclude-assets-plugin');
  10. const HtmlInlineSourcePlugin = require('html-webpack-inline-source-plugin');
  11. const HtmlPlugin = require('html-webpack-plugin');
  12. const ImageminPlugin = require('imagemin-webpack-plugin').default;
  13. const MiniCssExtractPlugin = require('mini-css-extract-plugin');
  14. const TerserPlugin = require('terser-webpack-plugin');
  15. module.exports = function(env, argv) {
  16. env = env || {};
  17. env.analyzeBundle = Boolean(env.analyzeBundle);
  18. env.analyzeDeps = Boolean(env.analyzeDeps);
  19. env.production = env.analyzeBundle || Boolean(env.production);
  20. env.optimizeImages = Boolean(env.optimizeImages) || (env.production && !env.analyzeBundle);
  21. if (!env.optimizeImages && !fs.existsSync(path.resolve(__dirname, 'images/settings'))) {
  22. env.optimizeImages = true;
  23. }
  24. return [getExtensionConfig(env), getUIConfig(env)];
  25. };
  26. function getExtensionConfig(env) {
  27. const plugins = [new CleanPlugin(), new webpack.IgnorePlugin(/^spawn-sync$/)];
  28. if (env.analyzeDeps) {
  29. plugins.push(
  30. new CircularDependencyPlugin({
  31. cwd: __dirname,
  32. exclude: /node_modules/,
  33. failOnError: false,
  34. onDetected: function({ module: webpackModuleRecord, paths, compilation }) {
  35. if (paths.some(p => /container\.ts/.test(p))) return;
  36. compilation.warnings.push(new Error(paths.join(' -> ')));
  37. }
  38. })
  39. );
  40. }
  41. if (env.analyzeBundle) {
  42. plugins.push(new BundleAnalyzerPlugin());
  43. }
  44. return {
  45. name: 'extension',
  46. entry: './src/extension.ts',
  47. mode: env.production ? 'production' : 'development',
  48. target: 'node',
  49. node: {
  50. __dirname: false
  51. },
  52. devtool: 'source-map',
  53. output: {
  54. libraryTarget: 'commonjs2',
  55. filename: 'extension.js'
  56. },
  57. optimization: {
  58. minimizer: [
  59. new TerserPlugin({
  60. cache: true,
  61. parallel: true,
  62. sourceMap: true,
  63. terserOptions: {
  64. ecma: 8,
  65. // Keep the class names otherwise @log won't provide a useful name
  66. keep_classnames: true,
  67. module: true
  68. }
  69. })
  70. ]
  71. },
  72. externals: {
  73. vscode: 'commonjs vscode'
  74. },
  75. module: {
  76. rules: [
  77. {
  78. test: /\.ts$/,
  79. enforce: 'pre',
  80. use: [
  81. {
  82. loader: 'eslint-loader',
  83. options: {
  84. cache: true,
  85. failOnError: true
  86. }
  87. }
  88. ],
  89. exclude: /node_modules/
  90. },
  91. {
  92. test: /\.tsx?$/,
  93. use: 'ts-loader',
  94. exclude: /node_modules|\.d\.ts$/
  95. }
  96. ],
  97. // Removes `Critical dependency: the request of a dependency is an expression` from `./node_modules/vsls/vscode.js`
  98. exprContextRegExp: /^$/,
  99. exprContextCritical: false
  100. },
  101. resolve: {
  102. extensions: ['.ts', '.tsx', '.js', '.jsx', '.json']
  103. },
  104. plugins: plugins,
  105. stats: {
  106. all: false,
  107. assets: true,
  108. builtAt: true,
  109. env: true,
  110. errors: true,
  111. timings: true,
  112. warnings: true
  113. }
  114. };
  115. }
  116. function getUIConfig(env) {
  117. const clean = [];
  118. if (env.optimizeImages) {
  119. console.log('Optimizing images (src/webviews/apps/images/settings/*.png)...');
  120. clean.push('images/settings');
  121. }
  122. const plugins = [
  123. new CleanPlugin({ cleanOnceBeforeBuildPatterns: clean }),
  124. new MiniCssExtractPlugin({
  125. filename: '[name].css'
  126. }),
  127. new HtmlPlugin({
  128. excludeAssets: [/main\.js/],
  129. excludeChunks: ['welcome'],
  130. template: 'settings/index.html',
  131. filename: path.resolve(__dirname, 'dist/webviews/settings.html'),
  132. inject: true,
  133. // inlineSource: env.production ? '.(js|css)$' : undefined,
  134. minify: env.production
  135. ? {
  136. removeComments: true,
  137. collapseWhitespace: true,
  138. removeRedundantAttributes: true,
  139. useShortDoctype: true,
  140. removeEmptyAttributes: true,
  141. removeStyleLinkTypeAttributes: true,
  142. keepClosingSlash: true,
  143. minifyCSS: true
  144. }
  145. : false
  146. }),
  147. new HtmlPlugin({
  148. excludeAssets: [/main\.js/],
  149. excludeChunks: ['settings'],
  150. template: 'welcome/index.html',
  151. filename: path.resolve(__dirname, 'dist/webviews/welcome.html'),
  152. inject: true,
  153. // inlineSource: env.production ? '.(js|css)$' : undefined,
  154. minify: env.production
  155. ? {
  156. removeComments: true,
  157. collapseWhitespace: true,
  158. removeRedundantAttributes: true,
  159. useShortDoctype: true,
  160. removeEmptyAttributes: true,
  161. removeStyleLinkTypeAttributes: true,
  162. keepClosingSlash: true,
  163. minifyCSS: true
  164. }
  165. : false
  166. }),
  167. new HtmlExcludeAssetsPlugin(),
  168. new HtmlInlineSourcePlugin(),
  169. new ImageminPlugin({
  170. disable: !env.optimizeImages,
  171. externalImages: {
  172. context: path.resolve(__dirname, 'src/webviews/apps/images'),
  173. sources: glob.sync('src/webviews/apps/images/settings/*.png'),
  174. destination: path.resolve(__dirname, 'images')
  175. },
  176. cacheFolder: path.resolve(__dirname, '.cache-images'),
  177. gifsicle: null,
  178. jpegtran: null,
  179. optipng: null,
  180. pngquant: {
  181. quality: '85-100',
  182. speed: env.production ? 1 : 10
  183. },
  184. svgo: null
  185. })
  186. ];
  187. return {
  188. name: 'webviews',
  189. context: path.resolve(__dirname, 'src/webviews/apps'),
  190. entry: {
  191. main: ['./scss/main.scss'],
  192. settings: ['./settings/index.ts'],
  193. welcome: ['./welcome/index.ts']
  194. },
  195. mode: env.production ? 'production' : 'development',
  196. devtool: env.production ? undefined : 'eval-source-map',
  197. output: {
  198. filename: '[name].js',
  199. path: path.resolve(__dirname, 'dist/webviews'),
  200. publicPath: '{{root}}/dist/webviews/'
  201. },
  202. module: {
  203. rules: [
  204. {
  205. test: /\.ts$/,
  206. enforce: 'pre',
  207. use: [
  208. {
  209. loader: 'eslint-loader',
  210. options: {
  211. cache: true,
  212. failOnError: true
  213. }
  214. }
  215. ],
  216. exclude: /node_modules/
  217. },
  218. {
  219. test: /\.tsx?$/,
  220. use: {
  221. loader: 'ts-loader',
  222. options: {
  223. configFile: 'webviews.tsconfig.json'
  224. }
  225. },
  226. exclude: /node_modules|\.d\.ts$/
  227. },
  228. {
  229. test: /\.scss$/,
  230. use: [
  231. {
  232. loader: MiniCssExtractPlugin.loader
  233. },
  234. {
  235. loader: 'css-loader',
  236. options: {
  237. sourceMap: true,
  238. url: false
  239. }
  240. },
  241. {
  242. loader: 'sass-loader',
  243. options: {
  244. sourceMap: true
  245. }
  246. }
  247. ],
  248. exclude: /node_modules/
  249. }
  250. ]
  251. },
  252. resolve: {
  253. extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
  254. modules: [path.resolve(__dirname, 'src/webviews/apps'), 'node_modules']
  255. },
  256. plugins: plugins,
  257. stats: {
  258. all: false,
  259. assets: true,
  260. builtAt: true,
  261. env: true,
  262. errors: true,
  263. timings: true,
  264. warnings: true
  265. }
  266. };
  267. }