Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support of injectHot and injectClient on specific chunks #2995

Open
wants to merge 1 commit into
base: v3
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions lib/options.json
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,13 @@
{
"type": "boolean"
},
{
"type": "array",
"items": {
"type": "string"
},
"minItems": 1
},
{
"instanceof": "Function"
}
Expand All @@ -170,6 +177,13 @@
{
"type": "boolean"
},
{
"type": "array",
"items": {
"type": "string"
},
"minItems": 1
},
{
"instanceof": "Function"
}
Expand Down Expand Up @@ -451,8 +465,8 @@
"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)",
"index": "should be {String} (https://webpack.js.org/configuration/dev-server/#devserverindex)",
"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)",
"inline": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverinline)",
"key": "should be {String|Buffer}",
"lazy": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverlazy-)",
Expand Down
64 changes: 43 additions & 21 deletions lib/utils/addEntries.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ const createDomain = require('./createDomain');
* @typedef {(string[] | string | Object<string | string[],string>)} Entry
*/

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

/**
* Add entries Method
* @param {?Object} config - Webpack config
Expand Down Expand Up @@ -51,7 +58,7 @@ function addEntries(config, options, server) {
/**
* prependEntry Method
* @param {Entry} originalEntry
* @param {Entry} additionalEntries
* @param {AdditionalChunkEntry[]} additionalEntries
* @returns {Entry}
*/
const prependEntry = (originalEntry, additionalEntries) => {
Expand All @@ -68,13 +75,17 @@ function addEntries(config, options, server) {

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

const entryDescription = originalEntry[key];
if (typeof entryDescription === 'object' && entryDescription.import) {
clone[key] = Object.assign({}, entryDescription, {
import: prependEntry(entryDescription.import, additionalEntries),
import: prependEntry(entryDescription.import, chunkAdditionalEntries),
});
} else {
clone[key] = prependEntry(entryDescription, additionalEntries);
clone[key] = prependEntry(entryDescription, chunkAdditionalEntries);
}
});

Expand All @@ -84,33 +95,36 @@ function addEntries(config, options, server) {
// 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) => {
return additionalEntry.entry;
});
[].concat(originalEntry).forEach((newEntry) => {
if (!entriesClone.includes(newEntry)) {
entriesClone.push(newEntry);
if (!newEntries.includes(newEntry)) {
newEntries.push(newEntry);
}
});
return entriesClone;
return newEntries;
};

/**
*
* Description of the option for checkInject method
* @typedef {Function} checkInjectOptionsParam
* @param {Object} _config - compilerConfig
* @return {Boolean}
* @return {Boolean | string[]}
*/

/**
*
* @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
const checkInject = (option, _config, defaultValue) => {
if (typeof option === 'boolean') return option;
if (Array.isArray(option)) return option;
if (typeof option === 'function') return option(_config);
return defaultValue;
};
Expand All @@ -126,17 +140,25 @@ function addEntries(config, options, server) {
undefined, // eslint-disable-line
null,
].includes(config.target);
/** @type {Entry} */
const additionalEntries = checkInject(
options.injectClient,
config,
webTarget
)
? [clientEntry]
: [];

if (hotEntry && checkInject(options.injectHot, config, true)) {
additionalEntries.push(hotEntry);
/** @type {AdditionalChunkEntry[]} */
const additionalEntries = []

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

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

config.entry = prependEntry(config.entry || './src', additionalEntries);
Expand Down
4 changes: 2 additions & 2 deletions test/options.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,11 @@ describe('options', () => {
failure: [false],
},
injectClient: {
success: [true, () => {}],
success: [true, ['a'], () => {}],
failure: [''],
},
injectHot: {
success: [true, () => {}],
success: [true, ['a'], () => {}],
failure: [''],
},
inline: {
Expand Down
36 changes: 36 additions & 0 deletions test/server/utils/addEntries.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,42 @@ describe('addEntries util', () => {
});
});

it('should allows selecting chunks to inline the client into', () => {
const webpackOptions = [
Object.assign({}, config, {
entry: {
chunk1: './foo.js',
chunk2: './foo.js',
chunk3: './foo.js'
}
})
];

const devServerOptions = {
injectClient: ['chunk1', 'chunk3']
};

addEntries(webpackOptions, devServerOptions);

// eslint-disable-next-line no-shadow
webpackOptions.forEach((webpackOptions) => {
expect(Object.keys(webpackOptions.entry).length).toEqual(3);
expect(webpackOptions.entry.chunk1.length).toEqual(2);
expect(webpackOptions.entry.chunk2.length).toEqual(1);
expect(webpackOptions.entry.chunk3.length).toEqual(2);

expect(
normalize(webpackOptions.entry.chunk1[0]).indexOf('client/index.js?') !== -1
).toBeTruthy();
expect(normalize(webpackOptions.entry.chunk2[0])).toEqual(
'./foo.js'
);
expect(
normalize(webpackOptions.entry.chunk3[0]).indexOf('client/index.js?') !== -1
).toBeTruthy();
});
});

it('should prepends the hot runtime to all targets by default (when hot)', () => {
const webpackOptions = [
Object.assign({ target: 'web' }, config),
Expand Down