Skip to content

Commit b06217c

Browse files
authored
Merge 6e0e451 into c49d783
2 parents c49d783 + 6e0e451 commit b06217c

File tree

4 files changed

+111
-44
lines changed

4 files changed

+111
-44
lines changed

lib/options.json

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,13 @@
228228
{
229229
"type": "boolean"
230230
},
231+
{
232+
"type": "array",
233+
"items": {
234+
"type": "string"
235+
},
236+
"minItems": 1
237+
},
231238
{
232239
"instanceof": "Function"
233240
}
@@ -238,6 +245,13 @@
238245
{
239246
"type": "boolean"
240247
},
248+
{
249+
"type": "array",
250+
"items": {
251+
"type": "string"
252+
},
253+
"minItems": 1
254+
},
241255
{
242256
"instanceof": "Function"
243257
}
@@ -395,8 +409,8 @@
395409
"hot": "should be {Boolean|String} (https://webpack.js.org/configuration/dev-server/#devserverhot)",
396410
"http2": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverhttp2)",
397411
"https": "should be {Object|Boolean} (https://webpack.js.org/configuration/dev-server/#devserverhttps)",
398-
"injectClient": "should be {Boolean|Function} (https://webpack.js.org/configuration/dev-server/#devserverinjectclient)",
399-
"injectHot": "should be {Boolean|Function} (https://webpack.js.org/configuration/dev-server/#devserverinjecthot)",
412+
"injectClient": "should be {Boolean|String[]|Function} (https://webpack.js.org/configuration/dev-server/#devserverinjectclient)",
413+
"injectHot": "should be {Boolean|String[]|Function} (https://webpack.js.org/configuration/dev-server/#devserverinjecthot)",
400414
"liveReload": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverlivereload)",
401415
"onAfterSetupMiddleware": "should be {Function} (https://webpack.js.org/configuration/dev-server/#devserverafter)",
402416
"onBeforeSetupMiddleware": "should be {Function} (https://webpack.js.org/configuration/dev-server/#devserverbefore)",

lib/utils/DevServerPlugin.js

Lines changed: 90 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,17 @@ class DevServerPlugin {
1616
}
1717

1818
/**
19-
* An Entry, it can be of type string or string[] or Object<string | string[],string>
19+
* A Entry, it can be of type string or string[] or Object<string | string[],string>
2020
* @typedef {(string[] | string | Object<string | string[],string>)} Entry
2121
*/
2222

23+
/**
24+
* Additional entry to add to specific chunk
25+
* @typedef {Object} AdditionalChunkEntry
26+
* @property {Entry} entry
27+
* @property {string[]} [chunks]
28+
*/
29+
2330
/**
2431
* Apply the plugin
2532
* @param {Object} compiler the compiler instance
@@ -69,7 +76,7 @@ class DevServerPlugin {
6976
/**
7077
* prependEntry Method for webpack 4
7178
* @param {Entry} originalEntry
72-
* @param {Entry} additionalEntries
79+
* @param {AdditionalChunkEntry[]} additionalEntries
7380
* @returns {Entry}
7481
*/
7582
const prependEntry = (originalEntry, additionalEntries) => {
@@ -86,8 +93,13 @@ class DevServerPlugin {
8693

8794
Object.keys(originalEntry).forEach((key) => {
8895
// entry[key] should be a string here
96+
const chunkAdditionalEntries = additionalEntries.filter(
97+
(additionalEntry) =>
98+
!additionalEntry.chunks || additionalEntry.chunks.includes(key)
99+
);
100+
89101
const entryDescription = originalEntry[key];
90-
clone[key] = prependEntry(entryDescription, additionalEntries);
102+
clone[key] = prependEntry(entryDescription, chunkAdditionalEntries);
91103
});
92104

93105
return clone;
@@ -96,13 +108,15 @@ class DevServerPlugin {
96108
// in this case, entry is a string or an array.
97109
// make sure that we do not add duplicates.
98110
/** @type {Entry} */
99-
const entriesClone = additionalEntries.slice(0);
111+
const newEntries = additionalEntries.map(
112+
(additionalEntry) => additionalEntry.entry
113+
);
100114
[].concat(originalEntry).forEach((newEntry) => {
101-
if (!entriesClone.includes(newEntry)) {
102-
entriesClone.push(newEntry);
115+
if (!newEntries.includes(newEntry)) {
116+
newEntries.push(newEntry);
103117
}
104118
});
105-
return entriesClone;
119+
return newEntries;
106120
};
107121

108122
/**
@@ -115,23 +129,27 @@ class DevServerPlugin {
115129

116130
/**
117131
*
118-
* @param {Boolean | checkInjectOptionsParam} option - inject(Hot|Client) it is Boolean | fn => Boolean
132+
* @param {Boolean | string[] | checkInjectOptionsParam} option - inject(Hot|Client) it is Boolean | fn => Boolean
119133
* @param {Object} _config
120134
* @param {Boolean} defaultValue
121-
* @return {Boolean}
135+
* @return {Boolean | string[]}
122136
*/
123-
// eslint-disable-next-line no-shadow
137+
// eslint-disable-next-line no-shadow
124138
const checkInject = (option, _config, defaultValue) => {
125-
if (typeof option === 'boolean') {
126-
return option;
127-
}
139+
if (typeof option === 'boolean') {
140+
return option;
141+
}
128142

129-
if (typeof option === 'function') {
130-
return option(_config);
131-
}
143+
if (Array.isArray(option)) {
144+
return option;
145+
}
132146

133-
return defaultValue;
134-
};
147+
if (typeof option === 'function') {
148+
return option(_config);
149+
}
150+
151+
return defaultValue;
152+
};
135153

136154
const compilerOptions = compiler.options;
137155

@@ -141,35 +159,68 @@ class DevServerPlugin {
141159
const isWebTarget = compilerOptions.externalsPresets
142160
? compilerOptions.externalsPresets.web
143161
: [
144-
'web',
145-
'webworker',
146-
'electron-renderer',
147-
'node-webkit',
148-
// eslint-disable-next-line no-undefined
149-
undefined,
150-
null,
151-
].includes(compilerOptions.target);
152-
153-
/** @type {Entry} */
154-
const additionalEntries = checkInject(
162+
'web',
163+
'webworker',
164+
'electron-renderer',
165+
'node-webkit',
166+
// eslint-disable-next-line no-undefined
167+
undefined,
168+
null,
169+
].includes(compilerOptions.target);
170+
171+
/** @type {AdditionalChunkEntry[]} */
172+
const additionalEntries = [];
173+
174+
const checkInjectClientResult = checkInject(
155175
options.injectClient,
156176
compilerOptions,
157177
isWebTarget
158-
)
159-
? [clientEntry]
160-
: [];
178+
);
179+
if (checkInjectClientResult) {
180+
additionalEntries.push({
181+
entry: clientEntry,
182+
chunks: Array.isArray(checkInjectClientResult)
183+
? checkInjectClientResult
184+
: null,
185+
});
186+
}
161187

162-
if (hotEntry && checkInject(options.injectHot, compilerOptions, true)) {
163-
additionalEntries.push(hotEntry);
188+
if (hotEntry) {
189+
const checkInjectHotResult = checkInject(
190+
options.injectHot,
191+
compilerOptions,
192+
true
193+
);
194+
if (checkInjectHotResult) {
195+
additionalEntries.push({
196+
entry: hotEntry,
197+
chunks: Array.isArray(checkInjectHotResult)
198+
? checkInjectHotResult
199+
: null,
200+
});
201+
}
164202
}
165203

166204
// use a hook to add entries if available
167205
if (EntryPlugin) {
168-
for (const additionalEntry of additionalEntries) {
169-
new EntryPlugin(compiler.context, additionalEntry, {
170-
// eslint-disable-next-line no-undefined
171-
name: undefined,
172-
}).apply(compiler);
206+
for (const additionalChunkEntry of additionalEntries) {
207+
// add entry to existing chunks
208+
if (
209+
additionalChunkEntry.chunks &&
210+
Array.isArray(additionalChunkEntry.chunks)
211+
) {
212+
additionalChunkEntry.chunks.forEach((chunkName) => {
213+
new EntryPlugin(compiler.context, additionalChunkEntry.entry, {
214+
// eslint-disable-next-line no-undefined
215+
name: chunkName,
216+
}).apply(compiler);
217+
});
218+
} else {
219+
new EntryPlugin(compiler.context, additionalChunkEntry.entry, {
220+
// eslint-disable-next-line no-undefined
221+
name: undefined,
222+
}).apply(compiler);
223+
}
173224
}
174225
} else {
175226
compilerOptions.entry = prependEntry(

test/__snapshots__/Validation.test.js.snap

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ exports[`Validation validation should fail validation for invalid \`hot\` config
1212
exports[`Validation validation should fail validation for invalid \`injectHot\` configuration 1`] = `
1313
"Invalid configuration object. Object has been initialized using a configuration object that does not match the API schema.
1414
- configuration.injectHot should be one of these:
15-
boolean | function
15+
boolean | [string, ...] (should not have fewer than 1 item) | function
1616
Details:
1717
* configuration.injectHot should be a boolean.
18+
* configuration.injectHot should be an array:
19+
[string, ...] (should not have fewer than 1 item)
1820
* configuration.injectHot should be an instance of function."
1921
`;
2022

test/options.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,11 +359,11 @@ describe('options', () => {
359359
],
360360
},
361361
injectClient: {
362-
success: [true, () => {}],
362+
success: [true, ['a'], () => {}],
363363
failure: [''],
364364
},
365365
injectHot: {
366-
success: [true, () => {}],
366+
success: [true, ['a'], () => {}],
367367
failure: [''],
368368
},
369369
onListening: {

0 commit comments

Comments
 (0)