feat: add lazyCompilationBackend configuration

support customizing lazyCompilationBackend's port and server options

Fixes #14053, Fixes #14205
This commit is contained in:
Chaz Gatian 2021-09-16 10:47:04 -04:00
parent 562f17a8c0
commit 537da95879
7 changed files with 87 additions and 17 deletions

View File

@ -1133,6 +1133,10 @@ export interface Experiments {
compiler: import("../lib/Compiler"),
client: string
) => Promise<any>);
/**
* Additional configuration to pass to the backend server.
*/
backendConfiguration?: import("../lib/hmr/lazyCompilationBackend").BackendConfiguration;
/**
* A custom client.
*/

View File

@ -272,7 +272,9 @@ class WebpackOptionsApply extends OptionsApply {
),
entries: !lazyOptions || lazyOptions.entries !== false,
imports: !lazyOptions || lazyOptions.imports !== false,
test: (lazyOptions && lazyOptions.test) || undefined
test: (lazyOptions && lazyOptions.test) || undefined,
backendConfiguration:
(lazyOptions && lazyOptions.backendConfiguration) || undefined
}).apply(compiler);
}

View File

@ -303,18 +303,27 @@ class LazyCompilationDependencyFactory extends ModuleFactory {
class LazyCompilationPlugin {
/**
* @param {Object} options options
* @param {(function(Compiler, string, function(Error?, any?): void): void) | function(Compiler, string): Promise<any>} options.backend the backend
* @param {(function(Compiler, string, function(Error?, any?): void, Object): void) | function(Compiler, string): Promise<any>} options.backend the backend
* @param {Object} options.backendConfiguration additional configuration passed to backend
* @param {string} options.client the client reference
* @param {boolean} options.entries true, when entries are lazy compiled
* @param {boolean} options.imports true, when import() modules are lazy compiled
* @param {RegExp | string | (function(Module): boolean)} options.test additional filter for lazy compiled entrypoint modules
*/
constructor({ backend, client, entries, imports, test }) {
constructor({
backend,
client,
entries,
imports,
test,
backendConfiguration
}) {
this.backend = backend;
this.client = client;
this.entries = entries;
this.imports = imports;
this.test = test;
this.backendConfiguration = backendConfiguration;
}
/**
* Apply the plugin
@ -327,11 +336,16 @@ class LazyCompilationPlugin {
"LazyCompilationPlugin",
(params, callback) => {
if (backend !== undefined) return callback();
const promise = this.backend(compiler, this.client, (err, result) => {
if (err) return callback(err);
backend = result;
callback();
});
const promise = this.backend(
compiler,
this.client,
(err, result) => {
if (err) return callback(err);
backend = result;
callback();
},
this.backendConfiguration
);
if (promise && promise.then) {
promise.then(b => {
backend = b;

View File

@ -5,21 +5,35 @@
"use strict";
const http = require("http");
/** @typedef {import("http").ServerOptions} HttpServerOptions */
/** @typedef {import("https").ServerOptions} HttpsServerOptions */
/** @typedef {import("../Compiler")} Compiler */
/**
* @typedef {Object} BackendConfiguration
* @property {HttpServerOptions} httpServerOptions Options to be passed to the Node.js HTTP module.
* @property {HttpsServerOptions} httpsServerOptions Options to be passed to the Node.js HTTPS module.
* @property {number?} port Custom port for lazy compilation backend. If not defined, a random port will be used.
*/
/**
* @param {Compiler} compiler compiler
* @param {string} client client reference
* @param {function(Error?, any?): void} callback callback
* @param {?BackendConfiguration} backendConfiguration additional options for the backend
* @returns {void}
*/
module.exports = (compiler, client, callback) => {
module.exports = (compiler, client, callback, backendConfiguration) => {
const logger = compiler.getInfrastructureLogger("LazyCompilationBackend");
const activeModules = new Map();
const prefix = "/lazy-compilation-using-";
const isHTTPS =
!!backendConfiguration && !!backendConfiguration.httpsServerOptions;
const protocol = isHTTPS ? "https" : "http";
const httpModule = isHTTPS ? require("https") : require("http");
const requestListener = (req, res) => {
const keys = req.url.slice(prefix.length).split("@");
req.socket.on("close", () => {
@ -52,7 +66,14 @@ module.exports = (compiler, client, callback) => {
}
if (moduleActivated && compiler.watching) compiler.watching.invalidate();
};
const server = http.createServer(requestListener);
const server = httpModule.createServer(
backendConfiguration &&
(backendConfiguration.httpServerOptions ||
backendConfiguration.httpsServerOptions),
requestListener
);
let isClosing = false;
/** @type {Set<import("net").Socket>} */
const sockets = new Set();
@ -63,16 +84,16 @@ module.exports = (compiler, client, callback) => {
});
if (isClosing) socket.destroy();
});
server.listen(err => {
server.listen(backendConfiguration && backendConfiguration.port, err => {
if (err) return callback(err);
const addr = server.address();
if (typeof addr === "string") throw new Error("addr must not be a string");
const urlBase =
addr.address === "::" || addr.address === "0.0.0.0"
? `http://localhost:${addr.port}`
? `${protocol}://localhost:${addr.port}`
: addr.family === "IPv6"
? `http://[${addr.address}]:${addr.port}`
: `http://${addr.address}:${addr.port}`;
? `${protocol}://[${addr.address}]:${addr.port}`
: `${protocol}://${addr.address}:${addr.port}`;
logger.log(
`Server-Sent-Events server for lazy compilation open at ${urlBase}.`
);

File diff suppressed because one or more lines are too long

View File

@ -722,6 +722,10 @@
"instanceof": "Function",
"tsType": "(((compiler: import('../lib/Compiler'), client: string, callback: (err?: Error, api?: any) => void) => void) | ((compiler: import('../lib/Compiler'), client: string) => Promise<any>))"
},
"backendConfiguration": {
"description": "Additional configuration to pass to the backend server.",
"tsType": "import('../lib/hmr/lazyCompilationBackend').BackendConfiguration"
},
"client": {
"description": "A custom client.",
"type": "string"

25
types.d.ts vendored
View File

@ -80,6 +80,7 @@ import {
WithStatement,
YieldExpression
} from "estree";
import { ServerOptions as ServerOptionsImport } from "http";
import { validate as validateFunction } from "schema-utils";
import { default as ValidationError } from "schema-utils/declarations/ValidationError";
import { ValidationErrorConfiguration } from "schema-utils/declarations/validate";
@ -95,6 +96,7 @@ import {
SyncHook,
SyncWaterfallHook
} from "tapable";
import { SecureContextOptions, TlsOptions } from "tls";
declare class AbstractLibraryPlugin<T> {
constructor(__0: {
@ -384,6 +386,22 @@ declare class AutomaticPrefetchPlugin {
apply(compiler: Compiler): void;
}
type AuxiliaryComment = string | LibraryCustomUmdCommentObject;
declare interface BackendConfiguration {
/**
* Options to be passed to the Node.js HTTP module.
*/
httpServerOptions: ServerOptionsImport;
/**
* Options to be passed to the Node.js HTTPS module.
*/
httpsServerOptions: ServerOptionsHttps;
/**
* Custom port for lazy compilation backend. If not defined, a random port will be used.
*/
port: null | number;
}
declare class BannerPlugin {
constructor(options: BannerPluginArgument);
options: BannerPluginOptions;
@ -3308,6 +3326,10 @@ declare interface Experiments {
callback: (err?: Error, api?: any) => void
) => void)
| ((compiler: Compiler, client: string) => Promise<any>);
/**
* Additional configuration to pass to the backend server.
*/
backendConfiguration?: BackendConfiguration;
/**
* A custom client.
*/
@ -10279,6 +10301,9 @@ declare abstract class Serializer {
serialize(obj?: any, context?: any): any;
deserialize(value?: any, context?: any): any;
}
type ServerOptionsHttps = SecureContextOptions &
TlsOptions &
ServerOptionsImport;
declare class SharePlugin {
constructor(options: SharePluginOptions);