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.

320 lines
7.9 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
  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. },
  75. optimization: {
  76. minimizer: [
  77. new TerserPlugin({
  78. cache: true,
  79. parallel: true,
  80. sourceMap: true,
  81. terserOptions: {
  82. ecma: 8,
  83. // Keep the class names otherwise @log won't provide a useful name
  84. // eslint-disable-next-line @typescript-eslint/camelcase
  85. keep_classnames: true,
  86. module: true
  87. }
  88. })
  89. ]
  90. },
  91. externals: {
  92. vscode: 'commonjs vscode'
  93. },
  94. module: {
  95. rules: [
  96. {
  97. exclude: /\.d\.ts$/,
  98. include: path.resolve(__dirname, 'src'),
  99. test: /\.tsx?$/,
  100. use: {
  101. loader: 'ts-loader',
  102. options: {
  103. experimentalWatchApi: true,
  104. transpileOnly: true
  105. }
  106. }
  107. }
  108. ]
  109. },
  110. resolve: {
  111. extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
  112. symlinks: false
  113. },
  114. plugins: plugins,
  115. stats: {
  116. all: false,
  117. assets: true,
  118. builtAt: true,
  119. env: true,
  120. errors: true,
  121. timings: true,
  122. warnings: true
  123. }
  124. };
  125. }
  126. function getWebviewsConfig(env) {
  127. const clean = ['**/*'];
  128. if (env.optimizeImages) {
  129. console.log('Optimizing images (src/webviews/apps/images/settings/*.png)...');
  130. clean.push(path.resolve(__dirname, 'images/settings/*'));
  131. }
  132. const cspPolicy = {
  133. 'default-src': "'none'",
  134. 'img-src': ['vscode-resource:', 'https:', 'data:'],
  135. 'script-src': ['vscode-resource:', "'nonce-Z2l0bGVucy1ib290c3RyYXA='"],
  136. 'style-src': ['vscode-resource:']
  137. };
  138. if (!env.production) {
  139. cspPolicy['script-src'].push("'unsafe-eval'");
  140. }
  141. /**
  142. * @type any[]
  143. */
  144. const plugins = [
  145. new CleanPlugin({ cleanOnceBeforeBuildPatterns: clean }),
  146. // new ESLintPlugin({
  147. // context: path.resolve(__dirname, 'src/webviews/apps'),
  148. // files: '**/*.ts',
  149. // lintDirtyModulesOnly: true
  150. // }),
  151. new ForkTsCheckerPlugin({
  152. tsconfig: path.resolve(__dirname, 'tsconfig.webviews.json'),
  153. async: false,
  154. eslint: true,
  155. useTypescriptIncrementalApi: true
  156. }),
  157. new MiniCssExtractPlugin({
  158. filename: '[name].css'
  159. }),
  160. new HtmlPlugin({
  161. excludeAssets: [/.+-styles\.js/],
  162. excludeChunks: ['welcome'],
  163. template: 'settings/index.html',
  164. filename: path.resolve(__dirname, 'dist/webviews/settings.html'),
  165. inject: true,
  166. inlineSource: env.production ? '.css$' : undefined,
  167. cspPlugin: {
  168. enabled: true,
  169. policy: cspPolicy,
  170. nonceEnabled: {
  171. 'script-src': true,
  172. 'style-src': true
  173. }
  174. },
  175. minify: env.production
  176. ? {
  177. removeComments: true,
  178. collapseWhitespace: true,
  179. removeRedundantAttributes: false,
  180. useShortDoctype: true,
  181. removeEmptyAttributes: true,
  182. removeStyleLinkTypeAttributes: true,
  183. keepClosingSlash: true,
  184. minifyCSS: true
  185. }
  186. : false
  187. }),
  188. new HtmlPlugin({
  189. excludeAssets: [/.+-styles\.js/],
  190. excludeChunks: ['settings'],
  191. template: 'welcome/index.html',
  192. filename: path.resolve(__dirname, 'dist/webviews/welcome.html'),
  193. inject: true,
  194. inlineSource: env.production ? '.css$' : undefined,
  195. cspPlugin: {
  196. enabled: true,
  197. policy: cspPolicy,
  198. nonceEnabled: {
  199. 'script-src': true,
  200. 'style-src': true
  201. }
  202. },
  203. minify: env.production
  204. ? {
  205. removeComments: true,
  206. collapseWhitespace: true,
  207. removeRedundantAttributes: false,
  208. useShortDoctype: true,
  209. removeEmptyAttributes: true,
  210. removeStyleLinkTypeAttributes: true,
  211. keepClosingSlash: true,
  212. minifyCSS: true
  213. }
  214. : false
  215. }),
  216. new HtmlExcludeAssetsPlugin(),
  217. new CspHtmlPlugin(),
  218. new ImageminPlugin({
  219. disable: !env.optimizeImages,
  220. externalImages: {
  221. context: path.resolve(__dirname, 'src/webviews/apps/images'),
  222. sources: glob.sync('src/webviews/apps/images/settings/*.png'),
  223. destination: path.resolve(__dirname, 'images')
  224. },
  225. cacheFolder: path.resolve(__dirname, 'node_modules', '.cache', 'imagemin-webpack-plugin'),
  226. gifsicle: null,
  227. jpegtran: null,
  228. optipng: null,
  229. pngquant: {
  230. quality: '85-100',
  231. speed: env.production ? 1 : 10
  232. },
  233. svgo: null
  234. }),
  235. new HtmlInlineSourcePlugin()
  236. ];
  237. return {
  238. name: 'webviews',
  239. context: path.resolve(__dirname, 'src/webviews/apps'),
  240. entry: {
  241. 'main-styles': ['./scss/main.scss'],
  242. settings: ['./settings/index.ts'],
  243. welcome: ['./welcome/index.ts']
  244. },
  245. mode: env.production ? 'production' : 'development',
  246. devtool: env.production ? undefined : 'eval-source-map',
  247. output: {
  248. filename: '[name].js',
  249. path: path.resolve(__dirname, 'dist/webviews'),
  250. publicPath: '#{root}/dist/webviews/'
  251. },
  252. module: {
  253. rules: [
  254. {
  255. exclude: /\.d\.ts$/,
  256. include: path.resolve(__dirname, 'src'),
  257. test: /\.tsx?$/,
  258. use: {
  259. loader: 'ts-loader',
  260. options: {
  261. configFile: 'tsconfig.webviews.json',
  262. experimentalWatchApi: true,
  263. transpileOnly: true
  264. }
  265. }
  266. },
  267. {
  268. test: /\.scss$/,
  269. use: [
  270. {
  271. loader: MiniCssExtractPlugin.loader
  272. },
  273. {
  274. loader: 'css-loader',
  275. options: {
  276. sourceMap: true,
  277. url: false
  278. }
  279. },
  280. {
  281. loader: 'sass-loader',
  282. options: {
  283. sourceMap: true
  284. }
  285. }
  286. ],
  287. exclude: /node_modules/
  288. }
  289. ]
  290. },
  291. resolve: {
  292. extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
  293. modules: [path.resolve(__dirname, 'src/webviews/apps'), 'node_modules'],
  294. symlinks: false
  295. },
  296. plugins: plugins,
  297. stats: {
  298. all: false,
  299. assets: true,
  300. builtAt: true,
  301. env: true,
  302. errors: true,
  303. timings: true,
  304. warnings: true
  305. }
  306. };
  307. }