APIPlugin.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const {
  7. getExternalModuleNodeCommonjsInitFragment
  8. } = require("./ExternalModule");
  9. const {
  10. JAVASCRIPT_MODULE_TYPE_AUTO,
  11. JAVASCRIPT_MODULE_TYPE_DYNAMIC,
  12. JAVASCRIPT_MODULE_TYPE_ESM
  13. } = require("./ModuleTypeConstants");
  14. const RuntimeGlobals = require("./RuntimeGlobals");
  15. const WebpackError = require("./WebpackError");
  16. const ConstDependency = require("./dependencies/ConstDependency");
  17. const BasicEvaluatedExpression = require("./javascript/BasicEvaluatedExpression");
  18. const JavascriptModulesPlugin = require("./javascript/JavascriptModulesPlugin");
  19. const {
  20. evaluateToString,
  21. toConstantDependency
  22. } = require("./javascript/JavascriptParserHelpers");
  23. const ChunkNameRuntimeModule = require("./runtime/ChunkNameRuntimeModule");
  24. const GetFullHashRuntimeModule = require("./runtime/GetFullHashRuntimeModule");
  25. /** @typedef {import("./Compiler")} Compiler */
  26. /** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
  27. /** @typedef {import("./Module").BuildInfo} BuildInfo */
  28. /** @typedef {import("./javascript/JavascriptParser")} JavascriptParser */
  29. /** @typedef {import("./javascript/JavascriptParser").Range} Range */
  30. /**
  31. * @returns {Record<string, {expr: string, req: string[] | null, type?: string, assign: boolean}>} replacements
  32. */
  33. function getReplacements() {
  34. return {
  35. __webpack_require__: {
  36. expr: RuntimeGlobals.require,
  37. req: [RuntimeGlobals.require],
  38. type: "function",
  39. assign: false
  40. },
  41. __webpack_global__: {
  42. expr: RuntimeGlobals.require,
  43. req: [RuntimeGlobals.require],
  44. type: "function",
  45. assign: false
  46. },
  47. __webpack_public_path__: {
  48. expr: RuntimeGlobals.publicPath,
  49. req: [RuntimeGlobals.publicPath],
  50. type: "string",
  51. assign: true
  52. },
  53. __webpack_base_uri__: {
  54. expr: RuntimeGlobals.baseURI,
  55. req: [RuntimeGlobals.baseURI],
  56. type: "string",
  57. assign: true
  58. },
  59. __webpack_modules__: {
  60. expr: RuntimeGlobals.moduleFactories,
  61. req: [RuntimeGlobals.moduleFactories],
  62. type: "object",
  63. assign: false
  64. },
  65. __webpack_chunk_load__: {
  66. expr: RuntimeGlobals.ensureChunk,
  67. req: [RuntimeGlobals.ensureChunk],
  68. type: "function",
  69. assign: true
  70. },
  71. __non_webpack_require__: {
  72. expr: "require",
  73. req: null,
  74. type: undefined, // type is not known, depends on environment
  75. assign: true
  76. },
  77. __webpack_nonce__: {
  78. expr: RuntimeGlobals.scriptNonce,
  79. req: [RuntimeGlobals.scriptNonce],
  80. type: "string",
  81. assign: true
  82. },
  83. __webpack_hash__: {
  84. expr: `${RuntimeGlobals.getFullHash}()`,
  85. req: [RuntimeGlobals.getFullHash],
  86. type: "string",
  87. assign: false
  88. },
  89. __webpack_chunkname__: {
  90. expr: RuntimeGlobals.chunkName,
  91. req: [RuntimeGlobals.chunkName],
  92. type: "string",
  93. assign: false
  94. },
  95. __webpack_get_script_filename__: {
  96. expr: RuntimeGlobals.getChunkScriptFilename,
  97. req: [RuntimeGlobals.getChunkScriptFilename],
  98. type: "function",
  99. assign: true
  100. },
  101. __webpack_runtime_id__: {
  102. expr: RuntimeGlobals.runtimeId,
  103. req: [RuntimeGlobals.runtimeId],
  104. assign: false
  105. },
  106. "require.onError": {
  107. expr: RuntimeGlobals.uncaughtErrorHandler,
  108. req: [RuntimeGlobals.uncaughtErrorHandler],
  109. type: undefined, // type is not known, could be function or undefined
  110. assign: true // is never a pattern
  111. },
  112. __system_context__: {
  113. expr: RuntimeGlobals.systemContext,
  114. req: [RuntimeGlobals.systemContext],
  115. type: "object",
  116. assign: false
  117. },
  118. __webpack_share_scopes__: {
  119. expr: RuntimeGlobals.shareScopeMap,
  120. req: [RuntimeGlobals.shareScopeMap],
  121. type: "object",
  122. assign: false
  123. },
  124. __webpack_init_sharing__: {
  125. expr: RuntimeGlobals.initializeSharing,
  126. req: [RuntimeGlobals.initializeSharing],
  127. type: "function",
  128. assign: true
  129. }
  130. };
  131. }
  132. const PLUGIN_NAME = "APIPlugin";
  133. class APIPlugin {
  134. /**
  135. * Apply the plugin
  136. * @param {Compiler} compiler the compiler instance
  137. * @returns {void}
  138. */
  139. apply(compiler) {
  140. compiler.hooks.compilation.tap(
  141. PLUGIN_NAME,
  142. (compilation, { normalModuleFactory }) => {
  143. const moduleOutput = compilation.options.output.module;
  144. const nodeTarget = compiler.platform.node;
  145. const nodeEsm = moduleOutput && nodeTarget;
  146. const REPLACEMENTS = getReplacements();
  147. if (nodeEsm) {
  148. REPLACEMENTS.__non_webpack_require__.expr =
  149. "__WEBPACK_EXTERNAL_createRequire_require";
  150. }
  151. compilation.dependencyTemplates.set(
  152. ConstDependency,
  153. new ConstDependency.Template()
  154. );
  155. compilation.hooks.runtimeRequirementInTree
  156. .for(RuntimeGlobals.chunkName)
  157. .tap(PLUGIN_NAME, (chunk) => {
  158. compilation.addRuntimeModule(
  159. chunk,
  160. new ChunkNameRuntimeModule(/** @type {string} */ (chunk.name))
  161. );
  162. return true;
  163. });
  164. compilation.hooks.runtimeRequirementInTree
  165. .for(RuntimeGlobals.getFullHash)
  166. .tap(PLUGIN_NAME, (chunk, _set) => {
  167. compilation.addRuntimeModule(chunk, new GetFullHashRuntimeModule());
  168. return true;
  169. });
  170. const hooks = JavascriptModulesPlugin.getCompilationHooks(compilation);
  171. hooks.renderModuleContent.tap(
  172. PLUGIN_NAME,
  173. (source, module, renderContext) => {
  174. if (/** @type {BuildInfo} */ (module.buildInfo).needCreateRequire) {
  175. const chunkInitFragments = [
  176. getExternalModuleNodeCommonjsInitFragment(
  177. renderContext.runtimeTemplate
  178. )
  179. ];
  180. renderContext.chunkInitFragments.push(...chunkInitFragments);
  181. }
  182. return source;
  183. }
  184. );
  185. /**
  186. * @param {JavascriptParser} parser the parser
  187. */
  188. const handler = (parser) => {
  189. for (const key of Object.keys(REPLACEMENTS)) {
  190. const info = REPLACEMENTS[key];
  191. parser.hooks.expression.for(key).tap(PLUGIN_NAME, (expression) => {
  192. const dep = toConstantDependency(parser, info.expr, info.req);
  193. if (key === "__non_webpack_require__" && moduleOutput) {
  194. if (nodeTarget) {
  195. /** @type {BuildInfo} */
  196. (parser.state.module.buildInfo).needCreateRequire = true;
  197. } else {
  198. const warning = new WebpackError(
  199. `${PLUGIN_NAME}\n__non_webpack_require__ is only allowed in target node`
  200. );
  201. warning.loc = /** @type {DependencyLocation} */ (
  202. expression.loc
  203. );
  204. warning.module = parser.state.module;
  205. compilation.warnings.push(warning);
  206. }
  207. }
  208. return dep(expression);
  209. });
  210. if (info.assign === false) {
  211. parser.hooks.assign.for(key).tap(PLUGIN_NAME, (expr) => {
  212. const err = new WebpackError(`${key} must not be assigned`);
  213. err.loc = /** @type {DependencyLocation} */ (expr.loc);
  214. throw err;
  215. });
  216. }
  217. if (info.type) {
  218. parser.hooks.evaluateTypeof
  219. .for(key)
  220. .tap(PLUGIN_NAME, evaluateToString(info.type));
  221. }
  222. }
  223. parser.hooks.expression
  224. .for("__webpack_layer__")
  225. .tap(PLUGIN_NAME, (expr) => {
  226. const dep = new ConstDependency(
  227. JSON.stringify(parser.state.module.layer),
  228. /** @type {Range} */ (expr.range)
  229. );
  230. dep.loc = /** @type {DependencyLocation} */ (expr.loc);
  231. parser.state.module.addPresentationalDependency(dep);
  232. return true;
  233. });
  234. parser.hooks.evaluateIdentifier
  235. .for("__webpack_layer__")
  236. .tap(PLUGIN_NAME, (expr) =>
  237. (parser.state.module.layer === null
  238. ? new BasicEvaluatedExpression().setNull()
  239. : new BasicEvaluatedExpression().setString(
  240. parser.state.module.layer
  241. )
  242. ).setRange(/** @type {Range} */ (expr.range))
  243. );
  244. parser.hooks.evaluateTypeof
  245. .for("__webpack_layer__")
  246. .tap(PLUGIN_NAME, (expr) =>
  247. new BasicEvaluatedExpression()
  248. .setString(
  249. parser.state.module.layer === null ? "object" : "string"
  250. )
  251. .setRange(/** @type {Range} */ (expr.range))
  252. );
  253. parser.hooks.expression
  254. .for("__webpack_module__.id")
  255. .tap(PLUGIN_NAME, (expr) => {
  256. /** @type {BuildInfo} */
  257. (parser.state.module.buildInfo).moduleConcatenationBailout =
  258. "__webpack_module__.id";
  259. const dep = new ConstDependency(
  260. `${parser.state.module.moduleArgument}.id`,
  261. /** @type {Range} */ (expr.range),
  262. [RuntimeGlobals.moduleId]
  263. );
  264. dep.loc = /** @type {DependencyLocation} */ (expr.loc);
  265. parser.state.module.addPresentationalDependency(dep);
  266. return true;
  267. });
  268. parser.hooks.expression
  269. .for("__webpack_module__")
  270. .tap(PLUGIN_NAME, (expr) => {
  271. /** @type {BuildInfo} */
  272. (parser.state.module.buildInfo).moduleConcatenationBailout =
  273. "__webpack_module__";
  274. const dep = new ConstDependency(
  275. parser.state.module.moduleArgument,
  276. /** @type {Range} */ (expr.range),
  277. [RuntimeGlobals.module]
  278. );
  279. dep.loc = /** @type {DependencyLocation} */ (expr.loc);
  280. parser.state.module.addPresentationalDependency(dep);
  281. return true;
  282. });
  283. parser.hooks.evaluateTypeof
  284. .for("__webpack_module__")
  285. .tap(PLUGIN_NAME, evaluateToString("object"));
  286. };
  287. normalModuleFactory.hooks.parser
  288. .for(JAVASCRIPT_MODULE_TYPE_AUTO)
  289. .tap(PLUGIN_NAME, handler);
  290. normalModuleFactory.hooks.parser
  291. .for(JAVASCRIPT_MODULE_TYPE_DYNAMIC)
  292. .tap(PLUGIN_NAME, handler);
  293. normalModuleFactory.hooks.parser
  294. .for(JAVASCRIPT_MODULE_TYPE_ESM)
  295. .tap(PLUGIN_NAME, handler);
  296. }
  297. );
  298. }
  299. }
  300. module.exports = APIPlugin;