Skip to content

Commit

Permalink
feat: support of injectHot and injectClient on specific chunks
Browse files Browse the repository at this point in the history
  • Loading branch information
jeromeh committed Feb 24, 2021
1 parent d3837f9 commit 6e0e451
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 44 deletions.
18 changes: 16 additions & 2 deletions lib/options.json
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,13 @@
{
"type": "boolean"
},
{
"type": "array",
"items": {
"type": "string"
},
"minItems": 1
},
{
"instanceof": "Function"
}
Expand All @@ -238,6 +245,13 @@
{
"type": "boolean"
},
{
"type": "array",
"items": {
"type": "string"
},
"minItems": 1
},
{
"instanceof": "Function"
}
Expand Down Expand Up @@ -395,8 +409,8 @@
"hot": "should be {Boolean|String} (https://webpack.js.org/configuration/dev-server/#devserverhot)",
"http2": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverhttp2)",
"https": "should be {Object|Boolean} (https://webpack.js.org/configuration/dev-server/#devserverhttps)",
"injectClient": "should be {Boolean|Function} (https://webpack.js.org/configuration/dev-server/#devserverinjectclient)",
"injectHot": "should be {Boolean|Function} (https://webpack.js.org/configuration/dev-server/#devserverinjecthot)",
"injectClient": "should be {Boolean|String[]|Function} (https://webpack.js.org/configuration/dev-server/#devserverinjectclient)",
"injectHot": "should be {Boolean|String[]|Function} (https://webpack.js.org/configuration/dev-server/#devserverinjecthot)",
"liveReload": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverlivereload)",
"onAfterSetupMiddleware": "should be {Function} (https://webpack.js.org/configuration/dev-server/#devserverafter)",
"onBeforeSetupMiddleware": "should be {Function} (https://webpack.js.org/configuration/dev-server/#devserverbefore)",
Expand Down
129 changes: 90 additions & 39 deletions lib/utils/DevServerPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,17 @@ class DevServerPlugin {
}

/**
* An Entry, it can be of type string or string[] or Object<string | string[],string>
* A Entry, it can be of type string or string[] or Object<string | string[],string>
* @typedef {(string[] | string | Object<string | string[],string>)} Entry
*/

/**
* Additional entry to add to specific chunk
* @typedef {Object} AdditionalChunkEntry
* @property {Entry} entry
* @property {string[]} [chunks]
*/

/**
* Apply the plugin
* @param {Object} compiler the compiler instance
Expand Down Expand Up @@ -69,7 +76,7 @@ class DevServerPlugin {
/**
* prependEntry Method for webpack 4
* @param {Entry} originalEntry
* @param {Entry} additionalEntries
* @param {AdditionalChunkEntry[]} additionalEntries
* @returns {Entry}
*/
const prependEntry = (originalEntry, additionalEntries) => {
Expand All @@ -86,8 +93,13 @@ class DevServerPlugin {

Object.keys(originalEntry).forEach((key) => {
// entry[key] should be a string here
const chunkAdditionalEntries = additionalEntries.filter(
(additionalEntry) =>
!additionalEntry.chunks || additionalEntry.chunks.includes(key)
);

const entryDescription = originalEntry[key];
clone[key] = prependEntry(entryDescription, additionalEntries);
clone[key] = prependEntry(entryDescription, chunkAdditionalEntries);
});

return clone;
Expand All @@ -96,13 +108,15 @@ class DevServerPlugin {
// in this case, entry is a string or an array.
// make sure that we do not add duplicates.
/** @type {Entry} */
const entriesClone = additionalEntries.slice(0);
const newEntries = additionalEntries.map(
(additionalEntry) => additionalEntry.entry
);
[].concat(originalEntry).forEach((newEntry) => {
if (!entriesClone.includes(newEntry)) {
entriesClone.push(newEntry);
if (!newEntries.includes(newEntry)) {
newEntries.push(newEntry);
}
});
return entriesClone;
return newEntries;
};

/**
Expand All @@ -115,23 +129,27 @@ class DevServerPlugin {

/**
*
* @param {Boolean | checkInjectOptionsParam} option - inject(Hot|Client) it is Boolean | fn => Boolean
* @param {Boolean | string[] | checkInjectOptionsParam} option - inject(Hot|Client) it is Boolean | fn => Boolean
* @param {Object} _config
* @param {Boolean} defaultValue
* @return {Boolean}
* @return {Boolean | string[]}
*/
// eslint-disable-next-line no-shadow
// eslint-disable-next-line no-shadow
const checkInject = (option, _config, defaultValue) => {
if (typeof option === 'boolean') {
return option;
}
if (typeof option === 'boolean') {
return option;
}

if (typeof option === 'function') {
return option(_config);
}
if (Array.isArray(option)) {
return option;
}

return defaultValue;
};
if (typeof option === 'function') {
return option(_config);
}

return defaultValue;
};

const compilerOptions = compiler.options;

Expand All @@ -141,35 +159,68 @@ class DevServerPlugin {
const isWebTarget = compilerOptions.externalsPresets
? compilerOptions.externalsPresets.web
: [
'web',
'webworker',
'electron-renderer',
'node-webkit',
// eslint-disable-next-line no-undefined
undefined,
null,
].includes(compilerOptions.target);

/** @type {Entry} */
const additionalEntries = checkInject(
'web',
'webworker',
'electron-renderer',
'node-webkit',
// eslint-disable-next-line no-undefined
undefined,
null,
].includes(compilerOptions.target);

/** @type {AdditionalChunkEntry[]} */
const additionalEntries = [];

const checkInjectClientResult = checkInject(
options.injectClient,
compilerOptions,
isWebTarget
)
? [clientEntry]
: [];
);
if (checkInjectClientResult) {
additionalEntries.push({
entry: clientEntry,
chunks: Array.isArray(checkInjectClientResult)
? checkInjectClientResult
: null,
});
}

if (hotEntry && checkInject(options.injectHot, compilerOptions, true)) {
additionalEntries.push(hotEntry);
if (hotEntry) {
const checkInjectHotResult = checkInject(
options.injectHot,
compilerOptions,
true
);
if (checkInjectHotResult) {
additionalEntries.push({
entry: hotEntry,
chunks: Array.isArray(checkInjectHotResult)
? checkInjectHotResult
: null,
});
}
}

// use a hook to add entries if available
if (EntryPlugin) {
for (const additionalEntry of additionalEntries) {
new EntryPlugin(compiler.context, additionalEntry, {
// eslint-disable-next-line no-undefined
name: undefined,
}).apply(compiler);
for (const additionalChunkEntry of additionalEntries) {
// add entry to existing chunks
if (
additionalChunkEntry.chunks &&
Array.isArray(additionalChunkEntry.chunks)
) {
additionalChunkEntry.chunks.forEach((chunkName) => {
new EntryPlugin(compiler.context, additionalChunkEntry.entry, {
// eslint-disable-next-line no-undefined
name: chunkName,
}).apply(compiler);
});
} else {
new EntryPlugin(compiler.context, additionalChunkEntry.entry, {
// eslint-disable-next-line no-undefined
name: undefined,
}).apply(compiler);
}
}
} else {
compilerOptions.entry = prependEntry(
Expand Down
4 changes: 3 additions & 1 deletion test/__snapshots__/Validation.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ exports[`Validation validation should fail validation for invalid \`hot\` config
exports[`Validation validation should fail validation for invalid \`injectHot\` configuration 1`] = `
"Invalid configuration object. Object has been initialized using a configuration object that does not match the API schema.
- configuration.injectHot should be one of these:
boolean | function
boolean | [string, ...] (should not have fewer than 1 item) | function
Details:
* configuration.injectHot should be a boolean.
* configuration.injectHot should be an array:
[string, ...] (should not have fewer than 1 item)
* configuration.injectHot should be an instance of function."
`;

Expand Down
4 changes: 2 additions & 2 deletions test/options.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -359,11 +359,11 @@ describe('options', () => {
],
},
injectClient: {
success: [true, () => {}],
success: [true, ['a'], () => {}],
failure: [''],
},
injectHot: {
success: [true, () => {}],
success: [true, ['a'], () => {}],
failure: [''],
},
onListening: {
Expand Down

0 comments on commit 6e0e451

Please sign in to comment.