webpack.config.base.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. const TerserPlugin = require('terser-webpack-plugin');
  2. const webpack = require('webpack');
  3. const WrapperPlugin = require('wrapper-webpack-plugin');
  4. const fs = require('node:fs');
  5. const path = require('node:path');
  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. const plugins = [];
  48. if (onlyPrintingGraph) {
  49. plugins.push(new AccessDependenciesPlugin());
  50. }
  51. if (targetDeletesNodeGlobals) {
  52. plugins.push(new webpack.ProvidePlugin({
  53. Buffer: ['@electron/internal/common/webpack-provider', 'Buffer'],
  54. global: ['@electron/internal/common/webpack-provider', '_global'],
  55. process: ['@electron/internal/common/webpack-provider', 'process']
  56. }));
  57. }
  58. // Webpack 5 no longer polyfills process or Buffer.
  59. if (!alwaysHasNode) {
  60. plugins.push(new webpack.ProvidePlugin({
  61. Buffer: ['buffer', 'Buffer'],
  62. process: 'process/browser'
  63. }));
  64. }
  65. plugins.push(new webpack.ProvidePlugin({
  66. Promise: ['@electron/internal/common/webpack-globals-provider', 'Promise']
  67. }));
  68. plugins.push(new webpack.DefinePlugin(defines));
  69. if (wrapInitWithProfilingTimeout) {
  70. plugins.push(new WrapperPlugin({
  71. header: 'function ___electron_webpack_init__() {',
  72. footer: `
  73. };
  74. if ((globalThis.process || binding.process).argv.includes("--profile-electron-init")) {
  75. setTimeout(___electron_webpack_init__, 0);
  76. } else {
  77. ___electron_webpack_init__();
  78. }`
  79. }));
  80. }
  81. if (wrapInitWithTryCatch) {
  82. plugins.push(new WrapperPlugin({
  83. header: 'try {',
  84. footer: `
  85. } catch (err) {
  86. console.error('Electron ${outputFilename} script failed to run');
  87. console.error(err);
  88. }`
  89. }));
  90. }
  91. return {
  92. mode: 'development',
  93. devtool: false,
  94. entry,
  95. target: alwaysHasNode ? 'node' : 'web',
  96. output: {
  97. filename: outputFilename
  98. },
  99. resolve: {
  100. alias: {
  101. '@electron/internal': path.resolve(electronRoot, 'lib'),
  102. electron$: electronAPIFile,
  103. 'electron/main$': electronAPIFile,
  104. 'electron/renderer$': electronAPIFile,
  105. 'electron/common$': electronAPIFile,
  106. // Force timers to resolve to our dependency that doesn't use window.postMessage
  107. timers: path.resolve(electronRoot, 'node_modules', 'timers-browserify', 'main.js')
  108. },
  109. extensions: ['.ts', '.js'],
  110. fallback: {
  111. // We provide our own "timers" import above, any usage of setImmediate inside
  112. // one of our renderer bundles should import it from the 'timers' package
  113. setImmediate: false
  114. }
  115. },
  116. module: {
  117. rules: [{
  118. test: (moduleName) => !onlyPrintingGraph && ignoredModules.includes(moduleName),
  119. loader: 'null-loader'
  120. }, {
  121. test: /\.ts$/,
  122. loader: 'ts-loader',
  123. options: {
  124. configFile: path.resolve(electronRoot, 'tsconfig.electron.json'),
  125. transpileOnly: onlyPrintingGraph,
  126. ignoreDiagnostics: [
  127. // File '{0}' is not under 'rootDir' '{1}'.
  128. 6059
  129. ]
  130. }
  131. }]
  132. },
  133. node: {
  134. __dirname: false,
  135. __filename: false
  136. },
  137. optimization: {
  138. minimize: env.mode === 'production',
  139. minimizer: [
  140. new TerserPlugin({
  141. terserOptions: {
  142. keep_classnames: true,
  143. keep_fnames: true
  144. }
  145. })
  146. ]
  147. },
  148. plugins
  149. };
  150. };
  151. };