webpack.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const util = require("util");
  7. const webpackOptionsSchemaCheck = require("../schemas/WebpackOptions.check.js");
  8. const webpackOptionsSchema = require("../schemas/WebpackOptions.json");
  9. const Compiler = require("./Compiler");
  10. const MultiCompiler = require("./MultiCompiler");
  11. const WebpackOptionsApply = require("./WebpackOptionsApply");
  12. const {
  13. applyWebpackOptionsDefaults,
  14. applyWebpackOptionsBaseDefaults
  15. } = require("./config/defaults");
  16. const { getNormalizedWebpackOptions } = require("./config/normalization");
  17. const NodeEnvironmentPlugin = require("./node/NodeEnvironmentPlugin");
  18. const memoize = require("./util/memoize");
  19. /** @typedef {import("../declarations/WebpackOptions").WebpackOptions} WebpackOptions */
  20. /** @typedef {import("./Compiler").WatchOptions} WatchOptions */
  21. /** @typedef {import("./MultiCompiler").MultiCompilerOptions} MultiCompilerOptions */
  22. /** @typedef {import("./MultiStats")} MultiStats */
  23. /** @typedef {import("./Stats")} Stats */
  24. const getValidateSchema = memoize(() => require("./validateSchema"));
  25. /**
  26. * @template T
  27. * @callback Callback
  28. * @param {Error=} err
  29. * @param {T=} stats
  30. * @returns {void}
  31. */
  32. /**
  33. * @param {ReadonlyArray<WebpackOptions>} childOptions options array
  34. * @param {MultiCompilerOptions} options options
  35. * @returns {MultiCompiler} a multi-compiler
  36. */
  37. const createMultiCompiler = (childOptions, options) => {
  38. const compilers = childOptions.map(options => createCompiler(options));
  39. const compiler = new MultiCompiler(compilers, options);
  40. for (const childCompiler of compilers) {
  41. if (childCompiler.options.dependencies) {
  42. compiler.setDependencies(
  43. childCompiler,
  44. childCompiler.options.dependencies
  45. );
  46. }
  47. }
  48. return compiler;
  49. };
  50. /**
  51. * @param {WebpackOptions} rawOptions options object
  52. * @returns {Compiler} a compiler
  53. */
  54. const createCompiler = rawOptions => {
  55. const options = getNormalizedWebpackOptions(rawOptions);
  56. applyWebpackOptionsBaseDefaults(options);
  57. const compiler = new Compiler(
  58. /** @type {string} */ (options.context),
  59. options
  60. );
  61. new NodeEnvironmentPlugin({
  62. infrastructureLogging: options.infrastructureLogging
  63. }).apply(compiler);
  64. if (Array.isArray(options.plugins)) {
  65. for (const plugin of options.plugins) {
  66. if (typeof plugin === "function") {
  67. plugin.call(compiler, compiler);
  68. } else if (plugin) {
  69. plugin.apply(compiler);
  70. }
  71. }
  72. }
  73. applyWebpackOptionsDefaults(options);
  74. compiler.hooks.environment.call();
  75. compiler.hooks.afterEnvironment.call();
  76. new WebpackOptionsApply().process(options, compiler);
  77. compiler.hooks.initialize.call();
  78. return compiler;
  79. };
  80. /**
  81. * @callback WebpackFunctionSingle
  82. * @param {WebpackOptions} options options object
  83. * @param {Callback<Stats>=} callback callback
  84. * @returns {Compiler} the compiler object
  85. */
  86. /**
  87. * @callback WebpackFunctionMulti
  88. * @param {ReadonlyArray<WebpackOptions> & MultiCompilerOptions} options options objects
  89. * @param {Callback<MultiStats>=} callback callback
  90. * @returns {MultiCompiler} the multi compiler object
  91. */
  92. /**
  93. * @template T
  94. * @param {Array<T> | T} options options
  95. * @returns {Array<T>} array of options
  96. */
  97. const asArray = options =>
  98. Array.isArray(options) ? Array.from(options) : [options];
  99. const webpack = /** @type {WebpackFunctionSingle & WebpackFunctionMulti} */ (
  100. /**
  101. * @param {WebpackOptions | (ReadonlyArray<WebpackOptions> & MultiCompilerOptions)} options options
  102. * @param {Callback<Stats> & Callback<MultiStats>=} callback callback
  103. * @returns {Compiler | MultiCompiler} Compiler or MultiCompiler
  104. */
  105. (options, callback) => {
  106. const create = () => {
  107. if (!asArray(options).every(webpackOptionsSchemaCheck)) {
  108. getValidateSchema()(webpackOptionsSchema, options);
  109. util.deprecate(
  110. () => {},
  111. "webpack bug: Pre-compiled schema reports error while real schema is happy. This has performance drawbacks.",
  112. "DEP_WEBPACK_PRE_COMPILED_SCHEMA_INVALID"
  113. )();
  114. }
  115. /** @type {MultiCompiler|Compiler} */
  116. let compiler;
  117. /** @type {boolean | undefined} */
  118. let watch = false;
  119. /** @type {WatchOptions|WatchOptions[]} */
  120. let watchOptions;
  121. if (Array.isArray(options)) {
  122. /** @type {MultiCompiler} */
  123. compiler = createMultiCompiler(
  124. options,
  125. /** @type {MultiCompilerOptions} */ (options)
  126. );
  127. watch = options.some(options => options.watch);
  128. watchOptions = options.map(options => options.watchOptions || {});
  129. } else {
  130. const webpackOptions = /** @type {WebpackOptions} */ (options);
  131. /** @type {Compiler} */
  132. compiler = createCompiler(webpackOptions);
  133. watch = webpackOptions.watch;
  134. watchOptions = webpackOptions.watchOptions || {};
  135. }
  136. return { compiler, watch, watchOptions };
  137. };
  138. if (callback) {
  139. try {
  140. const { compiler, watch, watchOptions } = create();
  141. if (watch) {
  142. compiler.watch(watchOptions, callback);
  143. } else {
  144. compiler.run((err, stats) => {
  145. compiler.close(err2 => {
  146. callback(err || err2, stats);
  147. });
  148. });
  149. }
  150. return compiler;
  151. } catch (err) {
  152. process.nextTick(() => callback(err));
  153. return null;
  154. }
  155. } else {
  156. const { compiler, watch } = create();
  157. if (watch) {
  158. util.deprecate(
  159. () => {},
  160. "A 'callback' argument needs to be provided to the 'webpack(options, callback)' function when the 'watch' option is set. There is no way to handle the 'watch' option without a callback.",
  161. "DEP_WEBPACK_WATCH_WITHOUT_CALLBACK"
  162. )();
  163. }
  164. return compiler;
  165. }
  166. }
  167. );
  168. module.exports = webpack;