UNPKG

4.64 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 handler = parser => {
73 // Handle nested requires
74 parser.hooks.preStatement.tap("CompatibilityPlugin", statement => {
75 if (
76 statement.type === "FunctionDeclaration" &&
77 statement.id &&
78 statement.id.name === "__webpack_require__"
79 ) {
80 const newName = `__nested_webpack_require_${statement.range[0]}__`;
81 parser.tagVariable(statement.id.name, nestedWebpackRequireTag, {
82 name: newName,
83 declaration: {
84 updated: false,
85 loc: statement.id.loc,
86 range: statement.id.range
87 }
88 });
89 return true;
90 }
91 });
92 parser.hooks.pattern
93 .for("__webpack_require__")
94 .tap("CompatibilityPlugin", pattern => {
95 const newName = `__nested_webpack_require_${pattern.range[0]}__`;
96 parser.tagVariable(pattern.name, nestedWebpackRequireTag, {
97 name: newName,
98 declaration: {
99 updated: false,
100 loc: pattern.loc,
101 range: pattern.range
102 }
103 });
104 return true;
105 });
106 parser.hooks.expression
107 .for(nestedWebpackRequireTag)
108 .tap("CompatibilityPlugin", expr => {
109 const { name, declaration } = parser.currentTagData;
110 if (!declaration.updated) {
111 const dep = new ConstDependency(name, declaration.range);
112 dep.loc = declaration.loc;
113 parser.state.module.addPresentationalDependency(dep);
114 declaration.updated = true;
115 }
116 const dep = new ConstDependency(name, expr.range);
117 dep.loc = expr.loc;
118 parser.state.module.addPresentationalDependency(dep);
119 return true;
120 });
121
122 // Handle hashbang
123 parser.hooks.program.tap(
124 "CompatibilityPlugin",
125 (program, comments) => {
126 if (comments.length === 0) return;
127 const c = comments[0];
128 if (c.type === "Line" && c.range[0] === 0) {
129 if (parser.state.source.slice(0, 2).toString() !== "#!") return;
130 // this is a hashbang comment
131 const dep = new ConstDependency("//", 0);
132 dep.loc = c.loc;
133 parser.state.module.addPresentationalDependency(dep);
134 }
135 }
136 );
137 };
138
139 normalModuleFactory.hooks.parser
140 .for("javascript/auto")
141 .tap("CompatibilityPlugin", handler);
142 normalModuleFactory.hooks.parser
143 .for("javascript/dynamic")
144 .tap("CompatibilityPlugin", handler);
145 normalModuleFactory.hooks.parser
146 .for("javascript/esm")
147 .tap("CompatibilityPlugin", handler);
148 }
149 );
150 }
151}
152module.exports = CompatibilityPlugin;