77 * https://github.com/webpack/webpack-dev-middleware/blob/master/LICENSE
88 */
99import type { Stats as FSStats , ReadStream } from 'node:fs' ;
10- import type { ServerResponse as NodeServerResponse } from 'node:http' ;
1110import { createRequire } from 'node:module' ;
1211import type { Compiler , MultiCompiler , Watching } from '@rspack/core' ;
1312import { applyToCompiler , isMultiCompiler } from '../../helpers' ;
1413import { logger } from '../../logger' ;
1514import type {
16- EnvironmentContext ,
15+ InternalContext ,
1716 NormalizedConfig ,
1817 NormalizedDevConfig ,
1918 NormalizedEnvironmentConfig ,
2019 RequestHandler ,
2120} from '../../types' ;
2221import { resolveHostname } from './../hmrFallback' ;
2322import type { SocketServer } from '../socketServer' ;
24- import { wrapper as createMiddleware } from './middleware' ;
25- import { setupHooks } from './setupHooks' ;
23+ import { createMiddleware } from './middleware' ;
2624import { setupOutputFileSystem } from './setupOutputFileSystem' ;
2725import { resolveWriteToDiskConfig , setupWriteToDisk } from './setupWriteToDisk' ;
2826
2927const noop = ( ) => { } ;
3028
31- export type ServerResponse = NodeServerResponse & {
32- locals ?: { webpack ?: { devMiddleware ?: Context } } ;
33- } ;
34-
3529export 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-
5847export 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({
198174export 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
0 commit comments