build: Wrap bundles using webpack (#25557)

This commit is contained in:
Julie Koubová 2020-10-20 21:10:15 +02:00 committed by GitHub
parent f7945ade07
commit 56d1fafe66
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 169 additions and 178 deletions

View file

@ -1,2 +0,0 @@
process.env.PRINT_WEBPACK_GRAPH = true;
require('./run-compiler');

View file

@ -1,45 +0,0 @@
const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
const configPath = process.argv[2];
const outPath = path.resolve(process.argv[3]);
const config = require(configPath);
config.output = {
path: path.dirname(outPath),
filename: path.basename(outPath)
};
const { wrapInitWithProfilingTimeout, wrapInitWithTryCatch, ...webpackConfig } = config;
webpack(webpackConfig, (err, stats) => {
if (err) {
console.error(err);
process.exit(1);
} else if (stats.hasErrors()) {
console.error(stats.toString('normal'));
process.exit(1);
} else {
let contents = fs.readFileSync(outPath, 'utf8');
if (wrapInitWithTryCatch) {
contents = `try {
${contents}
} catch (err) {
console.error('Electron ${webpackConfig.output.filename} script failed to run');
console.error(err);
}`;
}
if (wrapInitWithProfilingTimeout) {
contents = `function ___electron_webpack_init__() {
${contents}
};
if ((globalThis.process || binding.process).argv.includes("--profile-electron-init")) {
setTimeout(___electron_webpack_init__, 0);
} else {
___electron_webpack_init__();
}`;
}
fs.writeFileSync(outPath, contents);
process.exit(0);
}
});

View file

@ -2,16 +2,12 @@ const fs = require('fs');
const path = require('path'); const path = require('path');
const webpack = require('webpack'); const webpack = require('webpack');
const TerserPlugin = require('terser-webpack-plugin'); const TerserPlugin = require('terser-webpack-plugin');
const WrapperPlugin = require('wrapper-webpack-plugin');
const electronRoot = path.resolve(__dirname, '../..'); const electronRoot = path.resolve(__dirname, '../..');
const onlyPrintingGraph = !!process.env.PRINT_WEBPACK_GRAPH;
class AccessDependenciesPlugin { class AccessDependenciesPlugin {
apply (compiler) { apply (compiler) {
// Only hook into webpack when we are printing the dependency graph
if (!onlyPrintingGraph) return;
compiler.hooks.compilation.tap('AccessDependenciesPlugin', compilation => { compiler.hooks.compilation.tap('AccessDependenciesPlugin', compilation => {
compilation.hooks.finishModules.tap('AccessDependenciesPlugin', modules => { compilation.hooks.finishModules.tap('AccessDependenciesPlugin', modules => {
const filePaths = modules.map(m => m.resource).filter(p => p).map(p => path.relative(electronRoot, p)); const filePaths = modules.map(m => m.resource).filter(p => p).map(p => path.relative(electronRoot, p));
@ -21,49 +17,6 @@ class AccessDependenciesPlugin {
} }
} }
const defines = {
BUILDFLAG: onlyPrintingGraph ? '(a => a)' : ''
};
const buildFlagsPrefix = '--buildflags=';
const buildFlagArg = process.argv.find(arg => arg.startsWith(buildFlagsPrefix));
if (buildFlagArg) {
const buildFlagPath = buildFlagArg.substr(buildFlagsPrefix.length);
const flagFile = fs.readFileSync(buildFlagPath, 'utf8');
for (const line of flagFile.split(/(\r\n|\r|\n)/g)) {
const flagMatch = line.match(/#define BUILDFLAG_INTERNAL_(.+?)\(\) \(([01])\)/);
if (flagMatch) {
const [, flagName, flagValue] = flagMatch;
defines[flagName] = JSON.stringify(Boolean(parseInt(flagValue, 10)));
}
}
}
const ignoredModules = [];
if (defines.ENABLE_DESKTOP_CAPTURER === 'false') {
ignoredModules.push(
'@electron/internal/browser/desktop-capturer',
'@electron/internal/browser/api/desktop-capturer',
'@electron/internal/renderer/api/desktop-capturer'
);
}
if (defines.ENABLE_REMOTE_MODULE === 'false') {
ignoredModules.push(
'@electron/internal/browser/remote/server',
'@electron/internal/renderer/api/remote'
);
}
if (defines.ENABLE_VIEWS_API === 'false') {
ignoredModules.push(
'@electron/internal/browser/api/views/image-view.js'
);
}
module.exports = ({ module.exports = ({
alwaysHasNode, alwaysHasNode,
loadElectronFromAlternateTarget, loadElectronFromAlternateTarget,
@ -79,76 +32,148 @@ module.exports = ({
const electronAPIFile = path.resolve(electronRoot, 'lib', loadElectronFromAlternateTarget || target, 'api', 'exports', 'electron.ts'); const electronAPIFile = path.resolve(electronRoot, 'lib', loadElectronFromAlternateTarget || target, 'api', 'exports', 'electron.ts');
return ({ return (env = {}, argv = {}) => {
mode: 'development', const onlyPrintingGraph = !!env.PRINT_WEBPACK_GRAPH;
devtool: false, const outputFilename = argv['output-filename'] || `${target}.bundle.js`;
entry,
target: alwaysHasNode ? 'node' : 'web', const defines = {
output: { BUILDFLAG: onlyPrintingGraph ? '(a => a)' : ''
filename: `${target}.bundle.js` };
},
wrapInitWithProfilingTimeout, if (env.buildflags) {
wrapInitWithTryCatch, const flagFile = fs.readFileSync(env.buildflags, 'utf8');
resolve: { for (const line of flagFile.split(/(\r\n|\r|\n)/g)) {
alias: { const flagMatch = line.match(/#define BUILDFLAG_INTERNAL_(.+?)\(\) \(([01])\)/);
'@electron/internal': path.resolve(electronRoot, 'lib'), if (flagMatch) {
electron$: electronAPIFile, const [, flagName, flagValue] = flagMatch;
'electron/main$': electronAPIFile, defines[flagName] = JSON.stringify(Boolean(parseInt(flagValue, 10)));
'electron/renderer$': electronAPIFile,
'electron/common$': electronAPIFile,
// Force timers to resolve to our dependency that doesn't use window.postMessage
timers: path.resolve(electronRoot, 'node_modules', 'timers-browserify', 'main.js')
},
extensions: ['.ts', '.js']
},
module: {
rules: [{
test: (moduleName) => !onlyPrintingGraph && ignoredModules.includes(moduleName),
loader: 'null-loader'
}, {
test: /\.ts$/,
loader: 'ts-loader',
options: {
configFile: path.resolve(electronRoot, 'tsconfig.electron.json'),
transpileOnly: onlyPrintingGraph,
ignoreDiagnostics: [
// File '{0}' is not under 'rootDir' '{1}'.
6059
]
} }
}] }
}, }
node: {
__dirname: false, const ignoredModules = [];
__filename: false,
// We provide our own "timers" import above, any usage of setImmediate inside if (defines.ENABLE_DESKTOP_CAPTURER === 'false') {
// one of our renderer bundles should import it from the 'timers' package ignoredModules.push(
setImmediate: false '@electron/internal/browser/desktop-capturer',
}, '@electron/internal/browser/api/desktop-capturer',
optimization: { '@electron/internal/renderer/api/desktop-capturer'
minimize: true, );
minimizer: [ }
new TerserPlugin({
terserOptions: { if (defines.ENABLE_REMOTE_MODULE === 'false') {
keep_classnames: true, ignoredModules.push(
keep_fnames: true '@electron/internal/browser/remote/server',
} '@electron/internal/renderer/api/remote'
}) );
] }
},
plugins: [ if (defines.ENABLE_VIEWS_API === 'false') {
new AccessDependenciesPlugin(), ignoredModules.push(
...(targetDeletesNodeGlobals ? [ '@electron/internal/browser/api/views/image-view.js'
new webpack.ProvidePlugin({ );
process: ['@electron/internal/common/webpack-provider', 'process'], }
global: ['@electron/internal/common/webpack-provider', '_global'],
Buffer: ['@electron/internal/common/webpack-provider', 'Buffer'] const plugins = [];
})
] : []), if (onlyPrintingGraph) {
new webpack.ProvidePlugin({ plugins.push(new AccessDependenciesPlugin());
Promise: ['@electron/internal/common/webpack-globals-provider', 'Promise'] }
}),
new webpack.DefinePlugin(defines) if (targetDeletesNodeGlobals) {
] plugins.push(new webpack.ProvidePlugin({
}); process: ['@electron/internal/common/webpack-provider', 'process'],
global: ['@electron/internal/common/webpack-provider', '_global'],
Buffer: ['@electron/internal/common/webpack-provider', 'Buffer']
}));
}
plugins.push(new webpack.ProvidePlugin({
Promise: ['@electron/internal/common/webpack-globals-provider', 'Promise']
}));
plugins.push(new webpack.DefinePlugin(defines));
if (wrapInitWithProfilingTimeout) {
plugins.push(new WrapperPlugin({
header: 'function ___electron_webpack_init__() {',
footer: `
};
if ((globalThis.process || binding.process).argv.includes("--profile-electron-init")) {
setTimeout(___electron_webpack_init__, 0);
} else {
___electron_webpack_init__();
}`
}));
}
if (wrapInitWithTryCatch) {
plugins.push(new WrapperPlugin({
header: 'try {',
footer: `
} catch (err) {
console.error('Electron ${outputFilename} script failed to run');
console.error(err);
}`
}));
}
return {
mode: 'development',
devtool: false,
entry,
target: alwaysHasNode ? 'node' : 'web',
output: {
filename: outputFilename
},
resolve: {
alias: {
'@electron/internal': path.resolve(electronRoot, 'lib'),
electron$: electronAPIFile,
'electron/main$': electronAPIFile,
'electron/renderer$': electronAPIFile,
'electron/common$': electronAPIFile,
// Force timers to resolve to our dependency that doesn't use window.postMessage
timers: path.resolve(electronRoot, 'node_modules', 'timers-browserify', 'main.js')
},
extensions: ['.ts', '.js']
},
module: {
rules: [{
test: (moduleName) => !onlyPrintingGraph && ignoredModules.includes(moduleName),
loader: 'null-loader'
}, {
test: /\.ts$/,
loader: 'ts-loader',
options: {
configFile: path.resolve(electronRoot, 'tsconfig.electron.json'),
transpileOnly: onlyPrintingGraph,
ignoreDiagnostics: [
// File '{0}' is not under 'rootDir' '{1}'.
6059
]
}
}]
},
node: {
__dirname: false,
__filename: false,
// We provide our own "timers" import above, any usage of setImmediate inside
// one of our renderer bundles should import it from the 'timers' package
setImmediate: false
},
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
keep_classnames: true,
keep_fnames: true
}
})
]
},
plugins
};
};
}; };

View file

@ -16,7 +16,6 @@ template("webpack_build") {
inputs = [ inputs = [
invoker.config_file, invoker.config_file,
"//electron/build/webpack/webpack.config.base.js", "//electron/build/webpack/webpack.config.base.js",
"//electron/build/webpack/run-compiler.js",
"//electron/tsconfig.json", "//electron/tsconfig.json",
"//electron/yarn.lock", "//electron/yarn.lock",
"//electron/typings/internal-ambient.d.ts", "//electron/typings/internal-ambient.d.ts",
@ -24,9 +23,12 @@ template("webpack_build") {
] + invoker.inputs ] + invoker.inputs
args = [ args = [
"--config",
rebase_path(invoker.config_file), rebase_path(invoker.config_file),
rebase_path(invoker.out_file), "--output-filename=" + get_path_info(invoker.out_file, "file"),
"--buildflags=" + rebase_path("$target_gen_dir/buildflags/buildflags.h"), "--output-path=" + rebase_path(get_path_info(invoker.out_file, "dir")),
"--env.buildflags=" +
rebase_path("$target_gen_dir/buildflags/buildflags.h"),
] ]
deps += [ "buildflags" ] deps += [ "buildflags" ]

View file

@ -63,7 +63,8 @@
"ts-node": "6.2.0", "ts-node": "6.2.0",
"typescript": "^4.0.2", "typescript": "^4.0.2",
"webpack": "^4.43.0", "webpack": "^4.43.0",
"webpack-cli": "^3.3.12" "webpack-cli": "^3.3.12",
"wrapper-webpack-plugin": "^2.1.0"
}, },
"private": true, "private": true,
"scripts": { "scripts": {
@ -91,7 +92,7 @@
"start": "node ./script/start.js", "start": "node ./script/start.js",
"test": "node ./script/spec-runner.js", "test": "node ./script/spec-runner.js",
"tsc": "tsc", "tsc": "tsc",
"webpack": "node build/webpack/run-compiler" "webpack": "webpack"
}, },
"license": "MIT", "license": "MIT",
"author": "Electron Community", "author": "Electron Community",
@ -141,4 +142,4 @@
"@types/temp": "^0.8.34", "@types/temp": "^0.8.34",
"aws-sdk": "^2.727.1" "aws-sdk": "^2.727.1"
} }
} }

View file

@ -46,9 +46,12 @@ const main = async () => {
const webpackTargetsWithDeps = await Promise.all(webpackTargets.map(async webpackTarget => { const webpackTargetsWithDeps = await Promise.all(webpackTargets.map(async webpackTarget => {
const tmpDir = await fs.mkdtemp(path.resolve(os.tmpdir(), 'electron-filenames-')); const tmpDir = await fs.mkdtemp(path.resolve(os.tmpdir(), 'electron-filenames-'));
const child = cp.spawn('node', [ const child = cp.spawn('node', [
'build/webpack/get-outputs.js', './node_modules/webpack-cli/bin/cli.js',
`./${webpackTarget.config}`, '--config', `./build/webpack/${webpackTarget.config}`,
path.resolve(tmpDir, `${webpackTarget.name}.measure.js`) '--display', 'errors-only',
`--output-path=${tmpDir}`,
`--output-filename=${webpackTarget.name}.measure.js`,
'--env.PRINT_WEBPACK_GRAPH'
], { ], {
cwd: path.resolve(__dirname, '..') cwd: path.resolve(__dirname, '..')
}); });

View file

@ -424,7 +424,7 @@ node::Environment* NodeBindings::CreateEnvironment(
DCHECK(env); DCHECK(env);
// This will only be caught when something has gone terrible wrong as all // This will only be caught when something has gone terrible wrong as all
// electron scripts are wrapped in a try {} catch {} in run-compiler.js // electron scripts are wrapped in a try {} catch {} by webpack
if (try_catch.HasCaught()) { if (try_catch.HasCaught()) {
LOG(ERROR) << "Failed to initialize node environment in process: " LOG(ERROR) << "Failed to initialize node environment in process: "
<< process_type; << process_type;

View file

@ -29,7 +29,7 @@ v8::MaybeLocal<v8::Value> CompileAndCall(
v8::MaybeLocal<v8::Value> ret = fn->Call( v8::MaybeLocal<v8::Value> ret = fn->Call(
context, v8::Null(isolate), arguments->size(), arguments->data()); context, v8::Null(isolate), arguments->size(), arguments->data());
// This will only be caught when something has gone terrible wrong as all // This will only be caught when something has gone terrible wrong as all
// electron scripts are wrapped in a try {} catch {} in run-compiler.js // electron scripts are wrapped in a try {} catch {} by webpack
if (try_catch.HasCaught()) { if (try_catch.HasCaught()) {
LOG(ERROR) << "Failed to CompileAndCall electron script: " << id; LOG(ERROR) << "Failed to CompileAndCall electron script: " << id;
} }

View file

@ -8151,7 +8151,7 @@ webpack-cli@^3.3.12:
v8-compile-cache "^2.1.1" v8-compile-cache "^2.1.1"
yargs "^13.3.2" yargs "^13.3.2"
webpack-sources@^1.4.0, webpack-sources@^1.4.1: webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1:
version "1.4.3" version "1.4.3"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==
@ -8257,6 +8257,13 @@ wrapped@^1.0.1:
co "3.1.0" co "3.1.0"
sliced "^1.0.1" sliced "^1.0.1"
wrapper-webpack-plugin@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/wrapper-webpack-plugin/-/wrapper-webpack-plugin-2.1.0.tgz#2b5d80f46af84c9eeb707d08796a115e233adeac"
integrity sha512-e+2FhSYGCxhDq3PcUw5mRhH+8vcYa+9d9AuLChJUZ9ZbUPhQOHZ/O2dnN98iTqeUuvrzSSOv13+x/NhrAm5JEg==
dependencies:
webpack-sources "^1.1.0"
wrappy@1: wrappy@1:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"