UNPKG

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