Skip to content

Commit ddf5da5

Browse files
committed
refactor(assets-middleware): simplify context management
1 parent 2b2263a commit ddf5da5

File tree

4 files changed

+51
-99
lines changed

4 files changed

+51
-99
lines changed

packages/core/src/server/assets-middleware/index.ts

Lines changed: 41 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,25 @@
77
* https://github.com/webpack/webpack-dev-middleware/blob/master/LICENSE
88
*/
99
import type { Stats as FSStats, ReadStream } from 'node:fs';
10-
import type { ServerResponse as NodeServerResponse } from 'node:http';
1110
import { createRequire } from 'node:module';
1211
import type { Compiler, MultiCompiler, Watching } from '@rspack/core';
1312
import { applyToCompiler, isMultiCompiler } from '../../helpers';
1413
import { logger } from '../../logger';
1514
import type {
16-
EnvironmentContext,
15+
InternalContext,
1716
NormalizedConfig,
1817
NormalizedDevConfig,
1918
NormalizedEnvironmentConfig,
2019
RequestHandler,
2120
} from '../../types';
2221
import { resolveHostname } from './../hmrFallback';
2322
import type { SocketServer } from '../socketServer';
24-
import { wrapper as createMiddleware } from './middleware';
25-
import { setupHooks } from './setupHooks';
23+
import { createMiddleware } from './middleware';
2624
import { setupOutputFileSystem } from './setupOutputFileSystem';
2725
import { resolveWriteToDiskConfig, setupWriteToDisk } from './setupWriteToDisk';
2826

2927
const noop = () => {};
3028

31-
export type ServerResponse = NodeServerResponse & {
32-
locals?: { webpack?: { devMiddleware?: Context } };
33-
};
34-
3529
export type MultiWatching = ReturnType<MultiCompiler['watch']>;
3630

3731
// TODO: refine types to match underlying fs-like implementations
@@ -50,11 +44,6 @@ export type Options = {
5044
| ((targetPath: string, compilationName?: string) => boolean);
5145
};
5246

53-
export type Context = {
54-
ready: boolean;
55-
callbacks: (() => void)[];
56-
};
57-
5847
export type AssetsMiddlewareClose = (
5948
callback: (err?: Error | null) => void,
6049
) => void;
@@ -90,31 +79,19 @@ function getClientPaths(devConfig: NormalizedDevConfig) {
9079
return clientPaths;
9180
}
9281

93-
export const isClientCompiler = (compiler: {
94-
options: {
95-
target?: Compiler['options']['target'];
96-
};
97-
}): boolean => {
82+
export const isClientCompiler = (compiler: Compiler): boolean => {
9883
const { target } = compiler.options;
99-
10084
if (target) {
10185
return Array.isArray(target) ? target.includes('web') : target === 'web';
10286
}
103-
10487
return false;
10588
};
10689

107-
const isNodeCompiler = (compiler: {
108-
options: {
109-
target?: Compiler['options']['target'];
110-
};
111-
}) => {
90+
const isNodeCompiler = (compiler: Compiler) => {
11291
const { target } = compiler.options;
113-
11492
if (target) {
11593
return Array.isArray(target) ? target.includes('node') : target === 'node';
11694
}
117-
11895
return false;
11996
};
12097

@@ -127,21 +104,20 @@ export const setupServerHooks = ({
127104
token: string;
128105
socketServer: SocketServer;
129106
}): void => {
130-
// TODO: node SSR HMR is not supported yet
107+
// Node HMR is not supported yet
131108
if (isNodeCompiler(compiler)) {
132109
return;
133110
}
134111

135-
const { invalid, done } = compiler.hooks;
136-
137-
invalid.tap('rsbuild-dev-server', (fileName) => {
112+
compiler.hooks.invalid.tap('rsbuild-dev-server', (fileName) => {
138113
// reload page when HTML template changed
139114
if (typeof fileName === 'string' && fileName.endsWith('.html')) {
140115
socketServer.sockWrite({ type: 'static-changed' }, token);
141116
return;
142117
}
143118
});
144-
done.tap('rsbuild-dev-server', (stats) => {
119+
120+
compiler.hooks.done.tap('rsbuild-dev-server', (stats) => {
145121
socketServer.updateStats(stats, token);
146122
});
147123
};
@@ -198,17 +174,18 @@ function applyHMREntry({
198174
export const assetsMiddleware = async ({
199175
config,
200176
compiler,
177+
context,
201178
socketServer,
202-
environments,
203179
resolvedPort,
204180
}: {
205181
config: NormalizedConfig;
206182
compiler: Compiler | MultiCompiler;
183+
context: InternalContext;
207184
socketServer: SocketServer;
208-
environments: Record<string, EnvironmentContext>;
209185
resolvedPort: number;
210186
}): Promise<AssetsMiddleware> => {
211187
const resolvedHost = await resolveHostname(config.server.host);
188+
const { environments } = context;
212189

213190
const setupCompiler = (compiler: Compiler, index: number) => {
214191
const environment = Object.values(environments).find(
@@ -242,12 +219,20 @@ export const assetsMiddleware = async ({
242219
applyToCompiler(compiler, setupCompiler);
243220

244221
const compilers = isMultiCompiler(compiler) ? compiler.compilers : [compiler];
245-
const context: Context = {
246-
ready: false,
247-
callbacks: [],
248-
};
249-
250-
setupHooks(context, compiler);
222+
const callbacks: (() => void)[] = [];
223+
224+
compiler.hooks.done.tap('rsbuild-dev-middleware', () => {
225+
process.nextTick(() => {
226+
if (!(context.buildState.status === 'done')) {
227+
return;
228+
}
229+
230+
callbacks.forEach((callback) => {
231+
callback();
232+
});
233+
callbacks.length = 0;
234+
});
235+
});
251236

252237
const writeToDisk = resolveWriteToDiskConfig(config.dev, environments);
253238
if (writeToDisk) {
@@ -256,10 +241,18 @@ export const assetsMiddleware = async ({
256241

257242
const outputFileSystem = await setupOutputFileSystem(writeToDisk, compilers);
258243

244+
const ready = (callback: () => void) => {
245+
if (context.buildState.status === 'done') {
246+
callback();
247+
} else {
248+
callbacks.push(callback);
249+
}
250+
};
251+
259252
const instance = createMiddleware(
260253
context,
254+
ready,
261255
outputFileSystem,
262-
environments,
263256
) as AssetsMiddleware;
264257

265258
let watching: Watching | MultiWatching | undefined;
@@ -269,20 +262,19 @@ export const assetsMiddleware = async ({
269262
if (compiler.watching) {
270263
watching = compiler.watching;
271264
} else {
272-
const errorHandler = (error: Error | null | undefined) => {
265+
const watchOptions =
266+
compilers.length > 1
267+
? compilers.map(({ options }) => options.watchOptions || {})
268+
: compilers[0].options.watchOptions || {};
269+
270+
watching = compiler.watch(watchOptions, (error) => {
273271
if (error) {
274272
if (error.message?.includes('× Error:')) {
275273
error.message = error.message.replace('× Error:', '').trim();
276274
}
277275
logger.error(error);
278276
}
279-
};
280-
281-
const watchOptions =
282-
compilers.length > 1
283-
? compilers.map(({ options }) => options.watchOptions || {})
284-
: compilers[0].options.watchOptions || {};
285-
watching = compiler.watch(watchOptions, errorHandler);
277+
});
286278
}
287279
};
288280

packages/core/src/server/assets-middleware/middleware.ts

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,13 @@ import onFinished from 'on-finished';
33
import type { Range, Result as RangeResult, Ranges } from 'range-parser';
44
import rangeParser from 'range-parser';
55
import { logger } from '../../logger';
6-
import type { EnvironmentContext, RequestHandler } from '../../types';
6+
import type { InternalContext, RequestHandler } from '../../types';
77
import { escapeHtml } from './escapeHtml';
88
import { getFileFromUrl } from './getFileFromUrl';
9-
import type { Context, OutputFileSystem, ServerResponse } from './index';
9+
import type { OutputFileSystem } from './index';
1010
import { memorize } from './memorize';
1111
import { parseTokenList } from './parseTokenList';
1212

13-
export function ready(context: Context, callback: () => void): void {
14-
if (context.ready) {
15-
callback();
16-
} else {
17-
context.callbacks.push(callback);
18-
}
19-
}
20-
2113
function getEtag(stat: FSStats): string {
2214
const mtime = stat.mtime.getTime().toString(16);
2315
const size = stat.size.toString(16);
@@ -120,18 +112,17 @@ type SendErrorOptions = {
120112

121113
const acceptedMethods = ['GET', 'HEAD'];
122114

123-
export function wrapper(
124-
context: Context,
115+
export function createMiddleware(
116+
context: InternalContext,
117+
ready: (callback: () => void) => void,
125118
outputFileSystem: OutputFileSystem,
126-
environments: Record<string, EnvironmentContext>,
127119
): RequestHandler {
128120
return async function middleware(req, res, next) {
121+
const { environments } = context;
122+
129123
async function goNext() {
130124
return new Promise<void>((resolve) => {
131-
ready(context, () => {
132-
const extendedRes = res as ServerResponse;
133-
extendedRes.locals = extendedRes.locals || {};
134-
extendedRes.locals.webpack = { devMiddleware: context };
125+
ready(() => {
135126
next();
136127
resolve();
137128
});
@@ -514,6 +505,6 @@ export function wrapper(
514505
onFinished(res, cleanup);
515506
}
516507

517-
ready(context, processRequest);
508+
ready(processRequest);
518509
};
519510
}

packages/core/src/server/assets-middleware/setupHooks.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.

packages/core/src/server/buildManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,9 @@ export class BuildManager {
113113

114114
const middleware = await assetsMiddleware({
115115
config,
116+
context,
116117
compiler: this.compiler,
117118
socketServer: this.socketServer,
118-
environments: context.environments,
119119
resolvedPort: this.resolvedPort,
120120
});
121121

0 commit comments

Comments
 (0)