APIPlugin.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const RuntimeGlobals = require("./RuntimeGlobals");
  7. const WebpackError = require("./WebpackError");
  8. const ConstDependency = require("./dependencies/ConstDependency");
  9. const BasicEvaluatedExpression = require("./javascript/BasicEvaluatedExpression");
  10. const {
  11. toConstantDependency,
  12. evaluateToString
  13. } = require("./javascript/JavascriptParserHelpers");
  14. const ChunkNameRuntimeModule = require("./runtime/ChunkNameRuntimeModule");
  15. const GetFullHashRuntimeModule = require("./runtime/GetFullHashRuntimeModule");
  16. /** @typedef {import("./Compiler")} Compiler */
  17. /** @typedef {import("./javascript/JavascriptParser")} JavascriptParser */
  18. /* eslint-disable camelcase */
  19. const REPLACEMENTS = {
  20. __webpack_require__: {
  21. expr: RuntimeGlobals.require,
  22. req: [RuntimeGlobals.require],
  23. type: "function",
  24. assign: false
  25. },
  26. __webpack_public_path__: {
  27. expr: RuntimeGlobals.publicPath,
  28. req: [RuntimeGlobals.publicPath],
  29. type: "string",
  30. assign: true
  31. },
  32. __webpack_base_uri__: {
  33. expr: RuntimeGlobals.baseURI,
  34. req: [RuntimeGlobals.baseURI],
  35. type: "string",
  36. assign: true
  37. },
  38. __webpack_modules__: {
  39. expr: RuntimeGlobals.moduleFactories,
  40. req: [RuntimeGlobals.moduleFactories],
  41. type: "object",
  42. assign: false
  43. },
  44. __webpack_chunk_load__: {
  45. expr: RuntimeGlobals.ensureChunk,
  46. req: [RuntimeGlobals.ensureChunk],
  47. type: "function",
  48. assign: true
  49. },
  50. __non_webpack_require__: {
  51. expr: "require",
  52. req: null,
  53. type: undefined, // type is not known, depends on environment
  54. assign: true
  55. },
  56. __webpack_nonce__: {
  57. expr: RuntimeGlobals.scriptNonce,
  58. req: [RuntimeGlobals.scriptNonce],
  59. type: "string",
  60. assign: true
  61. },
  62. __webpack_hash__: {
  63. expr: `${RuntimeGlobals.getFullHash}()`,
  64. req: [RuntimeGlobals.getFullHash],
  65. type: "string",
  66. assign: false
  67. },
  68. __webpack_chunkname__: {
  69. expr: RuntimeGlobals.chunkName,
  70. req: [RuntimeGlobals.chunkName],
  71. type: "string",
  72. assign: false
  73. },
  74. __webpack_get_script_filename__: {
  75. expr: RuntimeGlobals.getChunkScriptFilename,
  76. req: [RuntimeGlobals.getChunkScriptFilename],
  77. type: "function",
  78. assign: true
  79. },
  80. __webpack_runtime_id__: {
  81. expr: RuntimeGlobals.runtimeId,
  82. req: [RuntimeGlobals.runtimeId],
  83. assign: false
  84. },
  85. "require.onError": {
  86. expr: RuntimeGlobals.uncaughtErrorHandler,
  87. req: [RuntimeGlobals.uncaughtErrorHandler],
  88. type: undefined, // type is not known, could be function or undefined
  89. assign: true // is never a pattern
  90. },
  91. __system_context__: {
  92. expr: RuntimeGlobals.systemContext,
  93. req: [RuntimeGlobals.systemContext],
  94. type: "object",
  95. assign: false
  96. },
  97. __webpack_share_scopes__: {
  98. expr: RuntimeGlobals.shareScopeMap,
  99. req: [RuntimeGlobals.shareScopeMap],
  100. type: "object",
  101. assign: false
  102. },
  103. __webpack_init_sharing__: {
  104. expr: RuntimeGlobals.initializeSharing,
  105. req: [RuntimeGlobals.initializeSharing],
  106. type: "function",
  107. assign: true
  108. }
  109. };
  110. /* eslint-enable camelcase */
  111. class APIPlugin {
  112. /**
  113. * Apply the plugin
  114. * @param {Compiler} compiler the compiler instance
  115. * @returns {void}
  116. */
  117. apply(compiler) {
  118. compiler.hooks.compilation.tap(
  119. "APIPlugin",
  120. (compilation, { normalModuleFactory }) => {
  121. compilation.dependencyTemplates.set(
  122. ConstDependency,
  123. new ConstDependency.Template()
  124. );
  125. compilation.hooks.runtimeRequirementInTree
  126. .for(RuntimeGlobals.chunkName)
  127. .tap("APIPlugin", chunk => {
  128. compilation.addRuntimeModule(
  129. chunk,
  130. new ChunkNameRuntimeModule(chunk.name)
  131. );
  132. return true;
  133. });
  134. compilation.hooks.runtimeRequirementInTree
  135. .for(RuntimeGlobals.getFullHash)
  136. .tap("APIPlugin", (chunk, set) => {
  137. compilation.addRuntimeModule(chunk, new GetFullHashRuntimeModule());
  138. return true;
  139. });
  140. /**
  141. * @param {JavascriptParser} parser the parser
  142. */
  143. const handler = parser => {
  144. Object.keys(REPLACEMENTS).forEach(key => {
  145. const info = REPLACEMENTS[key];
  146. parser.hooks.expression
  147. .for(key)
  148. .tap(
  149. "APIPlugin",
  150. toConstantDependency(parser, info.expr, info.req)
  151. );
  152. if (info.assign === false) {
  153. parser.hooks.assign.for(key).tap("APIPlugin", expr => {
  154. const err = new WebpackError(`${key} must not be assigned`);
  155. err.loc = expr.loc;
  156. throw err;
  157. });
  158. }
  159. if (info.type) {
  160. parser.hooks.evaluateTypeof
  161. .for(key)
  162. .tap("APIPlugin", evaluateToString(info.type));
  163. }
  164. });
  165. parser.hooks.expression
  166. .for("__webpack_layer__")
  167. .tap("APIPlugin", expr => {
  168. const dep = new ConstDependency(
  169. JSON.stringify(parser.state.module.layer),
  170. expr.range
  171. );
  172. dep.loc = expr.loc;
  173. parser.state.module.addPresentationalDependency(dep);
  174. return true;
  175. });
  176. parser.hooks.evaluateIdentifier
  177. .for("__webpack_layer__")
  178. .tap("APIPlugin", expr =>
  179. (parser.state.module.layer === null
  180. ? new BasicEvaluatedExpression().setNull()
  181. : new BasicEvaluatedExpression().setString(
  182. parser.state.module.layer
  183. )
  184. ).setRange(expr.range)
  185. );
  186. parser.hooks.evaluateTypeof
  187. .for("__webpack_layer__")
  188. .tap("APIPlugin", expr =>
  189. new BasicEvaluatedExpression()
  190. .setString(
  191. parser.state.module.layer === null ? "object" : "string"
  192. )
  193. .setRange(expr.range)
  194. );
  195. parser.hooks.expression
  196. .for("__webpack_module__.id")
  197. .tap("APIPlugin", expr => {
  198. parser.state.module.buildInfo.moduleConcatenationBailout =
  199. "__webpack_module__.id";
  200. const dep = new ConstDependency(
  201. parser.state.module.moduleArgument + ".id",
  202. expr.range,
  203. [RuntimeGlobals.moduleId]
  204. );
  205. dep.loc = expr.loc;
  206. parser.state.module.addPresentationalDependency(dep);
  207. return true;
  208. });
  209. parser.hooks.expression
  210. .for("__webpack_module__")
  211. .tap("APIPlugin", expr => {
  212. parser.state.module.buildInfo.moduleConcatenationBailout =
  213. "__webpack_module__";
  214. const dep = new ConstDependency(
  215. parser.state.module.moduleArgument,
  216. expr.range,
  217. [RuntimeGlobals.module]
  218. );
  219. dep.loc = expr.loc;
  220. parser.state.module.addPresentationalDependency(dep);
  221. return true;
  222. });
  223. parser.hooks.evaluateTypeof
  224. .for("__webpack_module__")
  225. .tap("APIPlugin", evaluateToString("object"));
  226. };
  227. normalModuleFactory.hooks.parser
  228. .for("javascript/auto")
  229. .tap("APIPlugin", handler);
  230. normalModuleFactory.hooks.parser
  231. .for("javascript/dynamic")
  232. .tap("APIPlugin", handler);
  233. normalModuleFactory.hooks.parser
  234. .for("javascript/esm")
  235. .tap("APIPlugin", handler);
  236. }
  237. );
  238. }
  239. }
  240. module.exports = APIPlugin;