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.

276 line
9.5 KiB

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