UNPKG

8.36 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5"use strict";
6
7const Template = require("webpack/lib/Template");
8
9class 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}
205function hotDisposeChunk(chunkId) {
206 delete installedChunks[chunkId];
207}
208var parentHotUpdateCallback = window[${JSON.stringify(hotUpdateFunction)}];
209window[${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}
221module.exports = JsonpMainTemplatePlugin;