@@ -33,6 +33,27 @@ const REPLACEMENTS = {
33
33
} ,
34
34
} ;
35
35
36
+ /**
37
+ * Gets the socket integration to use for Webpack messages.
38
+ * @param {'wds' | 'whm' | 'wps' | string } integrationType A valid socket integration type or a path to a module.
39
+ * @returns {string | undefined } Path to the resolved socket integration module.
40
+ */
41
+ function getSocketIntegrationEntry ( integrationType ) {
42
+ let resolvedEntry ;
43
+ switch ( integrationType ) {
44
+ case 'whm' : {
45
+ resolvedEntry = 'webpack-hot-middleware/client' ;
46
+ break ;
47
+ }
48
+ case 'wps' : {
49
+ resolvedEntry = 'webpack-plugin-serve/client' ;
50
+ break ;
51
+ }
52
+ }
53
+
54
+ return resolvedEntry ;
55
+ }
56
+
36
57
class ReactRefreshPlugin {
37
58
/**
38
59
* @param {import('./types').ReactRefreshPluginOptions } [options] Options for react-refresh-plugin.
@@ -81,36 +102,73 @@ class ReactRefreshPlugin {
81
102
// Inject react-refresh context to all Webpack entry points.
82
103
// This should create `EntryDependency` objects when available,
83
104
// and fallback to patching the `entry` object for legacy workflows.
84
- const additionalEntries = getAdditionalEntries ( {
105
+ const additional = getAdditionalEntries ( {
85
106
devServer : compiler . options . devServer ,
86
107
options : this . options ,
87
108
} ) ;
88
- if ( ! EntryPlugin ) {
89
- compiler . options . entry = injectRefreshEntry ( compiler . options . entry , additionalEntries ) ;
90
- } else {
91
- compiler . hooks . make . tapAsync (
92
- // `Number.NEGATIVE_INFINITY` ensures this will run before any other entries
93
- { name : this . constructor . name , stage : Number . NEGATIVE_INFINITY } ,
94
- ( compilation , callback ) => {
95
- additionalEntries . prependEntries . forEach ( ( entry ) => {
96
- /** @type {import('webpack').EntryOptions } */
97
- const entryOptions = { name : undefined } ;
98
- const dependency = EntryPlugin . createDependency ( entry , entryOptions ) ;
99
- compilation . addEntry ( compilation . context , dependency , entryOptions , ( err ) => {
100
- callback ( err ) ;
101
- } ) ;
102
- } ) ;
109
+ if ( EntryPlugin ) {
110
+ additional . prependEntries . forEach ( ( entry ) => {
111
+ new EntryPlugin ( compiler . context , entry , { name : undefined } ) . apply ( compiler ) ;
112
+ } ) ;
103
113
104
- additionalEntries . overlayEntries . forEach ( ( entry ) => {
105
- /** @type {import('webpack').EntryOptions } */
106
- const entryOptions = { dependOn : injectRefreshEntry . socketEntries , name : undefined } ;
107
- const dependency = EntryPlugin . createDependency ( entry , entryOptions ) ;
108
- compilation . addEntry ( compilation . context , dependency , entryOptions , ( err ) => {
109
- callback ( err ) ;
110
- } ) ;
111
- } ) ;
114
+ const socketEntryData = [ ] ;
115
+ compiler . hooks . make . tap (
116
+ { name : this . constructor . name , stage : Number . POSITIVE_INFINITY } ,
117
+ ( compilation ) => {
118
+ const integrationEntry = getSocketIntegrationEntry ( this . options . overlay . sockIntegration ) ;
119
+
120
+ // Exhaustively search all entries for `integrationEntry`.
121
+ // If found, inject `overlayEntries` to those entries,
122
+ // and ensure the order of dependencies either here or in `seal`.
123
+ // Else, inject `overlayEntries` to global entries.
124
+ for ( const [ name , entryData ] of compilation . entries . entries ( ) ) {
125
+ const index = entryData . dependencies . findIndex ( ( dep ) =>
126
+ dep . request . includes ( integrationEntry )
127
+ ) ;
128
+ if ( index !== - 1 ) {
129
+ socketEntryData . push ( { name, index } ) ;
130
+ }
131
+ }
112
132
}
113
133
) ;
134
+
135
+ additional . overlayEntries . forEach ( ( entry , idx , arr ) => {
136
+ compiler . hooks . finishMake . tapPromise (
137
+ { name : this . constructor . name , stage : Number . MIN_SAFE_INTEGER + ( arr . length - idx - 1 ) } ,
138
+ ( compilation ) => {
139
+ // Only hook into the current compiler
140
+ if ( compilation . compiler !== compiler ) {
141
+ return Promise . resolve ( ) ;
142
+ }
143
+
144
+ const injectData = socketEntryData . length ? socketEntryData : [ { name : undefined } ] ;
145
+ return Promise . all (
146
+ injectData . map ( ( { name, index } ) => {
147
+ return new Promise ( ( resolve , reject ) => {
148
+ const options = { name } ;
149
+ const dep = EntryPlugin . createDependency ( entry , options ) ;
150
+ compilation . addEntry ( compiler . context , dep , options , ( err ) => {
151
+ if ( err ) return reject ( err ) ;
152
+
153
+ if ( name && typeof index !== 'undefined' ) {
154
+ const entryData = compilation . entries . get ( name ) ;
155
+ entryData . dependencies . splice (
156
+ index + 1 ,
157
+ 0 ,
158
+ entryData . dependencies . splice ( entryData . dependencies . length - 1 , 1 ) [ 0 ]
159
+ ) ;
160
+ }
161
+
162
+ resolve ( ) ;
163
+ } ) ;
164
+ } ) ;
165
+ } )
166
+ ) . then ( ( ) => { } ) ;
167
+ }
168
+ ) ;
169
+ } ) ;
170
+ } else {
171
+ compiler . options . entry = injectRefreshEntry ( compiler . options . entry , additional ) ;
114
172
}
115
173
116
174
// Inject necessary modules to bundle's global scope
@@ -149,10 +207,8 @@ class ReactRefreshPlugin {
149
207
}
150
208
}
151
209
152
- const definePlugin = new DefinePlugin ( definedModules ) ;
153
- definePlugin . apply ( compiler ) ;
154
- const providePlugin = new ProvidePlugin ( providedModules ) ;
155
- providePlugin . apply ( compiler ) ;
210
+ new DefinePlugin ( definedModules ) . apply ( compiler ) ;
211
+ new ProvidePlugin ( providedModules ) . apply ( compiler ) ;
156
212
157
213
const match = ModuleFilenameHelpers . matchObject . bind ( undefined , this . options ) ;
158
214
const { evaluateToString, toConstantDependency } = getParserHelpers ( ) ;
@@ -272,10 +328,14 @@ class ReactRefreshPlugin {
272
328
break ;
273
329
}
274
330
case 5 : {
331
+ const EntryDependency = require ( 'webpack/lib/dependencies/EntryDependency' ) ;
275
332
const NormalModule = require ( 'webpack/lib/NormalModule' ) ;
276
333
const RuntimeGlobals = require ( 'webpack/lib/RuntimeGlobals' ) ;
277
334
const ReactRefreshRuntimeModule = require ( './RefreshRuntimeModule' ) ;
278
335
336
+ // Set factory for EntryDependency which is used to initialise the module
337
+ compilation . dependencyFactories . set ( EntryDependency , normalModuleFactory ) ;
338
+
279
339
compilation . hooks . additionalTreeRuntimeRequirements . tap (
280
340
this . constructor . name ,
281
341
// Setup react-refresh globals with a Webpack runtime module
0 commit comments