選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

304 行
7.4 KiB

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