UNPKG

6.39 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Ivan Kopeykin @vankop
4*/
5
6"use strict";
7
8const { pathToFileURL } = require("url");
9const ModuleDependencyWarning = require("../ModuleDependencyWarning");
10const Template = require("../Template");
11const BasicEvaluatedExpression = require("../javascript/BasicEvaluatedExpression");
12const {
13 evaluateToIdentifier,
14 toConstantDependency,
15 evaluateToString,
16 evaluateToNumber
17} = require("../javascript/JavascriptParserHelpers");
18const memoize = require("../util/memoize");
19const propertyAccess = require("../util/propertyAccess");
20const ConstDependency = require("./ConstDependency");
21
22/** @typedef {import("estree").MemberExpression} MemberExpression */
23/** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
24/** @typedef {import("../Compiler")} Compiler */
25/** @typedef {import("../NormalModule")} NormalModule */
26/** @typedef {import("../javascript/JavascriptParser")} Parser */
27
28const getCriticalDependencyWarning = memoize(() =>
29 require("./CriticalDependencyWarning")
30);
31
32class ImportMetaPlugin {
33 /**
34 * @param {Compiler} compiler compiler
35 */
36 apply(compiler) {
37 compiler.hooks.compilation.tap(
38 "ImportMetaPlugin",
39 (compilation, { normalModuleFactory }) => {
40 /**
41 * @param {NormalModule} module module
42 * @returns {string} file url
43 */
44 const getUrl = module => {
45 return pathToFileURL(module.resource).toString();
46 };
47 /**
48 * @param {Parser} parser parser parser
49 * @param {JavascriptParserOptions} parserOptions parserOptions
50 * @returns {void}
51 */
52 const parserHandler = (parser, { importMeta }) => {
53 if (importMeta === false) {
54 const { importMetaName } = compilation.outputOptions;
55 if (importMetaName === "import.meta") return;
56
57 parser.hooks.expression
58 .for("import.meta")
59 .tap("ImportMetaPlugin", metaProperty => {
60 const dep = new ConstDependency(
61 importMetaName,
62 metaProperty.range
63 );
64 dep.loc = metaProperty.loc;
65 parser.state.module.addPresentationalDependency(dep);
66 return true;
67 });
68 return;
69 }
70
71 /// import.meta direct ///
72 parser.hooks.typeof
73 .for("import.meta")
74 .tap(
75 "ImportMetaPlugin",
76 toConstantDependency(parser, JSON.stringify("object"))
77 );
78 parser.hooks.expression
79 .for("import.meta")
80 .tap("ImportMetaPlugin", metaProperty => {
81 const CriticalDependencyWarning = getCriticalDependencyWarning();
82 parser.state.module.addWarning(
83 new ModuleDependencyWarning(
84 parser.state.module,
85 new CriticalDependencyWarning(
86 "Accessing import.meta directly is unsupported (only property access is supported)"
87 ),
88 metaProperty.loc
89 )
90 );
91 const dep = new ConstDependency(
92 `${parser.isAsiPosition(metaProperty.range[0]) ? ";" : ""}({})`,
93 metaProperty.range
94 );
95 dep.loc = metaProperty.loc;
96 parser.state.module.addPresentationalDependency(dep);
97 return true;
98 });
99 parser.hooks.evaluateTypeof
100 .for("import.meta")
101 .tap("ImportMetaPlugin", evaluateToString("object"));
102 parser.hooks.evaluateIdentifier.for("import.meta").tap(
103 "ImportMetaPlugin",
104 evaluateToIdentifier("import.meta", "import.meta", () => [], true)
105 );
106
107 /// import.meta.url ///
108 parser.hooks.typeof
109 .for("import.meta.url")
110 .tap(
111 "ImportMetaPlugin",
112 toConstantDependency(parser, JSON.stringify("string"))
113 );
114 parser.hooks.expression
115 .for("import.meta.url")
116 .tap("ImportMetaPlugin", expr => {
117 const dep = new ConstDependency(
118 JSON.stringify(getUrl(parser.state.module)),
119 expr.range
120 );
121 dep.loc = expr.loc;
122 parser.state.module.addPresentationalDependency(dep);
123 return true;
124 });
125 parser.hooks.evaluateTypeof
126 .for("import.meta.url")
127 .tap("ImportMetaPlugin", evaluateToString("string"));
128 parser.hooks.evaluateIdentifier
129 .for("import.meta.url")
130 .tap("ImportMetaPlugin", expr => {
131 return new BasicEvaluatedExpression()
132 .setString(getUrl(parser.state.module))
133 .setRange(expr.range);
134 });
135
136 /// import.meta.webpack ///
137 const webpackVersion = parseInt(
138 require("../../package.json").version,
139 10
140 );
141 parser.hooks.typeof
142 .for("import.meta.webpack")
143 .tap(
144 "ImportMetaPlugin",
145 toConstantDependency(parser, JSON.stringify("number"))
146 );
147 parser.hooks.expression
148 .for("import.meta.webpack")
149 .tap(
150 "ImportMetaPlugin",
151 toConstantDependency(parser, JSON.stringify(webpackVersion))
152 );
153 parser.hooks.evaluateTypeof
154 .for("import.meta.webpack")
155 .tap("ImportMetaPlugin", evaluateToString("number"));
156 parser.hooks.evaluateIdentifier
157 .for("import.meta.webpack")
158 .tap("ImportMetaPlugin", evaluateToNumber(webpackVersion));
159
160 /// Unknown properties ///
161 parser.hooks.unhandledExpressionMemberChain
162 .for("import.meta")
163 .tap("ImportMetaPlugin", (expr, members) => {
164 const dep = new ConstDependency(
165 `${Template.toNormalComment(
166 "unsupported import.meta." + members.join(".")
167 )} undefined${propertyAccess(members, 1)}`,
168 expr.range
169 );
170 dep.loc = expr.loc;
171 parser.state.module.addPresentationalDependency(dep);
172 return true;
173 });
174 parser.hooks.evaluate
175 .for("MemberExpression")
176 .tap("ImportMetaPlugin", expression => {
177 const expr = /** @type {MemberExpression} */ (expression);
178 if (
179 expr.object.type === "MetaProperty" &&
180 expr.object.meta.name === "import" &&
181 expr.object.property.name === "meta" &&
182 expr.property.type ===
183 (expr.computed ? "Literal" : "Identifier")
184 ) {
185 return new BasicEvaluatedExpression()
186 .setUndefined()
187 .setRange(expr.range);
188 }
189 });
190 };
191
192 normalModuleFactory.hooks.parser
193 .for("javascript/auto")
194 .tap("ImportMetaPlugin", parserHandler);
195 normalModuleFactory.hooks.parser
196 .for("javascript/esm")
197 .tap("ImportMetaPlugin", parserHandler);
198 }
199 );
200 }
201}
202
203module.exports = ImportMetaPlugin;