Skip to content

Commit 2764e91

Browse files
committed
import.meta.webpackContext
1 parent 4abf353 commit 2764e91

File tree

7 files changed

+181
-19
lines changed

7 files changed

+181
-19
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
MIT License http://www.opensource.org/licenses/mit-license.php
3+
Author Ivan Kopeykin @vankop
4+
*/
5+
6+
"use strict";
7+
8+
const makeSerializable = require("../util/makeSerializable");
9+
const ContextDependency = require("./ContextDependency");
10+
const ModuleDependencyTemplateAsRequireId = require("./ModuleDependencyTemplateAsRequireId");
11+
12+
class ImportMetaContextDependency extends ContextDependency {
13+
constructor(options, range) {
14+
super(options);
15+
16+
this.range = range;
17+
}
18+
19+
get category() {
20+
return "esm";
21+
}
22+
23+
get type() {
24+
return "import.meta.webpackContext";
25+
}
26+
}
27+
28+
makeSerializable(
29+
ImportMetaContextDependency,
30+
"webpack/lib/dependencies/ImportMetaContextDependency"
31+
);
32+
33+
ImportMetaContextDependency.Template = ModuleDependencyTemplateAsRequireId;
34+
35+
module.exports = ImportMetaContextDependency;
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
MIT License http://www.opensource.org/licenses/mit-license.php
3+
Author Ivan Kopeykin @vankop
4+
*/
5+
6+
"use strict";
7+
8+
const {
9+
evaluateToIdentifier
10+
} = require("../javascript/JavascriptParserHelpers");
11+
const ImportMetaContextDependency = require("./ImportMetaContextDependency");
12+
13+
/** @typedef {import("estree").Expression} ExpressionNode */
14+
/** @typedef {import("estree").ObjectExpression} ObjectExpressionNode */
15+
/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
16+
17+
/**
18+
* @param {JavascriptParser} parser parser
19+
* @param {ObjectExpressionNode} optionsNode node
20+
* @returns {{mode: string, recursive: boolean, regExp: RegExp}} options
21+
*/
22+
function getOptions(parser, optionsNode) {
23+
let regExp = /^\.\/.*$/;
24+
let recursive = true;
25+
let mode = "sync";
26+
if (optionsNode) {
27+
for (const prop of optionsNode.properties) {
28+
if (prop.type !== "Property" || prop.key.type !== "Identifier") return;
29+
switch (prop.key.name) {
30+
case "regExp": {
31+
const regExpExpr = parser.evaluateExpression(
32+
/** @type {ExpressionNode} */ (prop.value)
33+
);
34+
if (!regExpExpr.isRegExp()) return;
35+
regExp = regExpExpr.regExp;
36+
break;
37+
}
38+
case "mode": {
39+
const modeExpr = parser.evaluateExpression(
40+
/** @type {ExpressionNode} */ (prop.value)
41+
);
42+
if (!modeExpr.isString()) return;
43+
mode = modeExpr.string;
44+
break;
45+
}
46+
case "recursive": {
47+
const recursiveExpr = parser.evaluateExpression(
48+
/** @type {ExpressionNode} */ (prop.value)
49+
);
50+
if (!recursiveExpr.isBoolean()) return;
51+
recursive = recursiveExpr.bool;
52+
}
53+
}
54+
}
55+
}
56+
57+
return { recursive, regExp, mode };
58+
}
59+
60+
module.exports = class ImportMetaContextDependencyParserPlugin {
61+
apply(parser) {
62+
parser.hooks.evaluateIdentifier
63+
.for("import.meta.webpackContext")
64+
.tap("HotModuleReplacementPlugin", expr => {
65+
return evaluateToIdentifier(
66+
"import.meta.webpackContext",
67+
"import.meta",
68+
() => ["webpackContext"],
69+
true
70+
)(expr);
71+
});
72+
parser.hooks.call
73+
.for("import.meta.webpackContext")
74+
.tap("ImportMetaContextDependencyParserPlugin", expr => {
75+
if (expr.arguments.length < 1 || expr.arguments.length > 2) return;
76+
const [directoryNode, optionsNode] = expr.arguments;
77+
if (optionsNode && optionsNode.type !== "ObjectExpression") return;
78+
const requestExpr = parser.evaluateExpression(directoryNode);
79+
if (!requestExpr.isString()) return;
80+
const request = requestExpr.string;
81+
const options = getOptions(parser, optionsNode);
82+
if (!options) return;
83+
84+
const dep = new ImportMetaContextDependency(
85+
{
86+
request,
87+
...options,
88+
category: "esm"
89+
},
90+
expr.range
91+
);
92+
dep.loc = expr.loc;
93+
dep.optional = !!parser.scope.inTry;
94+
parser.state.current.addDependency(dep);
95+
return true;
96+
});
97+
}
98+
};

lib/dependencies/RequireContextDependency.js

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,6 @@ class RequireContextDependency extends ContextDependency {
1919
get type() {
2020
return "require.context";
2121
}
22-
23-
serialize(context) {
24-
const { write } = context;
25-
26-
write(this.range);
27-
28-
super.serialize(context);
29-
}
30-
31-
deserialize(context) {
32-
const { read } = context;
33-
34-
this.range = read();
35-
36-
super.deserialize(context);
37-
}
3822
}
3923

4024
makeSerializable(

lib/dependencies/RequireContextPlugin.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
const { cachedSetProperty } = require("../util/cleverMerge");
99
const ContextElementDependency = require("./ContextElementDependency");
10+
const ImportMetaContextDependency = require("./ImportMetaContextDependency");
11+
const ImportMetaContextDependencyParserPlugin = require("./ImportMetaContextDependencyParserPlugin");
1012
const RequireContextDependency = require("./RequireContextDependency");
1113
const RequireContextDependencyParserPlugin = require("./RequireContextDependencyParserPlugin");
1214

@@ -34,6 +36,14 @@ class RequireContextPlugin {
3436
RequireContextDependency,
3537
new RequireContextDependency.Template()
3638
);
39+
compilation.dependencyFactories.set(
40+
ImportMetaContextDependency,
41+
contextModuleFactory
42+
);
43+
compilation.dependencyTemplates.set(
44+
ImportMetaContextDependency,
45+
new ImportMetaContextDependency.Template()
46+
);
3747

3848
compilation.dependencyFactories.set(
3949
ContextElementDependency,
@@ -50,6 +60,22 @@ class RequireContextPlugin {
5060
new RequireContextDependencyParserPlugin().apply(parser);
5161
};
5262

63+
const handlerImportMeta = (parser, parserOptions) => {
64+
if (
65+
parserOptions.requireContext !== undefined &&
66+
!parserOptions.requireContext
67+
)
68+
return;
69+
70+
new ImportMetaContextDependencyParserPlugin().apply(parser);
71+
};
72+
73+
normalModuleFactory.hooks.parser
74+
.for("javascript/auto")
75+
.tap("RequireContextPlugin", handlerImportMeta);
76+
normalModuleFactory.hooks.parser
77+
.for("javascript/esm")
78+
.tap("RequireContextPlugin", handlerImportMeta);
5379
normalModuleFactory.hooks.parser
5480
.for("javascript/auto")
5581
.tap("RequireContextPlugin", handler);

lib/util/internalSerializables.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ module.exports = {
126126
require("../dependencies/ImportMetaHotAcceptDependency"),
127127
"dependencies/ImportMetaHotDeclineDependency": () =>
128128
require("../dependencies/ImportMetaHotDeclineDependency"),
129+
"dependencies/ImportMetaContextDependency": () =>
130+
require("../dependencies/ImportMetaContextDependency"),
129131
"dependencies/ProvidedDependency": () =>
130132
require("../dependencies/ProvidedDependency"),
131133
"dependencies/PureExpressionDependency": () =>

module.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,14 @@ interface ImportMeta {
147147
url: string;
148148
webpack: number;
149149
webpackHot: webpack.Hot;
150+
webpackContext: (
151+
request: string,
152+
options?: {
153+
recursive?: boolean;
154+
regExp?: RegExp;
155+
mode?: "sync" | "eager" | "weak" | "lazy" | "lazy-once";
156+
}
157+
) => webpack.Context;
150158
}
151159

152160
declare const __resourceQuery: string;
Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
1+
it("import.meta.webpackContext without arguments should work", function() {
2+
const contextRequire = import.meta.webpackContext("./dir");
3+
expect(contextRequire("./four")).toBe(4);
4+
});
5+
16
it("should not bundle context requires with asyncMode === 'weak'", function() {
2-
var contextRequire = require.context(".", false, /two/, "weak");
7+
const contextRequire = import.meta.webpackContext(".", {
8+
recursive: false,
9+
regExp: /two/,
10+
mode: "weak"
11+
});
312
expect(function() {
413
contextRequire("./two")
514
}).toThrowError(/not available/);
615
});
716

817
it("should find module with asyncMode === 'weak' when required elsewhere", function() {
9-
var contextRequire = require.context(".", false, /.+/, "weak");
18+
const contextRequire = require.context(".", false, /.+/, "weak");
1019
expect(contextRequire("./three")).toBe(3);
1120
require("./three"); // in a real app would be served as a separate chunk
1221
});
1322

1423
it("should find module with asyncMode === 'weak' when required elsewhere (recursive)", function() {
15-
var contextRequire = require.context(".", true, /.+/, "weak");
24+
const contextRequire = require.context(".", true, /.+/, "weak");
1625
expect(contextRequire("./dir/four")).toBe(4);
1726
require("./dir/four"); // in a real app would be served as a separate chunk
1827
});

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy