UNPKG

5.41 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra and Zackary Jackson @ScriptedAlchemy
4*/
5
6"use strict";
7
8const { RawSource } = require("webpack-sources");
9const Module = require("../Module");
10const RuntimeGlobals = require("../RuntimeGlobals");
11const Template = require("../Template");
12const makeSerializable = require("../util/makeSerializable");
13const FallbackItemDependency = require("./FallbackItemDependency");
14
15/** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */
16/** @typedef {import("../Chunk")} Chunk */
17/** @typedef {import("../ChunkGraph")} ChunkGraph */
18/** @typedef {import("../ChunkGroup")} ChunkGroup */
19/** @typedef {import("../Compilation")} Compilation */
20/** @typedef {import("../Module").CodeGenerationContext} CodeGenerationContext */
21/** @typedef {import("../Module").CodeGenerationResult} CodeGenerationResult */
22/** @typedef {import("../Module").LibIdentOptions} LibIdentOptions */
23/** @typedef {import("../Module").NeedBuildContext} NeedBuildContext */
24/** @typedef {import("../RequestShortener")} RequestShortener */
25/** @typedef {import("../ResolverFactory").ResolverWithOptions} ResolverWithOptions */
26/** @typedef {import("../WebpackError")} WebpackError */
27/** @typedef {import("../util/Hash")} Hash */
28/** @typedef {import("../util/fs").InputFileSystem} InputFileSystem */
29
30const TYPES = new Set(["javascript"]);
31const RUNTIME_REQUIREMENTS = new Set([RuntimeGlobals.module]);
32
33class FallbackModule extends Module {
34 /**
35 * @param {string[]} requests list of requests to choose one
36 */
37 constructor(requests) {
38 super("fallback-module");
39 this.requests = requests;
40 this._identifier = `fallback ${this.requests.join(" ")}`;
41 }
42
43 /**
44 * @returns {string} a unique identifier of the module
45 */
46 identifier() {
47 return this._identifier;
48 }
49
50 /**
51 * @param {RequestShortener} requestShortener the request shortener
52 * @returns {string} a user readable identifier of the module
53 */
54 readableIdentifier(requestShortener) {
55 return this._identifier;
56 }
57
58 /**
59 * @param {LibIdentOptions} options options
60 * @returns {string | null} an identifier for library inclusion
61 */
62 libIdent(options) {
63 return `${this.layer ? `(${this.layer})/` : ""}webpack/container/fallback/${
64 this.requests[0]
65 }/and ${this.requests.length - 1} more`;
66 }
67
68 /**
69 * @param {Chunk} chunk the chunk which condition should be checked
70 * @param {Compilation} compilation the compilation
71 * @returns {boolean} true, if the chunk is ok for the module
72 */
73 chunkCondition(chunk, { chunkGraph }) {
74 return chunkGraph.getNumberOfEntryModules(chunk) > 0;
75 }
76
77 /**
78 * @param {NeedBuildContext} context context info
79 * @param {function((WebpackError | null)=, boolean=): void} callback callback function, returns true, if the module needs a rebuild
80 * @returns {void}
81 */
82 needBuild(context, callback) {
83 callback(null, !this.buildInfo);
84 }
85
86 /**
87 * @param {WebpackOptions} options webpack options
88 * @param {Compilation} compilation the compilation
89 * @param {ResolverWithOptions} resolver the resolver
90 * @param {InputFileSystem} fs the file system
91 * @param {function(WebpackError=): void} callback callback function
92 * @returns {void}
93 */
94 build(options, compilation, resolver, fs, callback) {
95 this.buildMeta = {};
96 this.buildInfo = {
97 strict: true
98 };
99
100 this.clearDependenciesAndBlocks();
101 for (const request of this.requests)
102 this.addDependency(new FallbackItemDependency(request));
103
104 callback();
105 }
106
107 /**
108 * @param {string=} type the source type for which the size should be estimated
109 * @returns {number} the estimated size of the module (must be non-zero)
110 */
111 size(type) {
112 return this.requests.length * 5 + 42;
113 }
114
115 /**
116 * @returns {Set<string>} types available (do not mutate)
117 */
118 getSourceTypes() {
119 return TYPES;
120 }
121
122 /**
123 * @param {CodeGenerationContext} context context for code generation
124 * @returns {CodeGenerationResult} result
125 */
126 codeGeneration({ runtimeTemplate, moduleGraph, chunkGraph }) {
127 const ids = this.dependencies.map(dep =>
128 chunkGraph.getModuleId(moduleGraph.getModule(dep))
129 );
130 const code = Template.asString([
131 `var ids = ${JSON.stringify(ids)};`,
132 "var error, result, i = 0;",
133 `var loop = ${runtimeTemplate.basicFunction("next", [
134 "while(i < ids.length) {",
135 Template.indent([
136 "try { next = __webpack_require__(ids[i++]); } catch(e) { return handleError(e); }",
137 "if(next) return next.then ? next.then(handleResult, handleError) : handleResult(next);"
138 ]),
139 "}",
140 "if(error) throw error;"
141 ])}`,
142 `var handleResult = ${runtimeTemplate.basicFunction("result", [
143 "if(result) return result;",
144 "return loop();"
145 ])};`,
146 `var handleError = ${runtimeTemplate.basicFunction("e", [
147 "error = e;",
148 "return loop();"
149 ])};`,
150 "module.exports = loop();"
151 ]);
152 const sources = new Map();
153 sources.set("javascript", new RawSource(code));
154 return { sources, runtimeRequirements: RUNTIME_REQUIREMENTS };
155 }
156
157 serialize(context) {
158 const { write } = context;
159 write(this.requests);
160 super.serialize(context);
161 }
162
163 static deserialize(context) {
164 const { read } = context;
165 const obj = new FallbackModule(read());
166 obj.deserialize(context);
167 return obj;
168 }
169}
170
171makeSerializable(FallbackModule, "webpack/lib/container/FallbackModule");
172
173module.exports = FallbackModule;