diff --git a/packages/core/src/provider/createCompiler.ts b/packages/core/src/provider/createCompiler.ts index 11b627456c..ee98ab58bf 100644 --- a/packages/core/src/provider/createCompiler.ts +++ b/packages/core/src/provider/createCompiler.ts @@ -11,12 +11,7 @@ import { } from '../helpers'; import { registerDevHook } from '../hooks'; import { logger } from '../logger'; -import type { - DevConfig, - InternalContext, - Rspack, - ServerConfig, -} from '../types'; +import type { InternalContext, Rspack } from '../types'; import { type InitConfigsOptions, initConfigs } from './initConfigs'; // keep the last 3 parts of the path to make logs clean @@ -201,35 +196,3 @@ export async function createCompiler(options: InitConfigsOptions): Promise<{ rspackConfigs, }; } - -export type MiddlewareCallbacks = { - onInvalid: () => void; - onDone: (stats: any) => void; -}; - -export type DevMiddlewareOptions = { - /** To ensure HMR works, the devMiddleware need inject the HMR client path into page when HMR enable. */ - clientPaths?: string[]; - clientConfig: DevConfig['client']; - publicPath?: string; - - /** When liveReload is disabled, the page does not reload. */ - liveReload?: boolean; - - etag?: 'weak' | 'strong'; - - /** The options need by compiler middleware (like webpackMiddleware) */ - headers?: Record; - writeToDisk?: - | boolean - | ((filename: string, compilationName?: string) => boolean); - stats?: boolean; - - /** should trigger when compiler hook called */ - callbacks: MiddlewareCallbacks; - - /** whether use Server Side Render */ - serverSideRender?: boolean; - - serverConfig: ServerConfig; -}; diff --git a/packages/core/src/server/compilerDevMiddleware.ts b/packages/core/src/server/compilationManager.ts similarity index 76% rename from packages/core/src/server/compilerDevMiddleware.ts rename to packages/core/src/server/compilationManager.ts index a4e1a334b8..9ea4974d68 100644 --- a/packages/core/src/server/compilerDevMiddleware.ts +++ b/packages/core/src/server/compilationManager.ts @@ -1,7 +1,8 @@ +import fs from 'node:fs'; import type { IncomingMessage, ServerResponse } from 'node:http'; import { createRequire } from 'node:module'; -import type { Socket } from 'node:net'; import { HTML_REGEX } from '../constants'; +import { isMultiCompiler } from '../helpers'; import { pathnameParse } from '../helpers/path'; import type { EnvironmentContext, @@ -11,10 +12,9 @@ import type { ServerConfig, } from '../types'; import { - type DevMiddleware as CustomDevMiddleware, - type DevMiddlewareAPI, - getDevMiddleware, -} from './devMiddleware'; + type CompilationMiddleware, + getCompilationMiddleware, +} from './compilationMiddleware'; import { stripBase } from './helper'; import { SocketServer } from './socketServer'; @@ -85,8 +85,10 @@ function getClientPaths(devConfig: DevConfig) { * 1. setup rsbuild-dev-middleware * 2. establish webSocket connect */ -export class CompilerDevMiddleware { - public middleware!: DevMiddlewareAPI; +export class CompilationManager { + public middleware!: CompilationMiddleware; + + public outputFileSystem: Rspack.OutputFileSystem; private devConfig: DevConfig; @@ -96,30 +98,27 @@ export class CompilerDevMiddleware { private publicPaths: string[]; - private socketServer: SocketServer; + public socketServer: SocketServer; constructor({ dev, server, compiler, publicPaths, environments }: Options) { this.devConfig = formatDevConfig(dev, environments); this.serverConfig = server; this.compiler = compiler; this.publicPaths = publicPaths; - - // init socket server + this.outputFileSystem = fs; this.socketServer = new SocketServer(dev); } public async init(): Promise { - // start compiling - const devMiddleware = await getDevMiddleware(this.compiler); - this.middleware = await this.setupDevMiddleware( - devMiddleware, - this.publicPaths, - ); + await this.setupCompilationMiddleware(); await this.socketServer.prepare(); - } - public upgrade(req: IncomingMessage, sock: Socket, head: any): void { - this.socketServer.upgrade(req, sock, head); + // Get the latest outputFileSystem from rsbuild-dev-middleware + const { compiler } = this; + this.outputFileSystem = + (isMultiCompiler(compiler) + ? compiler.compilers[0].outputFileSystem + : compiler.outputFileSystem) || fs; } public async close(): Promise { @@ -142,22 +141,18 @@ export class CompilerDevMiddleware { }); } - public sockWrite( - type: string, - data?: Record | string | boolean, - ): void { - this.socketServer.sockWrite({ - type, - data, - }); - } + public readFileSync = (fileName: string): string => { + if ('readFileSync' in this.outputFileSystem) { + // bundle require needs a synchronous method, although readFileSync is not within the + // outputFileSystem type definition, but nodejs fs API implemented. + // @ts-expect-error + return this.outputFileSystem.readFileSync(fileName, 'utf-8'); + } + return fs.readFileSync(fileName, 'utf-8'); + }; - private async setupDevMiddleware( - devMiddleware: CustomDevMiddleware, - publicPaths: string[], - ): Promise { - const { devConfig, serverConfig } = this; - const { headers, base } = serverConfig; + private async setupCompilationMiddleware(): Promise { + const { devConfig, serverConfig, publicPaths } = this; const callbacks = { onInvalid: (compilationId?: string, fileName?: string | null) => { @@ -169,7 +164,6 @@ export class CompilerDevMiddleware { }); return; } - this.socketServer.sockWrite({ type: 'invalid', compilationId, @@ -182,22 +176,14 @@ export class CompilerDevMiddleware { const clientPaths = getClientPaths(devConfig); - const middleware = await devMiddleware({ - headers, - publicPath: '/', - stats: false, + const middleware = await getCompilationMiddleware(this.compiler, { callbacks, - clientPaths: clientPaths, - clientConfig: devConfig.client, - liveReload: devConfig.liveReload, - writeToDisk: devConfig.writeToDisk, - serverSideRender: true, - // weak is enough in dev - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Conditional_requests#weak_validation - etag: 'weak', + clientPaths, + devConfig, serverConfig, }); + const { base } = serverConfig; const assetPrefixes = publicPaths .map(pathnameParse) .map((prefix) => @@ -230,6 +216,6 @@ export class CompilerDevMiddleware { // wrap rsbuild-dev-middleware to handle HTML file(without publicPath) // maybe we should serve HTML file by sirv - return wrapper; + this.middleware = wrapper; } } diff --git a/packages/core/src/server/devMiddleware.ts b/packages/core/src/server/compilationMiddleware.ts similarity index 51% rename from packages/core/src/server/devMiddleware.ts rename to packages/core/src/server/compilationMiddleware.ts index 4073c45573..c532f82ee2 100644 --- a/packages/core/src/server/devMiddleware.ts +++ b/packages/core/src/server/compilationMiddleware.ts @@ -1,16 +1,10 @@ import type { IncomingMessage, ServerResponse } from 'node:http'; import type { Compiler, MultiCompiler } from '@rspack/core'; import { applyToCompiler } from '../helpers'; -import type { DevMiddlewareOptions } from '../provider/createCompiler'; -import type { DevConfig, NextFunction } from '../types'; +import type { DevConfig, NextFunction, ServerConfig } from '../types'; import { getCompilationId } from './helper'; import { getResolvedClientConfig } from './hmrFallback'; -type ServerCallbacks = { - onInvalid: (compilationId?: string, fileName?: string | null) => void; - onDone: (stats: any) => void; -}; - export const isClientCompiler = (compiler: { options: { target?: Compiler['options']['target']; @@ -39,9 +33,14 @@ const isNodeCompiler = (compiler: { return false; }; +type ServerCallbacks = { + onInvalid: (compilationId?: string, fileName?: string | null) => void; + onDone: (stats: any) => void; +}; + export const setupServerHooks = ( compiler: Compiler, - hookCallbacks: ServerCallbacks, + { onDone, onInvalid }: ServerCallbacks, ): void => { // TODO: node SSR HMR is not supported yet if (isNodeCompiler(compiler)) { @@ -51,26 +50,24 @@ export const setupServerHooks = ( const { compile, invalid, done } = compiler.hooks; compile.tap('rsbuild-dev-server', () => { - hookCallbacks.onInvalid(getCompilationId(compiler)); + onInvalid(getCompilationId(compiler)); }); invalid.tap('rsbuild-dev-server', (fileName) => { - hookCallbacks.onInvalid(getCompilationId(compiler), fileName); + onInvalid(getCompilationId(compiler), fileName); }); - done.tap('rsbuild-dev-server', hookCallbacks.onDone); + done.tap('rsbuild-dev-server', onDone); }; function applyHMREntry({ compiler, clientPaths, - clientConfig = {}, - resolvedClientConfig = {}, - liveReload = true, + devConfig, + resolvedClientConfig, }: { compiler: Compiler; clientPaths: string[]; - clientConfig: DevConfig['client']; + devConfig: DevConfig; resolvedClientConfig: DevConfig['client']; - liveReload: DevConfig['liveReload']; }) { if (!isClientCompiler(compiler)) { return; @@ -78,9 +75,9 @@ function applyHMREntry({ new compiler.webpack.DefinePlugin({ RSBUILD_COMPILATION_NAME: JSON.stringify(getCompilationId(compiler)), - RSBUILD_CLIENT_CONFIG: JSON.stringify(clientConfig), + RSBUILD_CLIENT_CONFIG: JSON.stringify(devConfig.client), RSBUILD_RESOLVED_CLIENT_CONFIG: JSON.stringify(resolvedClientConfig), - RSBUILD_DEV_LIVE_RELOAD: liveReload, + RSBUILD_DEV_LIVE_RELOAD: devConfig.liveReload, }).apply(compiler); for (const clientPath of clientPaths) { @@ -90,62 +87,71 @@ function applyHMREntry({ } } -export type Middleware = ( +type Middleware = ( req: IncomingMessage, res: ServerResponse, next: NextFunction, ) => Promise; -export type DevMiddlewareAPI = Middleware & { +export type CompilationMiddlewareOptions = { + /** + * To ensure HMR works, the devMiddleware need inject the HMR client path into page when HMR enable. + */ + clientPaths?: string[]; + /** + * Should trigger when compiler hook called + */ + callbacks: ServerCallbacks; + devConfig: DevConfig; + serverConfig: ServerConfig; +}; + +export type CompilationMiddleware = Middleware & { close: (callback: (err: Error | null | undefined) => void) => any; }; /** - * The rsbuild/server do nothing about compiler, the devMiddleware need do such things to ensure dev works well: - * - Call compiler.watch (normally did by rsbuild-dev-middleware). - * - Inject the HMR client path into page (the HMR client rsbuild/server already provide). - * - Notify server when compiler hooks are triggered. + * The CompilationMiddleware handles compiler setup for development: + * - Call `compiler.watch` (handled by rsbuild-dev-middleware) + * - Inject the HMR client path into page + * - Notify server when compiler hooks are triggered */ -export type DevMiddleware = ( - options: DevMiddlewareOptions, -) => Promise; - -export const getDevMiddleware = async ( - multiCompiler: Compiler | MultiCompiler, -): Promise> => { +export const getCompilationMiddleware = async ( + compiler: Compiler | MultiCompiler, + options: CompilationMiddlewareOptions, +): Promise => { const { default: rsbuildDevMiddleware } = await import( '../../compiled/rsbuild-dev-middleware/index.js' ); - return async (options) => { - const { - clientPaths, - clientConfig, - callbacks, - liveReload, - serverConfig, - ...restOptions - } = options; - const resolvedClientConfig = await getResolvedClientConfig( - clientConfig, - serverConfig, - ); - - const setupCompiler = (compiler: Compiler) => { - if (clientPaths) { - applyHMREntry({ - compiler, - clientPaths, - clientConfig, - resolvedClientConfig, - liveReload, - }); - } - // register hooks for each compilation, update socket stats if recompiled - setupServerHooks(compiler, callbacks); - }; - - applyToCompiler(multiCompiler, setupCompiler); - - return rsbuildDevMiddleware(multiCompiler, restOptions); + + const { clientPaths, callbacks, devConfig, serverConfig } = options; + const resolvedClientConfig = await getResolvedClientConfig( + devConfig.client, + serverConfig, + ); + + const setupCompiler = (compiler: Compiler) => { + if (clientPaths) { + applyHMREntry({ + compiler, + clientPaths, + devConfig, + resolvedClientConfig, + }); + } + // register hooks for each compilation, update socket stats if recompiled + setupServerHooks(compiler, callbacks); }; + + applyToCompiler(compiler, setupCompiler); + + return rsbuildDevMiddleware(compiler, { + // weak is enough in dev + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Conditional_requests#weak_validation + etag: 'weak', + publicPath: '/', + stats: false, + serverSideRender: true, + writeToDisk: devConfig.writeToDisk, + }); }; diff --git a/packages/core/src/server/getDevMiddlewares.ts b/packages/core/src/server/devMiddlewares.ts similarity index 83% rename from packages/core/src/server/getDevMiddlewares.ts rename to packages/core/src/server/devMiddlewares.ts index 604b700d6b..3dae6dbcde 100644 --- a/packages/core/src/server/getDevMiddlewares.ts +++ b/packages/core/src/server/devMiddlewares.ts @@ -5,10 +5,10 @@ import type { DevConfig, EnvironmentAPI, RequestHandler, - Rspack, ServerConfig, SetupMiddlewaresServer, } from '../types'; +import type { CompilationManager } from './compilationManager'; import { gzipMiddleware } from './gzipMiddleware'; import type { UpgradeEvent } from './helper'; import { @@ -21,20 +21,12 @@ import { } from './middlewares'; import { createProxyMiddleware } from './proxy'; -export type CompileMiddlewareAPI = { - middleware: RequestHandler; - sockWrite: SetupMiddlewaresServer['sockWrite']; - onUpgrade: UpgradeEvent; - close: () => Promise; -}; - export type RsbuildDevMiddlewareOptions = { pwd: string; dev: DevConfig; server: ServerConfig; environments: EnvironmentAPI; - compileMiddlewareAPI?: CompileMiddlewareAPI; - outputFileSystem: Rspack.OutputFileSystem; + compilationManager?: CompilationManager; output: { distPath: string; }; @@ -47,12 +39,16 @@ export type RsbuildDevMiddlewareOptions = { const applySetupMiddlewares = ( dev: RsbuildDevMiddlewareOptions['dev'], environments: EnvironmentAPI, - compileMiddlewareAPI?: CompileMiddlewareAPI, + compilationManager?: CompilationManager, ) => { const setupMiddlewares = dev.setupMiddlewares || []; const serverOptions: SetupMiddlewaresServer = { - sockWrite: (type, data) => compileMiddlewareAPI?.sockWrite(type, data), + sockWrite: (type, data) => + compilationManager?.socketServer.sockWrite({ + type, + data, + }), environments, }; @@ -77,10 +73,9 @@ export type Middlewares = Array; const applyDefaultMiddlewares = async ({ middlewares, server, - compileMiddlewareAPI, + compilationManager, output, pwd, - outputFileSystem, environments, postCallbacks, }: RsbuildDevMiddlewareOptions & { @@ -137,13 +132,11 @@ const applyDefaultMiddlewares = async ({ middlewares.push(viewingServedFilesMiddleware({ environments })); - if (compileMiddlewareAPI) { - middlewares.push(compileMiddlewareAPI.middleware); + if (compilationManager) { + middlewares.push(compilationManager.middleware); // subscribe upgrade event to handle websocket - upgradeEvents.push( - compileMiddlewareAPI.onUpgrade.bind(compileMiddlewareAPI), - ); + upgradeEvents.push(compilationManager.socketServer.upgrade); middlewares.push((req, res, next) => { // [prevFullHash].hot-update.json will 404 (expected) when rsbuild restart and some file changed @@ -160,12 +153,11 @@ const applyDefaultMiddlewares = async ({ ? output.distPath : join(pwd, output.distPath); - if (compileMiddlewareAPI) { + if (compilationManager) { middlewares.push( getHtmlCompletionMiddleware({ distPath, - callback: compileMiddlewareAPI.middleware, - outputFileSystem, + compilationManager, }), ); } @@ -193,13 +185,12 @@ const applyDefaultMiddlewares = async ({ callback(); } - if (compileMiddlewareAPI) { + if (compilationManager) { middlewares.push( getHtmlFallbackMiddleware({ distPath, - callback: compileMiddlewareAPI.middleware, + compilationManager, htmlFallback: server.htmlFallback, - outputFileSystem, }), ); } @@ -214,9 +205,10 @@ const applyDefaultMiddlewares = async ({ middlewares.push(historyApiFallbackMiddleware); - // ensure fallback request can be handled by rsbuild-dev-middleware - compileMiddlewareAPI?.middleware && - middlewares.push(compileMiddlewareAPI.middleware); + // ensure fallback request can be handled by compilation middleware + if (compilationManager?.middleware) { + middlewares.push(compilationManager.middleware); + } } middlewares.push(faviconFallbackMiddleware); @@ -230,17 +222,17 @@ const applyDefaultMiddlewares = async ({ }; }; -export type GetMiddlewaresResult = { +export type GetDevMiddlewaresResult = { close: () => Promise; onUpgrade: UpgradeEvent; middlewares: Middlewares; }; -export const getMiddlewares = async ( +export const getDevMiddlewares = async ( options: RsbuildDevMiddlewareOptions, -): Promise => { +): Promise => { const middlewares: Middlewares = []; - const { environments, compileMiddlewareAPI } = options; + const { environments, compilationManager } = options; if (logger.level === 'verbose') { middlewares.push(await getRequestLoggerMiddleware()); @@ -250,7 +242,7 @@ export const getMiddlewares = async ( const { before, after } = applySetupMiddlewares( options.dev, environments, - compileMiddlewareAPI, + compilationManager, ); middlewares.push(...before); @@ -264,7 +256,7 @@ export const getMiddlewares = async ( return { close: async () => { - await compileMiddlewareAPI?.close(); + await compilationManager?.close(); }, onUpgrade, middlewares, diff --git a/packages/core/src/server/devServer.ts b/packages/core/src/server/devServer.ts index f2f67ac738..69bcb92f20 100644 --- a/packages/core/src/server/devServer.ts +++ b/packages/core/src/server/devServer.ts @@ -1,11 +1,10 @@ -import fs from 'node:fs'; import type { Server } from 'node:http'; import type { Http2SecureServer } from 'node:http2'; import type Connect from '../../compiled/connect/index.js'; import { ROOT_DIST_DIR } from '../constants'; import { getPublicPathFromCompiler, isMultiCompiler } from '../helpers'; import { logger } from '../logger'; -import { onBeforeRestartServer, restartDevServer } from '../restart.js'; +import { onBeforeRestartServer, restartDevServer } from '../restart'; import type { CreateCompiler, CreateDevServerOptions, @@ -16,17 +15,16 @@ import type { Rspack, } from '../types'; import { isCliShortcutsEnabled, setupCliShortcuts } from './cliShortcuts'; -import { CompilerDevMiddleware } from './compilerDevMiddleware'; +import { CompilationManager } from './compilationManager'; +import { + type GetDevMiddlewaresResult, + getDevMiddlewares, +} from './devMiddlewares'; import { createCacheableFunction, getTransformedHtml, loadBundle, } from './environment'; -import { - type CompileMiddlewareAPI, - type GetMiddlewaresResult, - getMiddlewares, -} from './getDevMiddlewares'; import { registerCleanup, removeCleanup, @@ -144,7 +142,6 @@ export async function createDevServer< https, }; - let outputFileSystem: Rspack.OutputFileSystem = fs; let lastStats: Rspack.Stats[]; // should register onDevCompileDone hook before startCompile @@ -163,7 +160,7 @@ export async function createDevServer< }) : Promise.resolve(); - const startCompile: () => Promise = async () => { + const startCompile: () => Promise = async () => { const compiler = customCompiler || (await createCompiler()); if (!compiler) { @@ -175,7 +172,7 @@ export async function createDevServer< : [getPublicPathFromCompiler(compiler)]; // create dev middleware instance - const compilerDevMiddleware = new CompilerDevMiddleware({ + const compilationManager = new CompilationManager({ dev: devConfig, server: { ...config.server, @@ -186,19 +183,9 @@ export async function createDevServer< environments: options.context.environments, }); - await compilerDevMiddleware.init(); + await compilationManager.init(); - outputFileSystem = - (isMultiCompiler(compiler) - ? compiler.compilers[0].outputFileSystem - : compiler.outputFileSystem) || fs; - - return { - middleware: compilerDevMiddleware.middleware, - sockWrite: (...args) => compilerDevMiddleware.sockWrite(...args), - onUpgrade: (...args) => compilerDevMiddleware.upgrade(...args), - close: () => compilerDevMiddleware?.close(), - }; + return compilationManager; }; const protocol = https ? 'https' : 'http'; @@ -228,7 +215,7 @@ export async function createDevServer< // biome-ignore lint/style/useConst: should be declared before use let fileWatcher: WatchFilesResult | undefined; - let devMiddlewares: GetMiddlewaresResult | undefined; + let devMiddlewares: GetDevMiddlewaresResult | undefined; const cleanupGracefulShutdown = middlewareMode ? null @@ -271,15 +258,6 @@ export async function createDevServer< } }; - const readFileSync = (fileName: string) => { - if ('readFileSync' in outputFileSystem) { - // bundle require needs a synchronous method, although readFileSync is not within the outputFileSystem type definition, but nodejs fs API implemented. - // @ts-expect-error - return outputFileSystem.readFileSync(fileName, 'utf-8'); - } - return fs.readFileSync(fileName, 'utf-8'); - }; - const cacheableLoadBundle = createCacheableFunction(loadBundle); const cacheableTransformedHtml = createCacheableFunction( (_stats, entryName, utils) => getTransformedHtml(entryName, utils), @@ -291,32 +269,42 @@ export async function createDevServer< name, { getStats: async () => { - if (!runCompile) { + if (!compilationManager) { throw new Error( - '[rsbuild:server] Can not get stats info when "runCompile" is false', + '[rsbuild:server] Can not call `getStats` when `runCompile` is false', ); } await waitFirstCompileDone; return lastStats[environment.index]; }, loadBundle: async (entryName: string) => { + if (!compilationManager) { + throw new Error( + '[rsbuild:server] Can not call `loadBundle` when `runCompile` is false', + ); + } await waitFirstCompileDone; return cacheableLoadBundle( lastStats[environment.index], entryName, { - readFileSync, + readFileSync: compilationManager.readFileSync, environment, }, ) as T; }, getTransformedHtml: async (entryName: string) => { + if (!compilationManager) { + throw new Error( + '[rsbuild:server] Can not call `getTransformedHtml` when `runCompile` is false', + ); + } await waitFirstCompileDone; return cacheableTransformedHtml( lastStats[environment.index], entryName, { - readFileSync, + readFileSync: compilationManager.readFileSync, environment, }, ); @@ -424,25 +412,24 @@ export async function createDevServer< beforeCreateCompiler(); } - const compileMiddlewareAPI = runCompile ? await startCompile() : undefined; + const compilationManager = runCompile ? await startCompile() : undefined; fileWatcher = await setupWatchFiles({ dev: devConfig, server: config.server, - compileMiddlewareAPI, + compilationManager, root, }); - devMiddlewares = await getMiddlewares({ + devMiddlewares = await getDevMiddlewares({ pwd: root, - compileMiddlewareAPI, + compilationManager, dev: devConfig, server: config.server, environments: environmentAPI, output: { distPath: options.context.distPath || ROOT_DIST_DIR, }, - outputFileSystem, postCallbacks, }); diff --git a/packages/core/src/server/middlewares.ts b/packages/core/src/server/middlewares.ts index 9268c0c9a2..790cf30c38 100644 --- a/packages/core/src/server/middlewares.ts +++ b/packages/core/src/server/middlewares.ts @@ -9,6 +9,7 @@ import type { RequestHandler as Middleware, Rspack, } from '../types'; +import type { CompilationManager } from './compilationManager'; import { joinUrlSegments, stripBase } from './helper'; export const faviconFallbackMiddleware: Middleware = (req, res, next) => { @@ -128,9 +129,8 @@ const getUrlPathname = (url: string): string => { */ export const getHtmlCompletionMiddleware: (params: { distPath: string; - callback: Middleware; - outputFileSystem: Rspack.OutputFileSystem; -}) => Middleware = ({ distPath, callback, outputFileSystem }) => { + compilationManager: CompilationManager; +}) => Middleware = ({ distPath, compilationManager }) => { return async (req, res, next) => { if (!maybeHTMLRequest(req)) { return next(); @@ -141,7 +141,7 @@ export const getHtmlCompletionMiddleware: (params: { const rewrite = (newUrl: string) => { req.url = newUrl; - return callback(req, res, (...args) => { + return compilationManager.middleware(req, res, (...args) => { next(...args); }); }; @@ -151,7 +151,7 @@ export const getHtmlCompletionMiddleware: (params: { const newUrl = `${pathname}index.html`; const filePath = path.join(distPath, newUrl); - if (await isFileExists(filePath, outputFileSystem)) { + if (await isFileExists(filePath, compilationManager.outputFileSystem)) { return rewrite(newUrl); } } @@ -160,7 +160,7 @@ export const getHtmlCompletionMiddleware: (params: { const newUrl = `${pathname}.html`; const filePath = path.join(distPath, newUrl); - if (await isFileExists(filePath, outputFileSystem)) { + if (await isFileExists(filePath, compilationManager.outputFileSystem)) { return rewrite(newUrl); } } @@ -225,10 +225,9 @@ export const getBaseMiddleware: (params: { base: string }) => Middleware = ({ */ export const getHtmlFallbackMiddleware: (params: { distPath: string; - callback: Middleware; + compilationManager: CompilationManager; htmlFallback?: HtmlFallback; - outputFileSystem: Rspack.OutputFileSystem; -}) => Middleware = ({ htmlFallback, distPath, callback, outputFileSystem }) => { +}) => Middleware = ({ htmlFallback, distPath, compilationManager }) => { return async (req, res, next) => { if ( !maybeHTMLRequest(req) || @@ -239,7 +238,7 @@ export const getHtmlFallbackMiddleware: (params: { } const filePath = path.join(distPath, 'index.html'); - if (await isFileExists(filePath, outputFileSystem)) { + if (await isFileExists(filePath, compilationManager.outputFileSystem)) { const newUrl = '/index.html'; if (logger.level === 'verbose') { @@ -251,7 +250,9 @@ export const getHtmlFallbackMiddleware: (params: { } req.url = newUrl; - return callback(req, res, (...args) => next(...args)); + return compilationManager.middleware(req, res, (...args) => + next(...args), + ); } next(); diff --git a/packages/core/src/server/socketServer.ts b/packages/core/src/server/socketServer.ts index b0c265a6c8..8e07b6faf4 100644 --- a/packages/core/src/server/socketServer.ts +++ b/packages/core/src/server/socketServer.ts @@ -47,7 +47,7 @@ export class SocketServer { this.initialChunks = {}; } - public upgrade(req: IncomingMessage, sock: Socket, head: any): void { + public upgrade = (req: IncomingMessage, sock: Socket, head: any): void => { // subscribe upgrade event to handle socket if (!this.wsServer.shouldHandle(req)) { @@ -57,7 +57,7 @@ export class SocketServer { this.wsServer.handleUpgrade(req, sock, head, (connection) => { this.wsServer.emit('connection', connection, req); }); - } + }; // detect and close broken connections // https://github.com/websockets/ws/blob/8.18.0/README.md#how-to-detect-and-close-broken-connections diff --git a/packages/core/src/server/watchFiles.ts b/packages/core/src/server/watchFiles.ts index cf1a75873e..694b0a80e7 100644 --- a/packages/core/src/server/watchFiles.ts +++ b/packages/core/src/server/watchFiles.ts @@ -7,13 +7,13 @@ import type { ServerConfig, WatchFiles, } from '../types'; -import type { CompileMiddlewareAPI } from './getDevMiddlewares'; +import type { CompilationManager } from './compilationManager'; type WatchFilesOptions = { dev: DevConfig; server: ServerConfig; - compileMiddlewareAPI?: CompileMiddlewareAPI; root: string; + compilationManager?: CompilationManager; }; export type WatchFilesResult = { @@ -23,21 +23,21 @@ export type WatchFilesResult = { export async function setupWatchFiles( options: WatchFilesOptions, ): Promise { - const { dev, server, root, compileMiddlewareAPI } = options; + const { dev, server, root, compilationManager } = options; const { hmr, liveReload } = dev; - if ((!hmr && !liveReload) || !compileMiddlewareAPI) { + if ((!hmr && !liveReload) || !compilationManager) { return; } const closeDevFilesWatcher = await watchDevFiles( dev, - compileMiddlewareAPI, + compilationManager, root, ); const serverFilesWatcher = await watchServerFiles( server, - compileMiddlewareAPI, + compilationManager, root, ); @@ -53,7 +53,7 @@ export async function setupWatchFiles( async function watchDevFiles( devConfig: DevConfig, - compileMiddlewareAPI: CompileMiddlewareAPI, + compilationManager: CompilationManager, root: string, ) { const { watchFiles } = devConfig; @@ -67,7 +67,7 @@ async function watchDevFiles( const watchOptions = prepareWatchOptions(paths, options, type); const watcher = await startWatchFiles( watchOptions, - compileMiddlewareAPI, + compilationManager, root, ); if (watcher) { @@ -84,7 +84,7 @@ async function watchDevFiles( function watchServerFiles( serverConfig: ServerConfig, - compileMiddlewareAPI: CompileMiddlewareAPI, + compilationManager: CompilationManager, root: string, ) { const publicDirs = normalizePublicDirs(serverConfig.publicDir); @@ -101,7 +101,7 @@ function watchServerFiles( } const watchOptions = prepareWatchOptions(watchPaths); - return startWatchFiles(watchOptions, compileMiddlewareAPI, root); + return startWatchFiles(watchOptions, compilationManager, root); } function prepareWatchOptions( @@ -162,7 +162,7 @@ async function startWatchFiles( options, type = 'reload-page', }: ReturnType, - compileMiddlewareAPI: CompileMiddlewareAPI, + compilationManager: CompilationManager, root: string, ) { if (type !== 'reload-page') { @@ -172,7 +172,9 @@ async function startWatchFiles( const watcher = await createChokidar(paths, root, options); watcher.on('change', () => { - compileMiddlewareAPI.sockWrite('static-changed'); + compilationManager.socketServer.sockWrite({ + type: 'static-changed', + }); }); return watcher; diff --git a/packages/core/tests/server.test.ts b/packages/core/tests/server.test.ts index 9e98266e31..fbbeafcf88 100644 --- a/packages/core/tests/server.test.ts +++ b/packages/core/tests/server.test.ts @@ -2,7 +2,7 @@ import { rspack } from '@rspack/core'; import { isClientCompiler, setupServerHooks, -} from '../src/server/devMiddleware'; +} from '../src/server/compilationMiddleware'; import { formatRoutes, printServerURLs } from '../src/server/helper'; test('formatRoutes', () => {