diff --git a/packages/plugin/webpack/src/Config.ts b/packages/plugin/webpack/src/Config.ts index 23c0f42fa3..d564953358 100644 --- a/packages/plugin/webpack/src/Config.ts +++ b/packages/plugin/webpack/src/Config.ts @@ -115,5 +115,16 @@ export interface WebpackPluginConfig { * Default: `default-src 'self' 'unsafe-inline' data:;` * `script-src 'self' 'unsafe-eval' 'unsafe-inline' data:` */ - devContentSecurityPolicy?: string + devContentSecurityPolicy?: string; + /** + * Overrides for [`webpack-dev-server`](https://webpack.js.org/configuration/dev-server/) options. + * + * The following options cannot be overridden here: + * * `port` (use the `port` config option) + * * `static` + * * `setupExitSignals` + * * `headers.Content-Security-Policy` (use the `devContentSecurityPolicy` config option) + */ + devServer?: Record; + // TODO: use webpack-dev-server.Configuration when @types/webpack-dev-server upgrades to v4 } diff --git a/packages/plugin/webpack/src/WebpackPlugin.ts b/packages/plugin/webpack/src/WebpackPlugin.ts index c278c53c9e..0023b97158 100644 --- a/packages/plugin/webpack/src/WebpackPlugin.ts +++ b/packages/plugin/webpack/src/WebpackPlugin.ts @@ -6,6 +6,7 @@ import Logger, { Tab } from '@electron-forge/web-multi-logger'; import debug from 'debug'; import fs from 'fs-extra'; import http from 'http'; +import { merge } from 'webpack-merge'; import path from 'path'; import webpack, { Configuration, Watching } from 'webpack'; import WebpackDevServer from 'webpack-dev-server'; @@ -300,23 +301,8 @@ Your packaged app may be larger than expected if you dont ignore everything othe if (!config.plugins) config.plugins = []; config.plugins.push(pluginLogs); - const cspDirectives = this.config.devContentSecurityPolicy - ?? "default-src 'self' 'unsafe-inline' data:; script-src 'self' 'unsafe-eval' 'unsafe-inline' data:"; - const compiler = webpack(config); - const webpackDevServer = new WebpackDevServer(compiler, { - hot: true, - port: this.port, - static: path.resolve(this.baseDir, 'renderer'), - devMiddleware: { - writeToDisk: true, - }, - setupExitSignals: true, - historyApiFallback: true, - headers: { - 'Content-Security-Policy': cspDirectives, - }, - }); + const webpackDevServer = new WebpackDevServer(compiler, this.devServerOptions()); const server = await webpackDevServer.listen(this.port); this.servers.push(server); }); @@ -348,6 +334,29 @@ Your packaged app may be larger than expected if you dont ignore everything othe }); } + devServerOptions(): Record { + const cspDirectives = this.config.devContentSecurityPolicy + ?? "default-src 'self' 'unsafe-inline' data:; script-src 'self' 'unsafe-eval' 'unsafe-inline' data:"; + + const defaults = { + hot: true, + devMiddleware: { + writeToDisk: true, + }, + historyApiFallback: true, + }; + const overrides = { + port: this.port, + setupExitSignals: true, + static: path.resolve(this.baseDir, 'renderer'), + headers: { + 'Content-Security-Policy': cspDirectives, + }, + }; + + return merge(defaults, this.config.devServer ?? {}, overrides); + } + private alreadyStarted = false; async startLogic(): Promise { diff --git a/packages/plugin/webpack/test/WebpackPlugin_spec.ts b/packages/plugin/webpack/test/WebpackPlugin_spec.ts index 2b58155dfa..3d7284c0de 100644 --- a/packages/plugin/webpack/test/WebpackPlugin_spec.ts +++ b/packages/plugin/webpack/test/WebpackPlugin_spec.ts @@ -107,4 +107,48 @@ describe('WebpackPlugin', () => { }); }); }); + + describe('devServerOptions', () => { + it('can override defaults', () => { + const defaultPlugin = new WebpackPlugin(baseConfig); + defaultPlugin.setDirectories(webpackTestDir); + expect(defaultPlugin.devServerOptions().hot).to.equal(true); + + const webpackConfig = { + ...baseConfig, + devServer: { + hot: false, + }, + }; + + const plugin = new WebpackPlugin(webpackConfig); + plugin.setDirectories(webpackTestDir); + const devServerConfig = plugin.devServerOptions(); + + expect(devServerConfig.hot).to.equal(false); + }); + + it('cannot override certain configuration', () => { + const webpackConfig = { + ...baseConfig, + port: 9999, + devServer: { + port: 8888, + headers: { + 'Content-Security-Policy': 'invalid', + 'X-Test-Header': 'test', + }, + }, + }; + + const plugin = new WebpackPlugin(webpackConfig); + plugin.setDirectories(webpackTestDir); + const devServerConfig = plugin.devServerOptions(); + + expect(devServerConfig.port).to.equal(9999); + const headers = devServerConfig.headers as Record; + expect(headers['Content-Security-Policy']).to.not.equal('invalid'); + expect(headers['X-Test-Header']).to.equal('test'); + }); + }); });