File: /home/imensosw/chartapi.imenso.co/node_modules/webpack-dev-server/lib/utils/DevServerPlugin.js
'use strict';
const webpack = require('webpack');
const createDomain = require('./createDomain');
const getSocketClientPath = require('./getSocketClientPath');
// @ts-ignore
const EntryPlugin = webpack.EntryPlugin;
class DevServerPlugin {
/**
* @param {?Object} options - Dev-Server options
*/
constructor(options) {
this.options = options;
}
/**
* An Entry, it can be of type string or string[] or Object<string | string[],string>
* @typedef {(string[] | string | Object<string | string[],string>)} Entry
*/
/**
* Apply the plugin
* @param {Object} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
const { options } = this;
/** @type {string} */
const domain = createDomain(options);
/** @type {string} */
const host =
options.client && options.client.host
? `&host=${options.client.host}`
: '';
/** @type {string} */
let path = '';
// only add the path if it is not default
if (
options.client &&
options.client.path &&
options.client.path !== '/ws'
) {
path = `&path=${options.client.path}`;
}
/** @type {string} */
const port =
options.client && options.client.port
? `&port=${options.client.port}`
: '';
/** @type {string} */
const clientEntry = `${require.resolve(
'../../client/'
)}?${domain}${host}${path}${port}`;
/** @type {(string[] | string)} */
let hotEntry;
if (options.hot === 'only') {
hotEntry = require.resolve('webpack/hot/only-dev-server');
} else if (options.hot) {
hotEntry = require.resolve('webpack/hot/dev-server');
}
/**
* prependEntry Method for webpack 4
* @param {Entry} originalEntry
* @param {Entry} additionalEntries
* @returns {Entry}
*/
const prependEntry = (originalEntry, additionalEntries) => {
if (typeof originalEntry === 'function') {
return () =>
Promise.resolve(originalEntry()).then((entry) =>
prependEntry(entry, additionalEntries)
);
}
if (typeof originalEntry === 'object' && !Array.isArray(originalEntry)) {
/** @type {Object<string,string>} */
const clone = {};
Object.keys(originalEntry).forEach((key) => {
// entry[key] should be a string here
const entryDescription = originalEntry[key];
clone[key] = prependEntry(entryDescription, additionalEntries);
});
return clone;
}
// 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);
[].concat(originalEntry).forEach((newEntry) => {
if (!entriesClone.includes(newEntry)) {
entriesClone.push(newEntry);
}
});
return entriesClone;
};
/**
*
* Description of the option for checkInject method
* @typedef {Function} checkInjectOptionsParam
* @param {Object} _config - compilerConfig
* @return {Boolean}
*/
/**
*
* @param {Boolean | checkInjectOptionsParam} option - inject(Hot|Client) it is Boolean | fn => Boolean
* @param {Object} _config
* @param {Boolean} defaultValue
* @return {Boolean}
*/
// eslint-disable-next-line no-shadow
const checkInject = (option, _config, defaultValue) => {
if (typeof option === 'boolean') {
return option;
}
if (typeof option === 'function') {
return option(_config);
}
return defaultValue;
};
const compilerOptions = compiler.options;
compilerOptions.plugins = compilerOptions.plugins || [];
/** @type {boolean} */
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(
options.injectClient,
compilerOptions,
isWebTarget
)
? [clientEntry]
: [];
if (hotEntry && checkInject(options.injectHot, compilerOptions, true)) {
additionalEntries.push(hotEntry);
}
// 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);
}
} else {
compilerOptions.entry = prependEntry(
compilerOptions.entry || './src',
additionalEntries
);
compiler.hooks.entryOption.call(
compilerOptions.context,
compilerOptions.entry
);
}
const providePlugin = new webpack.ProvidePlugin({
__webpack_dev_server_client__: getSocketClientPath(options),
});
providePlugin.apply(compiler);
if (
hotEntry &&
!compilerOptions.plugins.find(
(p) => p.constructor === webpack.HotModuleReplacementPlugin
)
) {
// apply the HMR plugin, if it didn't exist before.
const plugin = new webpack.HotModuleReplacementPlugin();
plugin.apply(compiler);
}
}
}
module.exports = DevServerPlugin;