webpack.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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(options.context, options);
  58. new NodeEnvironmentPlugin({
  59. infrastructureLogging: options.infrastructureLogging
  60. }).apply(compiler);
  61. if (Array.isArray(options.plugins)) {
  62. for (const plugin of options.plugins) {
  63. if (typeof plugin === "function") {
  64. plugin.call(compiler, compiler);
  65. } else {
  66. plugin.apply(compiler);
  67. }
  68. }
  69. }
  70. applyWebpackOptionsDefaults(options);
  71. compiler.hooks.environment.call();
  72. compiler.hooks.afterEnvironment.call();
  73. new WebpackOptionsApply().process(options, compiler);
  74. compiler.hooks.initialize.call();
  75. return compiler;
  76. };
  77. /**
  78. * @callback WebpackFunctionSingle
  79. * @param {WebpackOptions} options options object
  80. * @param {Callback<Stats>=} callback callback
  81. * @returns {Compiler} the compiler object
  82. */
  83. /**
  84. * @callback WebpackFunctionMulti
  85. * @param {ReadonlyArray<WebpackOptions> & MultiCompilerOptions} options options objects
  86. * @param {Callback<MultiStats>=} callback callback
  87. * @returns {MultiCompiler} the multi compiler object
  88. */
  89. const asArray = options =>
  90. Array.isArray(options) ? Array.from(options) : [options];
  91. const webpack = /** @type {WebpackFunctionSingle & WebpackFunctionMulti} */ (
  92. /**
  93. * @param {WebpackOptions | (ReadonlyArray<WebpackOptions> & MultiCompilerOptions)} options options
  94. * @param {Callback<Stats> & Callback<MultiStats>=} callback callback
  95. * @returns {Compiler | MultiCompiler}
  96. */
  97. (options, callback) => {
  98. const create = () => {
  99. if (!asArray(options).every(webpackOptionsSchemaCheck)) {
  100. getValidateSchema()(webpackOptionsSchema, options);
  101. util.deprecate(
  102. () => {},
  103. "webpack bug: Pre-compiled schema reports error while real schema is happy. This has performance drawbacks.",
  104. "DEP_WEBPACK_PRE_COMPILED_SCHEMA_INVALID"
  105. )();
  106. }
  107. /** @type {MultiCompiler|Compiler} */
  108. let compiler;
  109. let watch = false;
  110. /** @type {WatchOptions|WatchOptions[]} */
  111. let watchOptions;
  112. if (Array.isArray(options)) {
  113. /** @type {MultiCompiler} */
  114. compiler = createMultiCompiler(
  115. options,
  116. /** @type {MultiCompilerOptions} */ (options)
  117. );
  118. watch = options.some(options => options.watch);
  119. watchOptions = options.map(options => options.watchOptions || {});
  120. } else {
  121. const webpackOptions = /** @type {WebpackOptions} */ (options);
  122. /** @type {Compiler} */
  123. compiler = createCompiler(webpackOptions);
  124. watch = webpackOptions.watch;
  125. watchOptions = webpackOptions.watchOptions || {};
  126. }
  127. return { compiler, watch, watchOptions };
  128. };
  129. if (callback) {
  130. try {
  131. const { compiler, watch, watchOptions } = create();
  132. if (watch) {
  133. compiler.watch(watchOptions, callback);
  134. } else {
  135. compiler.run((err, stats) => {
  136. compiler.close(err2 => {
  137. callback(err || err2, stats);
  138. });
  139. });
  140. }
  141. return compiler;
  142. } catch (err) {
  143. process.nextTick(() => callback(err));
  144. return null;
  145. }
  146. } else {
  147. const { compiler, watch } = create();
  148. if (watch) {
  149. util.deprecate(
  150. () => {},
  151. "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.",
  152. "DEP_WEBPACK_WATCH_WITHOUT_CALLBACK"
  153. )();
  154. }
  155. return compiler;
  156. }
  157. }
  158. );
  159. module.exports = webpack;