build: compile 4 webpackRendererConfigs instead of N (#3101)
* compile 4 webpackRendererConfigs instead of N. Co-authored-by: Samuel Attard <marshallofsound@electronjs.org> Co-authored-by: Keeley Hammond <vertedinde@electronjs.org> * modify enum * promise all * refactor * fix typing * remove some tests + more * fix bug * add [name]/preload.js * fix some test * alter preload tests * packages now use asset relocator patch * fix test * add additional config per entrypoint config * apply fixes * chore: add webpack tests * clean up assetRelocatorPatch path * add test and fix merge order prioritization * revert webpack merge priority change --------- Co-authored-by: Samuel Attard <marshallofsound@electronjs.org> Co-authored-by: Keeley Hammond <vertedinde@electronjs.org> Co-authored-by: Erick Zhao <erick@hotmail.ca>
This commit is contained in:
Родитель
9ab274d3e6
Коммит
ed45e79c35
|
@ -8,7 +8,7 @@
|
|||
"main": "dist/WebpackPlugin.js",
|
||||
"typings": "dist/WebpackPlugin.d.ts",
|
||||
"scripts": {
|
||||
"test": "xvfb-maybe mocha --config ../../../.mocharc.js test/**/*_spec.ts"
|
||||
"test": "xvfb-maybe mocha --config ../../../.mocharc.js test/**/*_spec.ts test/*_spec.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@malept/cross-spawn-promise": "^2.0.0",
|
||||
|
|
|
@ -8,7 +8,7 @@ import { merge as webpackMerge } from 'webpack-merge';
|
|||
import { WebpackPluginConfig, WebpackPluginEntryPoint, WebpackPluginEntryPointLocalWindow, WebpackPluginEntryPointPreloadOnly } from './Config';
|
||||
import AssetRelocatorPatch from './util/AssetRelocatorPatch';
|
||||
import processConfig from './util/processConfig';
|
||||
import { isLocalWindow, isNoWindow, isPreloadOnly } from './util/rendererTypeUtils';
|
||||
import { isLocalOrNoWindowEntries, isLocalWindow, isNoWindow, isPreloadOnly, isPreloadOnlyEntries } from './util/rendererTypeUtils';
|
||||
|
||||
type EntryType = string | string[] | Record<string, string | string[]>;
|
||||
type WebpackMode = 'production' | 'development';
|
||||
|
@ -20,6 +20,35 @@ export type ConfigurationFactory = (
|
|||
args: Record<string, unknown>
|
||||
) => Configuration | Promise<Configuration>;
|
||||
|
||||
enum RendererTarget {
|
||||
Web,
|
||||
ElectronRenderer,
|
||||
ElectronPreload,
|
||||
SandboxedPreload,
|
||||
}
|
||||
|
||||
enum WebpackTarget {
|
||||
Web = 'web',
|
||||
ElectronPreload = 'electron-preload',
|
||||
ElectronRenderer = 'electron-renderer',
|
||||
}
|
||||
|
||||
function isNotNull<T>(item: T | null): item is T {
|
||||
return item !== null;
|
||||
}
|
||||
|
||||
function rendererTargetToWebpackTarget(target: RendererTarget): WebpackTarget {
|
||||
switch (target) {
|
||||
case RendererTarget.Web:
|
||||
case RendererTarget.SandboxedPreload:
|
||||
return WebpackTarget.Web;
|
||||
case RendererTarget.ElectronPreload:
|
||||
return WebpackTarget.ElectronPreload;
|
||||
case RendererTarget.ElectronRenderer:
|
||||
return WebpackTarget.ElectronRenderer;
|
||||
}
|
||||
}
|
||||
|
||||
export default class WebpackConfigGenerator {
|
||||
private isProd: boolean;
|
||||
|
||||
|
@ -69,10 +98,6 @@ export default class WebpackConfigGenerator {
|
|||
return this.isProd ? 'source-map' : 'eval-source-map';
|
||||
}
|
||||
|
||||
rendererTarget(entryPoint: WebpackPluginEntryPoint): string {
|
||||
return entryPoint.nodeIntegration ?? this.pluginConfig.renderer.nodeIntegration ? 'electron-renderer' : 'web';
|
||||
}
|
||||
|
||||
rendererEntryPoint(entryPoint: WebpackPluginEntryPoint, inRendererDir: boolean, basename: string): string {
|
||||
if (this.isProd) {
|
||||
return `\`file://$\{require('path').resolve(__dirname, '..', '${inRendererDir ? 'renderer' : '.'}', '${entryPoint.name}', '${basename}')}\``;
|
||||
|
@ -163,114 +188,151 @@ export default class WebpackConfigGenerator {
|
|||
);
|
||||
}
|
||||
|
||||
async getPreloadConfigForEntryPoint(entryPoint: WebpackPluginEntryPointLocalWindow | WebpackPluginEntryPointPreloadOnly): Promise<Configuration> {
|
||||
if (!entryPoint.preload) {
|
||||
return {};
|
||||
async getRendererConfig(entryPoints: WebpackPluginEntryPoint[]): Promise<Configuration[]> {
|
||||
const entryPointsForTarget = {
|
||||
web: [] as (WebpackPluginEntryPointLocalWindow | WebpackPluginEntryPoint)[],
|
||||
electronRenderer: [] as (WebpackPluginEntryPointLocalWindow | WebpackPluginEntryPoint)[],
|
||||
electronPreload: [] as WebpackPluginEntryPointPreloadOnly[],
|
||||
sandboxedPreload: [] as WebpackPluginEntryPointPreloadOnly[],
|
||||
};
|
||||
|
||||
for (const entry of entryPoints) {
|
||||
const target = entry.nodeIntegration ?? this.pluginConfig.renderer.nodeIntegration ? 'electronRenderer' : 'web';
|
||||
const preloadTarget = entry.nodeIntegration ?? this.pluginConfig.renderer.nodeIntegration ? 'electronPreload' : 'sandboxedPreload';
|
||||
|
||||
if (isPreloadOnly(entry)) {
|
||||
entryPointsForTarget[preloadTarget].push(entry);
|
||||
} else {
|
||||
entryPointsForTarget[target].push(entry);
|
||||
if (isLocalWindow(entry) && entry.preload) {
|
||||
entryPointsForTarget[preloadTarget].push({ ...entry, preload: entry.preload });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const rendererConfig = await this.resolveConfig(entryPoint.preload.config || this.pluginConfig.renderer.config);
|
||||
const prefixedEntries = entryPoint.prefixedEntries || [];
|
||||
|
||||
return webpackMerge(
|
||||
{
|
||||
devtool: this.rendererSourceMapOption,
|
||||
mode: this.mode,
|
||||
entry: prefixedEntries.concat([entryPoint.preload.js]),
|
||||
output: {
|
||||
path: path.resolve(this.webpackDir, 'renderer', entryPoint.name),
|
||||
filename: 'preload.js',
|
||||
},
|
||||
node: {
|
||||
__dirname: false,
|
||||
__filename: false,
|
||||
},
|
||||
},
|
||||
rendererConfig || {},
|
||||
{ target: 'electron-preload' }
|
||||
const rendererConfigs = await Promise.all(
|
||||
[
|
||||
await this.buildRendererConfigs(entryPointsForTarget.web, RendererTarget.Web),
|
||||
await this.buildRendererConfigs(entryPointsForTarget.electronRenderer, RendererTarget.ElectronRenderer),
|
||||
await this.buildRendererConfigs(entryPointsForTarget.electronPreload, RendererTarget.ElectronPreload),
|
||||
await this.buildRendererConfigs(entryPointsForTarget.sandboxedPreload, RendererTarget.SandboxedPreload),
|
||||
].reduce((configs, allConfigs) => allConfigs.concat(configs))
|
||||
);
|
||||
|
||||
return rendererConfigs.filter(isNotNull);
|
||||
}
|
||||
|
||||
async getRendererConfig(entryPoints: WebpackPluginEntryPoint[]): Promise<Configuration[]> {
|
||||
buildRendererBaseConfig(target: RendererTarget): webpack.Configuration {
|
||||
return {
|
||||
target: rendererTargetToWebpackTarget(target),
|
||||
devtool: this.rendererSourceMapOption,
|
||||
mode: this.mode,
|
||||
output: {
|
||||
path: path.resolve(this.webpackDir, 'renderer'),
|
||||
filename: '[name]/index.js',
|
||||
globalObject: 'self',
|
||||
...(this.isProd ? {} : { publicPath: '/' }),
|
||||
},
|
||||
node: {
|
||||
__dirname: false,
|
||||
__filename: false,
|
||||
},
|
||||
plugins: [new AssetRelocatorPatch(this.isProd, target === RendererTarget.ElectronRenderer || target === RendererTarget.ElectronPreload)],
|
||||
};
|
||||
}
|
||||
|
||||
async buildRendererConfigForWebOrRendererTarget(
|
||||
entryPoints: WebpackPluginEntryPoint[],
|
||||
target: RendererTarget.Web | RendererTarget.ElectronRenderer
|
||||
): Promise<Configuration | null> {
|
||||
if (!isLocalOrNoWindowEntries(entryPoints)) {
|
||||
throw new Error('Invalid renderer entry point detected.');
|
||||
}
|
||||
|
||||
const entry: webpack.Entry = {};
|
||||
const baseConfig: webpack.Configuration = this.buildRendererBaseConfig(target);
|
||||
const rendererConfig = await this.resolveConfig(this.pluginConfig.renderer.config);
|
||||
|
||||
return entryPoints.map((entryPoint) => {
|
||||
const baseConfig: webpack.Configuration = {
|
||||
target: this.rendererTarget(entryPoint),
|
||||
devtool: this.rendererSourceMapOption,
|
||||
mode: this.mode,
|
||||
output: {
|
||||
path: path.resolve(this.webpackDir, 'renderer'),
|
||||
filename: '[name]/index.js',
|
||||
globalObject: 'self',
|
||||
...(this.isProd ? {} : { publicPath: '/' }),
|
||||
},
|
||||
node: {
|
||||
__dirname: false,
|
||||
__filename: false,
|
||||
},
|
||||
plugins: [new AssetRelocatorPatch(this.isProd, !!this.pluginConfig.renderer.nodeIntegration)],
|
||||
};
|
||||
const output = {
|
||||
path: path.resolve(this.webpackDir, 'renderer'),
|
||||
filename: '[name]/index.js',
|
||||
globalObject: 'self',
|
||||
...(this.isProd ? {} : { publicPath: '/' }),
|
||||
};
|
||||
const plugins: webpack.WebpackPluginInstance[] = [];
|
||||
|
||||
for (const entryPoint of entryPoints) {
|
||||
entry[entryPoint.name] = (entryPoint.prefixedEntries || []).concat([entryPoint.js]);
|
||||
|
||||
if (isLocalWindow(entryPoint)) {
|
||||
return webpackMerge(
|
||||
baseConfig,
|
||||
{
|
||||
entry: {
|
||||
[entryPoint.name]: (entryPoint.prefixedEntries || []).concat([entryPoint.js]),
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(this.webpackDir, 'renderer'),
|
||||
filename: '[name]/index.js',
|
||||
globalObject: 'self',
|
||||
...(this.isProd ? {} : { publicPath: '/' }),
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
title: entryPoint.name,
|
||||
template: entryPoint.html,
|
||||
filename: `${entryPoint.name}/index.html`,
|
||||
chunks: [entryPoint.name].concat(entryPoint.additionalChunks || []),
|
||||
}) as WebpackPluginInstance,
|
||||
],
|
||||
},
|
||||
rendererConfig || {}
|
||||
plugins.push(
|
||||
new HtmlWebpackPlugin({
|
||||
title: entryPoint.name,
|
||||
template: entryPoint.html,
|
||||
filename: `${entryPoint.name}/index.html`,
|
||||
chunks: [entryPoint.name].concat(entryPoint.additionalChunks || []),
|
||||
}) as WebpackPluginInstance
|
||||
);
|
||||
} else if (isNoWindow(entryPoint)) {
|
||||
return webpackMerge(
|
||||
baseConfig,
|
||||
{
|
||||
entry: {
|
||||
[entryPoint.name]: (entryPoint.prefixedEntries || []).concat([entryPoint.js]),
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(this.webpackDir, 'renderer'),
|
||||
filename: '[name]/index.js',
|
||||
globalObject: 'self',
|
||||
...(this.isProd ? {} : { publicPath: '/' }),
|
||||
},
|
||||
},
|
||||
rendererConfig || {}
|
||||
);
|
||||
} else if (isPreloadOnly(entryPoint)) {
|
||||
return webpackMerge(
|
||||
baseConfig,
|
||||
{
|
||||
target: 'electron-preload',
|
||||
entry: {
|
||||
[entryPoint.name]: (entryPoint.prefixedEntries || []).concat([entryPoint.preload.js]),
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(this.webpackDir, 'renderer'),
|
||||
filename: 'preload.js',
|
||||
globalObject: 'self',
|
||||
...(this.isProd ? {} : { publicPath: '/' }),
|
||||
},
|
||||
},
|
||||
rendererConfig || {}
|
||||
);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
return webpackMerge(baseConfig, rendererConfig || {}, { entry, output, plugins });
|
||||
}
|
||||
|
||||
async buildRendererConfigForPreloadOrSandboxedPreloadTarget(
|
||||
entryPoints: WebpackPluginEntryPointPreloadOnly[],
|
||||
target: RendererTarget.ElectronPreload | RendererTarget.SandboxedPreload
|
||||
): Promise<Configuration | null> {
|
||||
if (entryPoints.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const externals = ['electron', 'electron/renderer', 'electron/common', 'events', 'timers', 'url'];
|
||||
|
||||
const entry: webpack.Entry = {};
|
||||
const baseConfig: webpack.Configuration = this.buildRendererBaseConfig(target);
|
||||
const rendererConfig = await this.resolveConfig(entryPoints[0].preload?.config || this.pluginConfig.renderer.config);
|
||||
|
||||
for (const entryPoint of entryPoints) {
|
||||
entry[entryPoint.name] = (entryPoint.prefixedEntries || []).concat([entryPoint.preload.js]);
|
||||
}
|
||||
const config: Configuration = {
|
||||
target: rendererTargetToWebpackTarget(target),
|
||||
entry,
|
||||
output: {
|
||||
path: path.resolve(this.webpackDir, 'renderer'),
|
||||
filename: '[name]/preload.js',
|
||||
globalObject: 'self',
|
||||
...(this.isProd ? {} : { publicPath: '/' }),
|
||||
},
|
||||
plugins: target === RendererTarget.ElectronPreload ? [] : [new webpack.ExternalsPlugin('commonjs2', externals)],
|
||||
};
|
||||
return webpackMerge(baseConfig, rendererConfig || {}, config);
|
||||
}
|
||||
|
||||
async buildRendererConfigs(entryPoints: WebpackPluginEntryPoint[], target: RendererTarget): Promise<Promise<webpack.Configuration | null>[]> {
|
||||
if (entryPoints.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const rendererConfigs = [];
|
||||
if (target === RendererTarget.Web || target === RendererTarget.ElectronRenderer) {
|
||||
rendererConfigs.push(this.buildRendererConfigForWebOrRendererTarget(entryPoints, target));
|
||||
return rendererConfigs;
|
||||
} else if (target === RendererTarget.ElectronPreload || target === RendererTarget.SandboxedPreload) {
|
||||
if (!isPreloadOnlyEntries(entryPoints)) {
|
||||
throw new Error('Invalid renderer entry point detected.');
|
||||
}
|
||||
});
|
||||
|
||||
const entryPointsWithPreloadConfig: WebpackPluginEntryPointPreloadOnly[] = [],
|
||||
entryPointsWithoutPreloadConfig: WebpackPluginEntryPointPreloadOnly[] = [];
|
||||
entryPoints.forEach((entryPoint) => (entryPoint.preload.config ? entryPointsWithPreloadConfig : entryPointsWithoutPreloadConfig).push(entryPoint));
|
||||
|
||||
rendererConfigs.push(this.buildRendererConfigForPreloadOrSandboxedPreloadTarget(entryPointsWithoutPreloadConfig, target));
|
||||
entryPointsWithPreloadConfig.forEach((entryPoint) => {
|
||||
rendererConfigs.push(this.buildRendererConfigForPreloadOrSandboxedPreloadTarget([entryPoint], target));
|
||||
});
|
||||
return rendererConfigs;
|
||||
} else {
|
||||
throw new Error('Invalid renderer entry point detected.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ import { merge } from 'webpack-merge';
|
|||
import { WebpackPluginConfig } from './Config';
|
||||
import ElectronForgeLoggingPlugin from './util/ElectronForgeLogging';
|
||||
import once from './util/once';
|
||||
import { isLocalWindow, isPreloadOnly } from './util/rendererTypeUtils';
|
||||
import WebpackConfigGenerator from './WebpackConfig';
|
||||
|
||||
const d = debug('electron-forge:plugin:webpack');
|
||||
|
@ -281,34 +280,17 @@ the generated files). Instead, it is ${JSON.stringify(pj.main)}`);
|
|||
if (!watch && stats?.hasErrors()) {
|
||||
throw new Error(`Compilation errors in the renderer: ${stats.toString()}`);
|
||||
}
|
||||
|
||||
for (const entryPoint of this.config.renderer.entryPoints) {
|
||||
if ((isLocalWindow(entryPoint) && !!entryPoint.preload) || isPreloadOnly(entryPoint)) {
|
||||
const stats = await this.runWebpack(
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
[await this.configGenerator.getPreloadConfigForEntryPoint(entryPoint)]
|
||||
);
|
||||
|
||||
if (stats?.hasErrors()) {
|
||||
throw new Error(`Compilation errors in the preload (${entryPoint.name}): ${stats.toString()}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
launchRendererDevServers = async (logger: Logger): Promise<void> => {
|
||||
const tab = logger.createTab('Renderers');
|
||||
const pluginLogs = new ElectronForgeLoggingPlugin(tab);
|
||||
|
||||
const config = await this.configGenerator.getRendererConfig(this.config.renderer.entryPoints);
|
||||
|
||||
if (config.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const entryConfig of config) {
|
||||
if (!entryConfig.plugins) entryConfig.plugins = [];
|
||||
entryConfig.plugins.push(pluginLogs);
|
||||
entryConfig.plugins.push(new ElectronForgeLoggingPlugin(logger.createTab(`Renderer Target Bundle (${entryConfig.target})`)));
|
||||
|
||||
entryConfig.infrastructureLogging = {
|
||||
level: 'none',
|
||||
|
@ -320,35 +302,6 @@ the generated files). Instead, it is ${JSON.stringify(pj.main)}`);
|
|||
const webpackDevServer = new WebpackDevServer(this.devServerOptions(), compiler);
|
||||
await webpackDevServer.start();
|
||||
this.servers.push(webpackDevServer.server!);
|
||||
|
||||
for (const entryPoint of this.config.renderer.entryPoints) {
|
||||
if ((isLocalWindow(entryPoint) && !!entryPoint.preload) || isPreloadOnly(entryPoint)) {
|
||||
const config = await this.configGenerator.getPreloadConfigForEntryPoint(entryPoint);
|
||||
config.infrastructureLogging = {
|
||||
level: 'none',
|
||||
};
|
||||
config.stats = 'none';
|
||||
await new Promise((resolve, reject) => {
|
||||
const tab = logger.createTab(`${entryPoint.name} - Preload`);
|
||||
const [onceResolve, onceReject] = once(resolve, reject);
|
||||
|
||||
this.watchers.push(
|
||||
webpack(config).watch({}, (err, stats) => {
|
||||
if (stats) {
|
||||
tab.log(
|
||||
stats.toString({
|
||||
colors: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (err) return onceReject(err);
|
||||
return onceResolve(undefined);
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
devServerOptions(): WebpackDevServer.Configuration {
|
||||
|
|
|
@ -15,3 +15,27 @@ export const isPreloadOnly = (entry: WebpackPluginEntryPoint): entry is WebpackP
|
|||
export const isNoWindow = (entry: WebpackPluginEntryPoint): entry is WebpackPluginEntryPointNoWindow => {
|
||||
return !(entry as any).html && !!(entry as any).js;
|
||||
};
|
||||
|
||||
export const hasPreloadScript = (entry: WebpackPluginEntryPoint): entry is WebpackPluginEntryPointPreloadOnly => {
|
||||
return 'preload' in entry;
|
||||
};
|
||||
|
||||
export const isLocalOrNoWindowEntries = (
|
||||
entries: WebpackPluginEntryPoint[]
|
||||
): entries is (WebpackPluginEntryPointLocalWindow | WebpackPluginEntryPointNoWindow)[] => {
|
||||
for (const entry of entries) {
|
||||
if (!isLocalWindow(entry) && !isNoWindow(entry)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
export const isPreloadOnlyEntries = (entries: WebpackPluginEntryPoint[]): entries is WebpackPluginEntryPointPreloadOnly[] => {
|
||||
for (const entry of entries) {
|
||||
if (!hasPreloadScript(entry)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
|
|
@ -145,14 +145,13 @@ describe('AssetRelocatorPatch', () => {
|
|||
});
|
||||
|
||||
it('builds preload', async () => {
|
||||
const entryPoint = config.renderer.entryPoints[0] as WebpackPluginEntryPointLocalWindow;
|
||||
const preloadConfig = await generator.getPreloadConfigForEntryPoint(entryPoint);
|
||||
await asyncWebpack(preloadConfig);
|
||||
const preloadConfig = await generator.getRendererConfig(config.renderer.entryPoints);
|
||||
await asyncWebpack(preloadConfig[0]);
|
||||
|
||||
await expectOutputFileToHaveTheCorrectNativeModulePath({
|
||||
outDir: path.join(rendererOut, 'main_window'),
|
||||
outDir: rendererOut,
|
||||
jsPath: path.join(rendererOut, 'main_window/preload.js'),
|
||||
nativeModulesString: '__webpack_require__.ab = __dirname + "/native_modules/"',
|
||||
nativeModulesString: `__webpack_require__.ab = ${JSON.stringify(rendererOut)} + "/native_modules/"`,
|
||||
nativePathString: `require(__webpack_require__.ab + \\"${nativePathSuffix}\\")`,
|
||||
});
|
||||
});
|
||||
|
@ -199,13 +198,13 @@ describe('AssetRelocatorPatch', () => {
|
|||
|
||||
it('builds preload', async () => {
|
||||
const entryPoint = config.renderer.entryPoints[0] as WebpackPluginEntryPointLocalWindow;
|
||||
const preloadConfig = await generator.getPreloadConfigForEntryPoint(entryPoint);
|
||||
await asyncWebpack(preloadConfig);
|
||||
const preloadConfig = await generator.getRendererConfig([entryPoint]);
|
||||
await asyncWebpack(preloadConfig[0]);
|
||||
|
||||
await expectOutputFileToHaveTheCorrectNativeModulePath({
|
||||
outDir: path.join(rendererOut, 'main_window'),
|
||||
outDir: rendererOut,
|
||||
jsPath: path.join(rendererOut, 'main_window/preload.js'),
|
||||
nativeModulesString: '.ab=__dirname+"/native_modules/"',
|
||||
nativeModulesString: '.ab=require("path").resolve(__dirname,"..")+"/native_modules/"',
|
||||
nativePathString: `.ab+"${nativePathSuffix}"`,
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@ import path from 'path';
|
|||
import { expect } from 'chai';
|
||||
import { Compiler, Configuration, Entry, WebpackPluginInstance } from 'webpack';
|
||||
|
||||
import { WebpackConfiguration, WebpackPluginConfig, WebpackPluginEntryPoint, WebpackPluginEntryPointLocalWindow } from '../src/Config';
|
||||
import { WebpackConfiguration, WebpackPluginConfig, WebpackPluginEntryPoint } from '../src/Config';
|
||||
import AssetRelocatorPatch from '../src/util/AssetRelocatorPatch';
|
||||
import WebpackConfigGenerator, { ConfigurationFactory } from '../src/WebpackConfig';
|
||||
|
||||
|
@ -28,17 +28,18 @@ const sampleWebpackConfig = {
|
|||
|
||||
describe('WebpackConfigGenerator', () => {
|
||||
describe('rendererTarget', () => {
|
||||
it('is web if undefined', () => {
|
||||
it('is web if undefined', async () => {
|
||||
const config = {
|
||||
renderer: {
|
||||
entryPoints: [{ name: 'foo', js: 'foo/index.js' }],
|
||||
},
|
||||
} as WebpackPluginConfig;
|
||||
const generator = new WebpackConfigGenerator(config, '/', false, 3000);
|
||||
expect(generator.rendererTarget(config.renderer.entryPoints[0])).to.equal('web');
|
||||
const webpackConfig = await generator.getRendererConfig(config.renderer.entryPoints);
|
||||
expect(webpackConfig[0].target).to.equal('web');
|
||||
});
|
||||
|
||||
it('is web if false', () => {
|
||||
it('is web if false', async () => {
|
||||
const config = {
|
||||
renderer: {
|
||||
entryPoints: [{ name: 'foo', js: 'foo/index.js' }],
|
||||
|
@ -46,10 +47,11 @@ describe('WebpackConfigGenerator', () => {
|
|||
},
|
||||
} as WebpackPluginConfig;
|
||||
const generator = new WebpackConfigGenerator(config, '/', false, 3000);
|
||||
expect(generator.rendererTarget(config.renderer.entryPoints[0])).to.equal('web');
|
||||
const webpackConfig = await generator.getRendererConfig(config.renderer.entryPoints);
|
||||
expect(webpackConfig[0].target).to.equal('web');
|
||||
});
|
||||
|
||||
it('is electron-renderer if true', () => {
|
||||
it('is electron-renderer if true', async () => {
|
||||
const config = {
|
||||
renderer: {
|
||||
entryPoints: [{ name: 'foo', js: 'foo/index.js' }],
|
||||
|
@ -57,10 +59,11 @@ describe('WebpackConfigGenerator', () => {
|
|||
},
|
||||
} as WebpackPluginConfig;
|
||||
const generator = new WebpackConfigGenerator(config, '/', false, 3000);
|
||||
expect(generator.rendererTarget(config.renderer.entryPoints[0])).to.equal('electron-renderer');
|
||||
const webpackConfig = await generator.getRendererConfig(config.renderer.entryPoints);
|
||||
expect(webpackConfig[0].target).to.equal('electron-renderer');
|
||||
});
|
||||
|
||||
it('is web if entry nodeIntegration is false', () => {
|
||||
it('is web if entry nodeIntegration is false', async () => {
|
||||
const config = {
|
||||
renderer: {
|
||||
entryPoints: [{ name: 'foo', js: 'foo/index.js', nodeIntegration: false }],
|
||||
|
@ -68,7 +71,8 @@ describe('WebpackConfigGenerator', () => {
|
|||
},
|
||||
} as WebpackPluginConfig;
|
||||
const generator = new WebpackConfigGenerator(config, '/', false, 3000);
|
||||
expect(generator.rendererTarget(config.renderer.entryPoints[0])).to.equal('web');
|
||||
const webpackConfig = await generator.getRendererConfig(config.renderer.entryPoints);
|
||||
expect(webpackConfig[0].target).to.equal('web');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -308,113 +312,6 @@ describe('WebpackConfigGenerator', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('getPreloadConfigForEntryPoint', () => {
|
||||
it('generates a development config', async () => {
|
||||
const config = {
|
||||
renderer: {
|
||||
entryPoints: [
|
||||
{
|
||||
name: 'main',
|
||||
preload: {
|
||||
js: 'preloadScript.js',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
} as WebpackPluginConfig;
|
||||
const generator = new WebpackConfigGenerator(config, mockProjectDir, false, 3000);
|
||||
const entryPoint = config.renderer.entryPoints[0] as WebpackPluginEntryPointLocalWindow;
|
||||
const webpackConfig = await generator.getPreloadConfigForEntryPoint(entryPoint);
|
||||
expect(webpackConfig.target).to.equal('electron-preload');
|
||||
expect(webpackConfig.mode).to.equal('development');
|
||||
expect(webpackConfig.entry).to.deep.equal(['preloadScript.js']);
|
||||
expect(webpackConfig.output).to.deep.equal({
|
||||
path: path.join(mockProjectDir, '.webpack', 'renderer', 'main'),
|
||||
filename: 'preload.js',
|
||||
});
|
||||
expect(hasAssetRelocatorPatchPlugin(webpackConfig.plugins)).to.equal(false);
|
||||
});
|
||||
|
||||
it('generates a production config', async () => {
|
||||
const config = {
|
||||
renderer: {
|
||||
entryPoints: [
|
||||
{
|
||||
name: 'main',
|
||||
preload: {
|
||||
js: 'preload.js',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
} as WebpackPluginConfig;
|
||||
const generator = new WebpackConfigGenerator(config, mockProjectDir, true, 3000);
|
||||
const entryPoint = config.renderer.entryPoints[0] as WebpackPluginEntryPointLocalWindow;
|
||||
const webpackConfig = await generator.getPreloadConfigForEntryPoint(entryPoint);
|
||||
expect(webpackConfig.target).to.equal('electron-preload');
|
||||
expect(webpackConfig.mode).to.equal('production');
|
||||
expect(webpackConfig.entry).to.deep.equal(['preload.js']);
|
||||
expect(webpackConfig.output).to.deep.equal({
|
||||
path: path.join(mockProjectDir, '.webpack', 'renderer', 'main'),
|
||||
filename: 'preload.js',
|
||||
});
|
||||
expect(hasAssetRelocatorPatchPlugin(webpackConfig.plugins)).to.equal(false);
|
||||
});
|
||||
it('prevents the preload target from being overridden', async () => {
|
||||
const config = {
|
||||
renderer: {
|
||||
config: {
|
||||
target: 'web',
|
||||
},
|
||||
entryPoints: [
|
||||
{
|
||||
name: 'main',
|
||||
preload: {
|
||||
js: 'preload.js',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
} as WebpackPluginConfig;
|
||||
const generator = new WebpackConfigGenerator(config, mockProjectDir, true, 3000);
|
||||
const entryPoint = config.renderer.entryPoints[0] as WebpackPluginEntryPointLocalWindow;
|
||||
const webpackConfig = await generator.getPreloadConfigForEntryPoint(entryPoint);
|
||||
expect(webpackConfig.target).to.equal('electron-preload');
|
||||
});
|
||||
|
||||
it('allows you to specify a preload webpack config', async () => {
|
||||
const config = {
|
||||
renderer: {
|
||||
config: {
|
||||
name: 'renderer',
|
||||
target: 'web',
|
||||
entry: 'renderer',
|
||||
},
|
||||
entryPoints: [
|
||||
{
|
||||
name: 'main',
|
||||
preload: {
|
||||
js: 'preload.js',
|
||||
config: {
|
||||
name: 'preload',
|
||||
target: 'electron-preload',
|
||||
entry: 'preload',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
} as WebpackPluginConfig;
|
||||
const generator = new WebpackConfigGenerator(config, mockProjectDir, true, 3000);
|
||||
const entryPoint = config.renderer.entryPoints[0] as WebpackPluginEntryPointLocalWindow;
|
||||
const preloadWebpackConfig = await generator.getPreloadConfigForEntryPoint(entryPoint);
|
||||
const rendererWebpackConfig = await generator.getRendererConfig(config.renderer.entryPoints);
|
||||
// Our preload config plugins is an empty list while our renderer config plugins has a member
|
||||
expect(preloadWebpackConfig.name).to.equal('preload');
|
||||
expect(rendererWebpackConfig[0].name).to.equal('renderer');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getRendererConfig', () => {
|
||||
it('generates a development config', async () => {
|
||||
const config = {
|
||||
|
@ -483,12 +380,19 @@ describe('WebpackConfigGenerator', () => {
|
|||
} as WebpackPluginConfig;
|
||||
const generator = new WebpackConfigGenerator(config, mockProjectDir, false, 3000);
|
||||
const webpackConfig = await generator.getRendererConfig(config.renderer.entryPoints);
|
||||
expect(webpackConfig[0].target).to.equal('electron-preload');
|
||||
expect(webpackConfig[0].target).to.equal('web');
|
||||
expect(webpackConfig[0].mode).to.equal('development');
|
||||
expect(webpackConfig[0].entry).to.deep.equal({
|
||||
main: ['rendererScript.js'],
|
||||
});
|
||||
expect(webpackConfig[0].output).to.deep.equal({
|
||||
path: path.join(mockProjectDir, '.webpack', 'renderer'),
|
||||
filename: '[name]/preload.js',
|
||||
globalObject: 'self',
|
||||
publicPath: '/',
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(webpackConfig[0].plugins!.length).to.equal(1);
|
||||
expect(webpackConfig[0].plugins!.length).to.equal(2);
|
||||
expect(hasAssetRelocatorPatchPlugin(webpackConfig[0].plugins)).to.equal(true);
|
||||
});
|
||||
|
||||
|
@ -520,6 +424,34 @@ describe('WebpackConfigGenerator', () => {
|
|||
expect(hasAssetRelocatorPatchPlugin(webpackConfig[0].plugins)).to.equal(true);
|
||||
});
|
||||
|
||||
it('generates a production config with entryPoint preload', async () => {
|
||||
const config = {
|
||||
renderer: {
|
||||
entryPoints: [
|
||||
{
|
||||
name: 'main',
|
||||
preload: {
|
||||
js: 'preload.js',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
} as WebpackPluginConfig;
|
||||
const generator = new WebpackConfigGenerator(config, mockProjectDir, true, 3000);
|
||||
const webpackConfig = await generator.getRendererConfig(config.renderer.entryPoints);
|
||||
expect(webpackConfig[0].target).to.equal('web');
|
||||
expect(webpackConfig[0].mode).to.equal('production');
|
||||
expect(webpackConfig[0].entry).to.deep.equal({ main: ['preload.js'] });
|
||||
expect(webpackConfig[0].output).to.deep.equal({
|
||||
path: path.join(mockProjectDir, '.webpack', 'renderer'),
|
||||
filename: '[name]/preload.js',
|
||||
globalObject: 'self',
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(webpackConfig[0].plugins!.length).to.equal(2);
|
||||
expect(hasAssetRelocatorPatchPlugin(webpackConfig[0].plugins)).to.equal(true);
|
||||
});
|
||||
|
||||
it('generates a preload-only production config', async () => {
|
||||
const config = {
|
||||
renderer: {
|
||||
|
@ -535,18 +467,18 @@ describe('WebpackConfigGenerator', () => {
|
|||
} as WebpackPluginConfig;
|
||||
const generator = new WebpackConfigGenerator(config, mockProjectDir, true, 3000);
|
||||
const webpackConfig = await generator.getRendererConfig(config.renderer.entryPoints);
|
||||
expect(webpackConfig[0].target).to.deep.equal('electron-preload');
|
||||
expect(webpackConfig[0].target).to.deep.equal('web');
|
||||
expect(webpackConfig[0].mode).to.equal('production');
|
||||
expect(webpackConfig[0].entry).to.deep.equal({
|
||||
main: ['rendererScript.js'],
|
||||
});
|
||||
expect(webpackConfig[0].output).to.deep.equal({
|
||||
path: path.join(mockProjectDir, '.webpack', 'renderer'),
|
||||
filename: 'preload.js',
|
||||
filename: '[name]/preload.js',
|
||||
globalObject: 'self',
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(webpackConfig[0].plugins!.length).to.equal(1);
|
||||
expect(webpackConfig[0].plugins!.length).to.equal(2);
|
||||
expect(hasAssetRelocatorPatchPlugin(webpackConfig[0].plugins)).to.equal(true);
|
||||
});
|
||||
|
||||
|
@ -569,6 +501,105 @@ describe('WebpackConfigGenerator', () => {
|
|||
expect(webpackConfig[0].target).to.equal('web');
|
||||
});
|
||||
|
||||
it('prevents the preload target from being overridden', async () => {
|
||||
const config = {
|
||||
renderer: {
|
||||
config: {
|
||||
target: 'web',
|
||||
},
|
||||
entryPoints: [
|
||||
{
|
||||
name: 'main',
|
||||
preload: {
|
||||
js: 'preload.js',
|
||||
},
|
||||
nodeIntegration: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
} as WebpackPluginConfig;
|
||||
const generator = new WebpackConfigGenerator(config, mockProjectDir, true, 3000);
|
||||
const webpackConfig = await generator.getRendererConfig(config.renderer.entryPoints);
|
||||
expect(webpackConfig[0].target).to.equal('electron-preload');
|
||||
});
|
||||
|
||||
it('allows you to specify a preload webpack config', async () => {
|
||||
const config = {
|
||||
renderer: {
|
||||
config: {
|
||||
target: 'web',
|
||||
name: 'renderer',
|
||||
entry: 'renderer',
|
||||
},
|
||||
entryPoints: [
|
||||
{
|
||||
name: 'main',
|
||||
preload: {
|
||||
js: 'preload.js',
|
||||
config: {
|
||||
name: 'preload',
|
||||
target: 'electron-preload',
|
||||
entry: 'preload',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
} as WebpackPluginConfig;
|
||||
const generator = new WebpackConfigGenerator(config, mockProjectDir, true, 3000);
|
||||
const webpackConfig = await generator.getRendererConfig(config.renderer.entryPoints);
|
||||
expect(webpackConfig[0].target).to.equal('web');
|
||||
expect(webpackConfig[0].name).to.equal('preload');
|
||||
});
|
||||
|
||||
it('generates up to 4 rendererConfigs instead of 1 per entrypoint', async () => {
|
||||
const config = {
|
||||
renderer: {
|
||||
config: {
|
||||
target: 'web',
|
||||
},
|
||||
entryPoints: [
|
||||
{
|
||||
name: '1',
|
||||
preload: {
|
||||
js: 'preload.js',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '2',
|
||||
preload: {
|
||||
js: 'preload.js',
|
||||
},
|
||||
nodeIntegration: true,
|
||||
},
|
||||
{
|
||||
html: './src/mediaPlayer/index.html',
|
||||
js: './src/mediaPlayer/index.tsx',
|
||||
name: '3',
|
||||
},
|
||||
{
|
||||
html: './src/mediaPlayer/index.html',
|
||||
js: './src/mediaPlayer/index.tsx',
|
||||
name: '4',
|
||||
nodeIntegration: true,
|
||||
},
|
||||
{
|
||||
js: './src/background/background.ts',
|
||||
name: '5',
|
||||
},
|
||||
{
|
||||
js: './src/background/background.ts',
|
||||
name: '6',
|
||||
nodeIntegration: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
} as WebpackPluginConfig;
|
||||
const generator = new WebpackConfigGenerator(config, mockProjectDir, true, 3000);
|
||||
const webpackConfig = await generator.getRendererConfig(config.renderer.entryPoints);
|
||||
expect(webpackConfig.length).to.equal(4);
|
||||
});
|
||||
|
||||
it('generates a config from function', async () => {
|
||||
const generateWebpackConfig = (webpackConfig: WebpackConfiguration) => {
|
||||
const config = {
|
||||
|
|
Загрузка…
Ссылка в новой задаче