webpack.config.base.js 5.2 KB

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