webpack.config.base.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. const fs = require('fs');
  2. const path = require('path');
  3. const webpack = require('webpack');
  4. const TerserPlugin = require('terser-webpack-plugin');
  5. const WrapperPlugin = require('wrapper-webpack-plugin');
  6. const electronRoot = path.resolve(__dirname, '../..');
  7. class AccessDependenciesPlugin {
  8. apply (compiler) {
  9. compiler.hooks.compilation.tap('AccessDependenciesPlugin', compilation => {
  10. compilation.hooks.finishModules.tap('AccessDependenciesPlugin', modules => {
  11. const filePaths = modules.map(m => m.resource).filter(p => p).map(p => path.relative(electronRoot, p));
  12. console.info(JSON.stringify(filePaths));
  13. });
  14. });
  15. }
  16. }
  17. module.exports = ({
  18. alwaysHasNode,
  19. loadElectronFromAlternateTarget,
  20. targetDeletesNodeGlobals,
  21. target,
  22. wrapInitWithProfilingTimeout,
  23. wrapInitWithTryCatch
  24. }) => {
  25. let entry = path.resolve(electronRoot, 'lib', target, 'init.ts');
  26. if (!fs.existsSync(entry)) {
  27. entry = path.resolve(electronRoot, 'lib', target, 'init.js');
  28. }
  29. const electronAPIFile = path.resolve(electronRoot, 'lib', loadElectronFromAlternateTarget || target, 'api', 'exports', 'electron.ts');
  30. return (env = {}, argv = {}) => {
  31. const onlyPrintingGraph = !!env.PRINT_WEBPACK_GRAPH;
  32. const outputFilename = argv['output-filename'] || `${target}.bundle.js`;
  33. const defines = {
  34. BUILDFLAG: onlyPrintingGraph ? '(a => a)' : ''
  35. };
  36. if (env.buildflags) {
  37. const flagFile = fs.readFileSync(env.buildflags, 'utf8');
  38. for (const line of flagFile.split(/(\r\n|\r|\n)/g)) {
  39. const flagMatch = line.match(/#define BUILDFLAG_INTERNAL_(.+?)\(\) \(([01])\)/);
  40. if (flagMatch) {
  41. const [, flagName, flagValue] = flagMatch;
  42. defines[flagName] = JSON.stringify(Boolean(parseInt(flagValue, 10)));
  43. }
  44. }
  45. }
  46. const ignoredModules = [];
  47. if (defines.ENABLE_DESKTOP_CAPTURER === 'false') {
  48. ignoredModules.push(
  49. '@electron/internal/browser/desktop-capturer',
  50. '@electron/internal/browser/api/desktop-capturer',
  51. '@electron/internal/renderer/api/desktop-capturer'
  52. );
  53. }
  54. if (defines.ENABLE_VIEWS_API === 'false') {
  55. ignoredModules.push(
  56. '@electron/internal/browser/api/views/image-view.js'
  57. );
  58. }
  59. const plugins = [];
  60. if (onlyPrintingGraph) {
  61. plugins.push(new AccessDependenciesPlugin());
  62. }
  63. if (targetDeletesNodeGlobals) {
  64. plugins.push(new webpack.ProvidePlugin({
  65. Buffer: ['@electron/internal/common/webpack-provider', 'Buffer'],
  66. global: ['@electron/internal/common/webpack-provider', '_global'],
  67. process: ['@electron/internal/common/webpack-provider', 'process']
  68. }));
  69. }
  70. // Webpack 5 no longer polyfills process or Buffer.
  71. if (!alwaysHasNode) {
  72. plugins.push(new webpack.ProvidePlugin({
  73. Buffer: ['buffer', 'Buffer'],
  74. process: 'process/browser'
  75. }));
  76. }
  77. plugins.push(new webpack.ProvidePlugin({
  78. Promise: ['@electron/internal/common/webpack-globals-provider', 'Promise']
  79. }));
  80. plugins.push(new webpack.DefinePlugin(defines));
  81. if (wrapInitWithProfilingTimeout) {
  82. plugins.push(new WrapperPlugin({
  83. header: 'function ___electron_webpack_init__() {',
  84. footer: `
  85. };
  86. if ((globalThis.process || binding.process).argv.includes("--profile-electron-init")) {
  87. setTimeout(___electron_webpack_init__, 0);
  88. } else {
  89. ___electron_webpack_init__();
  90. }`
  91. }));
  92. }
  93. if (wrapInitWithTryCatch) {
  94. plugins.push(new WrapperPlugin({
  95. header: 'try {',
  96. footer: `
  97. } catch (err) {
  98. console.error('Electron ${outputFilename} script failed to run');
  99. console.error(err);
  100. }`
  101. }));
  102. }
  103. return {
  104. mode: 'development',
  105. devtool: false,
  106. entry,
  107. target: alwaysHasNode ? 'node' : 'web',
  108. output: {
  109. filename: outputFilename
  110. },
  111. resolve: {
  112. alias: {
  113. '@electron/internal': path.resolve(electronRoot, 'lib'),
  114. electron$: electronAPIFile,
  115. 'electron/main$': electronAPIFile,
  116. 'electron/renderer$': electronAPIFile,
  117. 'electron/common$': electronAPIFile,
  118. // Force timers to resolve to our dependency that doesn't use window.postMessage
  119. timers: path.resolve(electronRoot, 'node_modules', 'timers-browserify', 'main.js')
  120. },
  121. extensions: ['.ts', '.js'],
  122. fallback: {
  123. // We provide our own "timers" import above, any usage of setImmediate inside
  124. // one of our renderer bundles should import it from the 'timers' package
  125. setImmediate: false
  126. }
  127. },
  128. module: {
  129. rules: [{
  130. test: (moduleName) => !onlyPrintingGraph && ignoredModules.includes(moduleName),
  131. loader: 'null-loader'
  132. }, {
  133. test: /\.ts$/,
  134. loader: 'ts-loader',
  135. options: {
  136. configFile: path.resolve(electronRoot, 'tsconfig.electron.json'),
  137. transpileOnly: onlyPrintingGraph,
  138. ignoreDiagnostics: [
  139. // File '{0}' is not under 'rootDir' '{1}'.
  140. 6059
  141. ]
  142. }
  143. }]
  144. },
  145. node: {
  146. __dirname: false,
  147. __filename: false
  148. },
  149. optimization: {
  150. minimize: env.mode === 'production',
  151. minimizer: [
  152. new TerserPlugin({
  153. terserOptions: {
  154. keep_classnames: true,
  155. keep_fnames: true
  156. }
  157. })
  158. ]
  159. },
  160. plugins
  161. };
  162. };
  163. };