RuntimeTemplate.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const Template = require("./Template");
  7. /** @typedef {import("./Module")} Module */
  8. module.exports = class RuntimeTemplate {
  9. constructor(outputOptions, requestShortener) {
  10. this.outputOptions = outputOptions || {};
  11. this.requestShortener = requestShortener;
  12. }
  13. /**
  14. * Add a comment
  15. * @param {object} options Information content of the comment
  16. * @param {string=} options.request request string used originally
  17. * @param {string=} options.chunkName name of the chunk referenced
  18. * @param {string=} options.chunkReason reason information of the chunk
  19. * @param {string=} options.message additional message
  20. * @param {string=} options.exportName name of the export
  21. * @returns {string} comment
  22. */
  23. comment({ request, chunkName, chunkReason, message, exportName }) {
  24. let content;
  25. if (this.outputOptions.pathinfo) {
  26. content = [message, request, chunkName, chunkReason]
  27. .filter(Boolean)
  28. .map(item => this.requestShortener.shorten(item))
  29. .join(" | ");
  30. } else {
  31. content = [message, chunkName, chunkReason]
  32. .filter(Boolean)
  33. .map(item => this.requestShortener.shorten(item))
  34. .join(" | ");
  35. }
  36. if (!content) return "";
  37. if (this.outputOptions.pathinfo) {
  38. return Template.toComment(content) + " ";
  39. } else {
  40. return Template.toNormalComment(content) + " ";
  41. }
  42. }
  43. throwMissingModuleErrorFunction({ request }) {
  44. const err = `Cannot find module '${request}'`;
  45. return `function webpackMissingModule() { var e = new Error(${JSON.stringify(
  46. err
  47. )}); e.code = 'MODULE_NOT_FOUND'; throw e; }`;
  48. }
  49. missingModule({ request }) {
  50. return `!(${this.throwMissingModuleErrorFunction({ request })}())`;
  51. }
  52. missingModuleStatement({ request }) {
  53. return `${this.missingModule({ request })};\n`;
  54. }
  55. missingModulePromise({ request }) {
  56. return `Promise.resolve().then(${this.throwMissingModuleErrorFunction({
  57. request
  58. })})`;
  59. }
  60. moduleId({ module, request }) {
  61. if (!module) {
  62. return this.missingModule({
  63. request
  64. });
  65. }
  66. if (module.id === null) {
  67. throw new Error(
  68. `RuntimeTemplate.moduleId(): Module ${module.identifier()} has no id. This should not happen.`
  69. );
  70. }
  71. return `${this.comment({ request })}${JSON.stringify(module.id)}`;
  72. }
  73. moduleRaw({ module, request }) {
  74. if (!module) {
  75. return this.missingModule({
  76. request
  77. });
  78. }
  79. return `__webpack_require__(${this.moduleId({ module, request })})`;
  80. }
  81. moduleExports({ module, request }) {
  82. return this.moduleRaw({
  83. module,
  84. request
  85. });
  86. }
  87. moduleNamespace({ module, request, strict }) {
  88. if (!module) {
  89. return this.missingModule({
  90. request
  91. });
  92. }
  93. const moduleId = this.moduleId({
  94. module,
  95. request
  96. });
  97. const exportsType = module.buildMeta && module.buildMeta.exportsType;
  98. if (exportsType === "namespace") {
  99. const rawModule = this.moduleRaw({
  100. module,
  101. request
  102. });
  103. return rawModule;
  104. } else if (exportsType === "named") {
  105. return `__webpack_require__.t(${moduleId}, 3)`;
  106. } else if (strict) {
  107. return `__webpack_require__.t(${moduleId}, 1)`;
  108. } else {
  109. return `__webpack_require__.t(${moduleId}, 7)`;
  110. }
  111. }
  112. moduleNamespacePromise({ block, module, request, message, strict, weak }) {
  113. if (!module) {
  114. return this.missingModulePromise({
  115. request
  116. });
  117. }
  118. if (module.id === null) {
  119. throw new Error(
  120. `RuntimeTemplate.moduleNamespacePromise(): Module ${module.identifier()} has no id. This should not happen.`
  121. );
  122. }
  123. const promise = this.blockPromise({
  124. block,
  125. message
  126. });
  127. let getModuleFunction;
  128. let idExpr = JSON.stringify(module.id);
  129. const comment = this.comment({
  130. request
  131. });
  132. let header = "";
  133. if (weak) {
  134. if (idExpr.length > 8) {
  135. // 'var x="nnnnnn";x,"+x+",x' vs '"nnnnnn",nnnnnn,"nnnnnn"'
  136. header += `var id = ${idExpr}; `;
  137. idExpr = "id";
  138. }
  139. header += `if(!__webpack_require__.m[${idExpr}]) { var e = new Error("Module '" + ${idExpr} + "' is not available (weak dependency)"); e.code = 'MODULE_NOT_FOUND'; throw e; } `;
  140. }
  141. const moduleId = this.moduleId({
  142. module,
  143. request
  144. });
  145. const exportsType = module.buildMeta && module.buildMeta.exportsType;
  146. if (exportsType === "namespace") {
  147. if (header) {
  148. const rawModule = this.moduleRaw({
  149. module,
  150. request
  151. });
  152. getModuleFunction = `function() { ${header}return ${rawModule}; }`;
  153. } else {
  154. getModuleFunction = `__webpack_require__.bind(null, ${comment}${idExpr})`;
  155. }
  156. } else if (exportsType === "named") {
  157. if (header) {
  158. getModuleFunction = `function() { ${header}return __webpack_require__.t(${moduleId}, 3); }`;
  159. } else {
  160. getModuleFunction = `__webpack_require__.t.bind(null, ${comment}${idExpr}, 3)`;
  161. }
  162. } else if (strict) {
  163. if (header) {
  164. getModuleFunction = `function() { ${header}return __webpack_require__.t(${moduleId}, 1); }`;
  165. } else {
  166. getModuleFunction = `__webpack_require__.t.bind(null, ${comment}${idExpr}, 1)`;
  167. }
  168. } else {
  169. if (header) {
  170. getModuleFunction = `function() { ${header}return __webpack_require__.t(${moduleId}, 7); }`;
  171. } else {
  172. getModuleFunction = `__webpack_require__.t.bind(null, ${comment}${idExpr}, 7)`;
  173. }
  174. }
  175. return `${promise || "Promise.resolve()"}.then(${getModuleFunction})`;
  176. }
  177. /**
  178. *
  179. * @param {Object} options options object
  180. * @param {boolean=} options.update whether a new variable should be created or the existing one updated
  181. * @param {Module} options.module the module
  182. * @param {string} options.request the request that should be printed as comment
  183. * @param {string} options.importVar name of the import variable
  184. * @param {Module} options.originModule module in which the statement is emitted
  185. * @returns {string} the import statement
  186. */
  187. importStatement({ update, module, request, importVar, originModule }) {
  188. if (!module) {
  189. return this.missingModuleStatement({
  190. request
  191. });
  192. }
  193. const moduleId = this.moduleId({
  194. module,
  195. request
  196. });
  197. const optDeclaration = update ? "" : "var ";
  198. const exportsType = module.buildMeta && module.buildMeta.exportsType;
  199. let content = `/* harmony import */ ${optDeclaration}${importVar} = __webpack_require__(${moduleId});\n`;
  200. if (!exportsType && !originModule.buildMeta.strictHarmonyModule) {
  201. content += `/* harmony import */ ${optDeclaration}${importVar}_default = /*#__PURE__*/__webpack_require__.n(${importVar});\n`;
  202. }
  203. if (exportsType === "named") {
  204. if (Array.isArray(module.buildMeta.providedExports)) {
  205. content += `${optDeclaration}${importVar}_namespace = /*#__PURE__*/__webpack_require__.t(${moduleId}, 1);\n`;
  206. } else {
  207. content += `${optDeclaration}${importVar}_namespace = /*#__PURE__*/__webpack_require__.t(${moduleId});\n`;
  208. }
  209. }
  210. return content;
  211. }
  212. exportFromImport({
  213. module,
  214. request,
  215. exportName,
  216. originModule,
  217. asiSafe,
  218. isCall,
  219. callContext,
  220. importVar
  221. }) {
  222. if (!module) {
  223. return this.missingModule({
  224. request
  225. });
  226. }
  227. const exportsType = module.buildMeta && module.buildMeta.exportsType;
  228. if (!exportsType) {
  229. if (exportName === "default") {
  230. if (!originModule.buildMeta.strictHarmonyModule) {
  231. if (isCall) {
  232. return `${importVar}_default()`;
  233. } else if (asiSafe) {
  234. return `(${importVar}_default())`;
  235. } else {
  236. return `${importVar}_default.a`;
  237. }
  238. } else {
  239. return importVar;
  240. }
  241. } else if (originModule.buildMeta.strictHarmonyModule) {
  242. if (exportName) {
  243. return "/* non-default import from non-esm module */undefined";
  244. } else {
  245. return `/*#__PURE__*/__webpack_require__.t(${importVar})`;
  246. }
  247. }
  248. }
  249. if (exportsType === "named") {
  250. if (exportName === "default") {
  251. return importVar;
  252. } else if (!exportName) {
  253. return `${importVar}_namespace`;
  254. }
  255. }
  256. if (exportName) {
  257. const used = module.isUsed(exportName);
  258. if (!used) {
  259. const comment = Template.toNormalComment(`unused export ${exportName}`);
  260. return `${comment} undefined`;
  261. }
  262. const comment =
  263. used !== exportName ? Template.toNormalComment(exportName) + " " : "";
  264. const access = `${importVar}[${comment}${JSON.stringify(used)}]`;
  265. if (isCall) {
  266. if (callContext === false && asiSafe) {
  267. return `(0,${access})`;
  268. } else if (callContext === false) {
  269. return `Object(${access})`;
  270. }
  271. }
  272. return access;
  273. } else {
  274. return importVar;
  275. }
  276. }
  277. blockPromise({ block, message }) {
  278. if (!block || !block.chunkGroup || block.chunkGroup.chunks.length === 0) {
  279. const comment = this.comment({
  280. message
  281. });
  282. return `Promise.resolve(${comment.trim()})`;
  283. }
  284. const chunks = block.chunkGroup.chunks.filter(
  285. chunk => !chunk.hasRuntime() && chunk.id !== null
  286. );
  287. const comment = this.comment({
  288. message,
  289. chunkName: block.chunkName,
  290. chunkReason: block.chunkReason
  291. });
  292. if (chunks.length === 1) {
  293. const chunkId = JSON.stringify(chunks[0].id);
  294. return `__webpack_require__.e(${comment}${chunkId})`;
  295. } else if (chunks.length > 0) {
  296. const requireChunkId = chunk =>
  297. `__webpack_require__.e(${JSON.stringify(chunk.id)})`;
  298. return `Promise.all(${comment.trim()}[${chunks
  299. .map(requireChunkId)
  300. .join(", ")}])`;
  301. } else {
  302. return `Promise.resolve(${comment.trim()})`;
  303. }
  304. }
  305. onError() {
  306. return "__webpack_require__.oe";
  307. }
  308. defineEsModuleFlagStatement({ exportsArgument }) {
  309. return `__webpack_require__.r(${exportsArgument});\n`;
  310. }
  311. };