1 |
|
2 |
|
3 |
|
4 |
|
5 | "use strict";
|
6 |
|
7 | const Template = require("webpack/lib/Template");
|
8 |
|
9 | class JsonpMainTemplatePlugin {
|
10 |
|
11 | apply(mainTemplate) {
|
12 | mainTemplate.plugin("local-vars", function(source, chunk) {
|
13 | if(chunk.chunks.length > 0) {
|
14 | return this.asString([
|
15 | source,
|
16 | "",
|
17 | "// objects to store loaded and loading chunks",
|
18 | "var installedChunks = {",
|
19 | this.indent(
|
20 | chunk.ids.map(id => `${JSON.stringify(id)}: 0`).join(",\n")
|
21 | ),
|
22 | "};"
|
23 | ]);
|
24 | }
|
25 | return source;
|
26 | });
|
27 | mainTemplate.plugin("jsonp-script", function(_, chunk, hash) {
|
28 | var jsonpFunction = this.outputOptions.jsonpFunction;
|
29 | const chunkFilename = this.outputOptions.chunkFilename;
|
30 | const chunkMaps = chunk.getChunkMaps();
|
31 | const crossOriginLoading = this.outputOptions.crossOriginLoading;
|
32 | const chunkLoadTimeout = this.outputOptions.chunkLoadTimeout;
|
33 | const jsonpScriptType = this.outputOptions.jsonpScriptType;
|
34 | const scriptSrcPath = this.applyPluginsWaterfall("asset-path", JSON.stringify(chunkFilename), {
|
35 | hash: `" + ${this.renderCurrentHashCode(hash)} + "`,
|
36 | hashWithLength: length => `" + ${this.renderCurrentHashCode(hash, length)} + "`,
|
37 | chunk: {
|
38 | id: "\" + chunkId + \"",
|
39 | hash: `" + ${JSON.stringify(chunkMaps.hash)}[chunkId] + "`,
|
40 | hashWithLength(length) {
|
41 | const shortChunkHashMap = Object.create(null);
|
42 | Object.keys(chunkMaps.hash).forEach(chunkId => {
|
43 | if(typeof chunkMaps.hash[chunkId] === "string")
|
44 | shortChunkHashMap[chunkId] = chunkMaps.hash[chunkId].substr(0, length);
|
45 | });
|
46 | return `" + ${JSON.stringify(shortChunkHashMap)}[chunkId] + "`;
|
47 | },
|
48 | name: `" + (${JSON.stringify(chunkMaps.name)}[chunkId]||chunkId) + "`
|
49 | }
|
50 | });
|
51 | return this.asString([
|
52 | `if(typeof window !== "undefined"){`,
|
53 | "var script = document.createElement('script');",
|
54 | `script.type = ${JSON.stringify(jsonpScriptType)};`,
|
55 | "script.charset = 'utf-8';",
|
56 | "script.async = true;",
|
57 | `script.timeout = ${chunkLoadTimeout};`,
|
58 | crossOriginLoading ? `script.crossOrigin = ${JSON.stringify(crossOriginLoading)};` : "",
|
59 | `if (${this.requireFn}.nc) {`,
|
60 | this.indent(`script.setAttribute("nonce", ${this.requireFn}.nc);`),
|
61 | "}",
|
62 | `script.src = ${this.requireFn}.p + ${scriptSrcPath};`,
|
63 | `var timeout = setTimeout(onScriptComplete, ${chunkLoadTimeout});`,
|
64 | "script.onerror = script.onload = onScriptComplete;",
|
65 | "function onScriptComplete() {",
|
66 | this.indent([
|
67 | "// avoid mem leaks in IE.",
|
68 | "script.onerror = script.onload = null;",
|
69 | "clearTimeout(timeout);",
|
70 | "var chunk = installedChunks[chunkId];",
|
71 | "if(chunk !== 0) {",
|
72 | this.indent([
|
73 | "if(chunk) {",
|
74 | this.indent("chunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));"),
|
75 | "}",
|
76 | "installedChunks[chunkId] = undefined;"
|
77 | ]),
|
78 | "}"
|
79 | ]),
|
80 | "};",
|
81 | `document.querySelector("head").appendChild(script);`,
|
82 | "}else{",
|
83 | `weex.requireModule("stream").fetch({
|
84 | url:${this.requireFn}.p + ${scriptSrcPath}
|
85 | },function(data){
|
86 | var webpackJsonp = (typeof window==="undefined"?lightGlobal:window)[${JSON.stringify(jsonpFunction)}];
|
87 | eval(data.data)
|
88 | })`,
|
89 | "}",
|
90 | ]);
|
91 | });
|
92 | mainTemplate.plugin("require-ensure", function(_, chunk, hash) {
|
93 | return this.asString([
|
94 | "var installedChunkData = installedChunks[chunkId];",
|
95 | "if(installedChunkData === 0) {",
|
96 | this.indent([
|
97 | "return new Promise(function(resolve) { resolve(); });"
|
98 | ]),
|
99 | "}",
|
100 | "",
|
101 | "// a Promise means \"currently loading\".",
|
102 | "if(installedChunkData) {",
|
103 | this.indent([
|
104 | "return installedChunkData[2];"
|
105 | ]),
|
106 | "}",
|
107 | "",
|
108 | "// setup Promise in chunk cache",
|
109 | "var promise = new Promise(function(resolve, reject) {",
|
110 | this.indent([
|
111 | "installedChunkData = installedChunks[chunkId] = [resolve, reject];"
|
112 | ]),
|
113 | "});",
|
114 | "installedChunkData[2] = promise;",
|
115 | "",
|
116 | "// start chunk loading",
|
117 | this.applyPluginsWaterfall("jsonp-script", "", chunk, hash),
|
118 | "",
|
119 | "return promise;"
|
120 | ]);
|
121 | });
|
122 | mainTemplate.plugin("require-extensions", function(source, chunk) {
|
123 | if(chunk.chunks.length === 0) return source;
|
124 |
|
125 | return this.asString([
|
126 | source,
|
127 | "",
|
128 | "// on error function for async loading",
|
129 | `${this.requireFn}.oe = function(err) { console.error(err); throw err; };`
|
130 | ]);
|
131 | });
|
132 | mainTemplate.plugin("bootstrap", function(source, chunk, hash) {
|
133 | if(chunk.chunks.length > 0) {
|
134 | var jsonpFunction = this.outputOptions.jsonpFunction;
|
135 | return this.asString([
|
136 | source,
|
137 | "",
|
138 | "// install a JSONP callback for chunk loading",
|
139 | `var parentJsonpFunction = (typeof window==="undefined"?lightGlobal:window)[${JSON.stringify(jsonpFunction)}];`,
|
140 | `(typeof window==="undefined"?lightGlobal:window)[${JSON.stringify(jsonpFunction)}] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {`,
|
141 | this.indent([
|
142 | "// add \"moreModules\" to the modules object,",
|
143 | "// then flag all \"chunkIds\" as loaded and fire callback",
|
144 | "var moduleId, chunkId, i = 0, resolves = [], result;",
|
145 | "for(;i < chunkIds.length; i++) {",
|
146 | this.indent([
|
147 | "chunkId = chunkIds[i];",
|
148 | "if(installedChunks[chunkId]) {",
|
149 | this.indent("resolves.push(installedChunks[chunkId][0]);"),
|
150 | "}",
|
151 | "installedChunks[chunkId] = 0;"
|
152 | ]),
|
153 | "}",
|
154 | "for(moduleId in moreModules) {",
|
155 | this.indent([
|
156 | "if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {",
|
157 | this.indent(this.renderAddModule(hash, chunk, "moduleId", "moreModules[moduleId]")),
|
158 | "}"
|
159 | ]),
|
160 | "}",
|
161 | "if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);",
|
162 | "while(resolves.length) {",
|
163 | this.indent("resolves.shift()();"),
|
164 | "}",
|
165 | this.entryPointInChildren(chunk) ? [
|
166 | "if(executeModules) {",
|
167 | this.indent([
|
168 | "for(i=0; i < executeModules.length; i++) {",
|
169 | this.indent(`result = ${this.requireFn}(${this.requireFn}.s = executeModules[i]);`),
|
170 | "}"
|
171 | ]),
|
172 | "}",
|
173 | "return result;",
|
174 | ] : ""
|
175 | ]),
|
176 | "};"
|
177 | ]);
|
178 | }
|
179 | return source;
|
180 | });
|
181 | mainTemplate.plugin("hot-bootstrap", function(source, chunk, hash) {
|
182 | const hotUpdateChunkFilename = this.outputOptions.hotUpdateChunkFilename;
|
183 | const hotUpdateMainFilename = this.outputOptions.hotUpdateMainFilename;
|
184 | const crossOriginLoading = this.outputOptions.crossOriginLoading;
|
185 | const hotUpdateFunction = this.outputOptions.hotUpdateFunction;
|
186 | const currentHotUpdateChunkFilename = this.applyPluginsWaterfall("asset-path", JSON.stringify(hotUpdateChunkFilename), {
|
187 | hash: `" + ${this.renderCurrentHashCode(hash)} + "`,
|
188 | hashWithLength: length => `" + ${this.renderCurrentHashCode(hash, length)} + "`,
|
189 | chunk: {
|
190 | id: "\" + chunkId + \""
|
191 | }
|
192 | });
|
193 | const currentHotUpdateMainFilename = this.applyPluginsWaterfall("asset-path", JSON.stringify(hotUpdateMainFilename), {
|
194 | hash: `" + ${this.renderCurrentHashCode(hash)} + "`,
|
195 | hashWithLength: length => `" + ${this.renderCurrentHashCode(hash, length)} + "`
|
196 | });
|
197 | const runtimeSource = Template.getFunctionContent(require("webpack/lib/JsonpMainTemplate.runtime.js"))
|
198 | .replace(/\/\/\$semicolon/g, ";")
|
199 | .replace(/\$require\$/g, this.requireFn)
|
200 | .replace(/\$crossOriginLoading\$/g, crossOriginLoading ? `script.crossOrigin = ${JSON.stringify(crossOriginLoading)}` : "")
|
201 | .replace(/\$hotMainFilename\$/g, currentHotUpdateMainFilename)
|
202 | .replace(/\$hotChunkFilename\$/g, currentHotUpdateChunkFilename)
|
203 | .replace(/\$hash\$/g, JSON.stringify(hash));
|
204 | return `${source}
|
205 | function hotDisposeChunk(chunkId) {
|
206 | delete installedChunks[chunkId];
|
207 | }
|
208 | var parentHotUpdateCallback = window[${JSON.stringify(hotUpdateFunction)}];
|
209 | window[${JSON.stringify(hotUpdateFunction)}] = ${runtimeSource}`;
|
210 | });
|
211 | mainTemplate.plugin("hash", function(hash) {
|
212 | hash.update("jsonp");
|
213 | hash.update("4");
|
214 | hash.update(`${this.outputOptions.filename}`);
|
215 | hash.update(`${this.outputOptions.chunkFilename}`);
|
216 | hash.update(`${this.outputOptions.jsonpFunction}`);
|
217 | hash.update(`${this.outputOptions.hotUpdateFunction}`);
|
218 | });
|
219 | }
|
220 | }
|
221 | module.exports = JsonpMainTemplatePlugin;
|