UNPKG

4.18 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const ConstDependency = require("./dependencies/ConstDependency");
9
10/** @typedef {import("./Compiler")} Compiler */
11/** @typedef {import("./javascript/JavascriptParser")} JavascriptParser */
12
13const nestedWebpackRequireTag = Symbol("nested __webpack_require__");
14
15class CompatibilityPlugin {
16 /**
17 * Apply the plugin
18 * @param {Compiler} compiler the compiler instance
19 * @returns {void}
20 */
21 apply(compiler) {
22 compiler.hooks.compilation.tap(
23 "CompatibilityPlugin",
24 (compilation, { normalModuleFactory }) => {
25 compilation.dependencyTemplates.set(
26 ConstDependency,
27 new ConstDependency.Template()
28 );
29
30 normalModuleFactory.hooks.parser
31 .for("javascript/auto")
32 .tap("CompatibilityPlugin", (parser, parserOptions) => {
33 if (
34 parserOptions.browserify !== undefined &&
35 !parserOptions.browserify
36 )
37 return;
38
39 parser.hooks.call
40 .for("require")
41 .tap("CompatibilityPlugin", expr => {
42 // support for browserify style require delegator: "require(o, !0)"
43 if (expr.arguments.length !== 2) return;
44 const second = parser.evaluateExpression(expr.arguments[1]);
45 if (!second.isBoolean()) return;
46 if (second.asBool() !== true) return;
47 const dep = new ConstDependency("require", expr.callee.range);
48 dep.loc = expr.loc;
49 if (parser.state.current.dependencies.length > 0) {
50 const last =
51 parser.state.current.dependencies[
52 parser.state.current.dependencies.length - 1
53 ];
54 if (
55 last.critical &&
56 last.options &&
57 last.options.request === "." &&
58 last.userRequest === "." &&
59 last.options.recursive
60 )
61 parser.state.current.dependencies.pop();
62 }
63 parser.state.module.addPresentationalDependency(dep);
64 return true;
65 });
66 });
67
68 /**
69 * @param {JavascriptParser} parser the parser
70 * @returns {void}
71 */
72 const nestedWebpackRequireHandler = parser => {
73 parser.hooks.preStatement.tap("CompatibilityPlugin", statement => {
74 if (
75 statement.type === "FunctionDeclaration" &&
76 statement.id &&
77 statement.id.name === "__webpack_require__"
78 ) {
79 const newName = `__nested_webpack_require_${statement.range[0]}__`;
80 parser.tagVariable(statement.id.name, nestedWebpackRequireTag, {
81 name: newName,
82 declaration: {
83 updated: false,
84 loc: statement.id.loc,
85 range: statement.id.range
86 }
87 });
88 return true;
89 }
90 });
91 parser.hooks.pattern
92 .for("__webpack_require__")
93 .tap("CompatibilityPlugin", pattern => {
94 const newName = `__nested_webpack_require_${pattern.range[0]}__`;
95 parser.tagVariable(pattern.name, nestedWebpackRequireTag, {
96 name: newName,
97 declaration: {
98 updated: false,
99 loc: pattern.loc,
100 range: pattern.range
101 }
102 });
103 return true;
104 });
105 parser.hooks.expression
106 .for(nestedWebpackRequireTag)
107 .tap("CompatibilityPlugin", expr => {
108 const { name, declaration } = parser.currentTagData;
109 if (!declaration.updated) {
110 const dep = new ConstDependency(name, declaration.range);
111 dep.loc = declaration.loc;
112 parser.state.module.addPresentationalDependency(dep);
113 declaration.updated = true;
114 }
115 const dep = new ConstDependency(name, expr.range);
116 dep.loc = expr.loc;
117 parser.state.module.addPresentationalDependency(dep);
118 return true;
119 });
120 };
121
122 normalModuleFactory.hooks.parser
123 .for("javascript/auto")
124 .tap("CompatibilityPlugin", nestedWebpackRequireHandler);
125 normalModuleFactory.hooks.parser
126 .for("javascript/dynamic")
127 .tap("CompatibilityPlugin", nestedWebpackRequireHandler);
128 normalModuleFactory.hooks.parser
129 .for("javascript/esm")
130 .tap("CompatibilityPlugin", nestedWebpackRequireHandler);
131 }
132 );
133 }
134}
135module.exports = CompatibilityPlugin;