You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 lines
4.5 KiB

4 years ago
  1. 'use strict';
  2. const webpack = require('webpack');
  3. const createDomain = require('./createDomain');
  4. /**
  5. * A Entry, it can be of type string or string[] or Object<string | string[],string>
  6. * @typedef {(string[] | string | Object<string | string[],string>)} Entry
  7. */
  8. /**
  9. * Add entries Method
  10. * @param {?Object} config - Webpack config
  11. * @param {?Object} options - Dev-Server options
  12. * @param {?Object} server
  13. * @returns {void}
  14. */
  15. function addEntries(config, options, server) {
  16. if (options.inline !== false) {
  17. // we're stubbing the app in this method as it's static and doesn't require
  18. // a server to be supplied. createDomain requires an app with the
  19. // address() signature.
  20. const app = server || {
  21. address() {
  22. return { port: options.port };
  23. },
  24. };
  25. /** @type {string} */
  26. const domain = createDomain(options, app);
  27. /** @type {string} */
  28. const sockHost = options.sockHost ? `&sockHost=${options.sockHost}` : '';
  29. /** @type {string} */
  30. const sockPath = options.sockPath ? `&sockPath=${options.sockPath}` : '';
  31. /** @type {string} */
  32. const sockPort = options.sockPort ? `&sockPort=${options.sockPort}` : '';
  33. /** @type {string} */
  34. const clientEntry = `${require.resolve(
  35. '../../client/'
  36. )}?${domain}${sockHost}${sockPath}${sockPort}`;
  37. /** @type {(string[] | string)} */
  38. let hotEntry;
  39. if (options.hotOnly) {
  40. hotEntry = require.resolve('webpack/hot/only-dev-server');
  41. } else if (options.hot) {
  42. hotEntry = require.resolve('webpack/hot/dev-server');
  43. }
  44. /**
  45. * prependEntry Method
  46. * @param {Entry} originalEntry
  47. * @param {Entry} additionalEntries
  48. * @returns {Entry}
  49. */
  50. const prependEntry = (originalEntry, additionalEntries) => {
  51. if (typeof originalEntry === 'function') {
  52. return () =>
  53. Promise.resolve(originalEntry()).then((entry) =>
  54. prependEntry(entry, additionalEntries)
  55. );
  56. }
  57. if (typeof originalEntry === 'object' && !Array.isArray(originalEntry)) {
  58. /** @type {Object<string,string>} */
  59. const clone = {};
  60. Object.keys(originalEntry).forEach((key) => {
  61. // entry[key] should be a string here
  62. clone[key] = prependEntry(originalEntry[key], additionalEntries);
  63. });
  64. return clone;
  65. }
  66. // in this case, entry is a string or an array.
  67. // make sure that we do not add duplicates.
  68. /** @type {Entry} */
  69. const entriesClone = additionalEntries.slice(0);
  70. [].concat(originalEntry).forEach((newEntry) => {
  71. if (!entriesClone.includes(newEntry)) {
  72. entriesClone.push(newEntry);
  73. }
  74. });
  75. return entriesClone;
  76. };
  77. /**
  78. *
  79. * Description of the option for checkInject method
  80. * @typedef {Function} checkInjectOptionsParam
  81. * @param {Object} _config - compilerConfig
  82. * @return {Boolean}
  83. */
  84. /**
  85. *
  86. * @param {Boolean | checkInjectOptionsParam} option - inject(Hot|Client) it is Boolean | fn => Boolean
  87. * @param {Object} _config
  88. * @param {Boolean} defaultValue
  89. * @return {Boolean}
  90. */
  91. // eslint-disable-next-line no-shadow
  92. const checkInject = (option, _config, defaultValue) => {
  93. if (typeof option === 'boolean') return option;
  94. if (typeof option === 'function') return option(_config);
  95. return defaultValue;
  96. };
  97. // eslint-disable-next-line no-shadow
  98. [].concat(config).forEach((config) => {
  99. /** @type {Boolean} */
  100. const webTarget = [
  101. 'web',
  102. 'webworker',
  103. 'electron-renderer',
  104. 'node-webkit',
  105. undefined, // eslint-disable-line
  106. null,
  107. ].includes(config.target);
  108. /** @type {Entry} */
  109. const additionalEntries = checkInject(
  110. options.injectClient,
  111. config,
  112. webTarget
  113. )
  114. ? [clientEntry]
  115. : [];
  116. if (hotEntry && checkInject(options.injectHot, config, true)) {
  117. additionalEntries.push(hotEntry);
  118. }
  119. config.entry = prependEntry(config.entry || './src', additionalEntries);
  120. if (options.hot || options.hotOnly) {
  121. config.plugins = config.plugins || [];
  122. if (
  123. !config.plugins.find(
  124. // Check for the name rather than the constructor reference in case
  125. // there are multiple copies of webpack installed
  126. (plugin) => plugin.constructor.name === 'HotModuleReplacementPlugin'
  127. )
  128. ) {
  129. config.plugins.push(new webpack.HotModuleReplacementPlugin());
  130. }
  131. }
  132. });
  133. }
  134. }
  135. module.exports = addEntries;