1 |
|
2 |
|
3 |
|
4 |
|
5 | "use strict";
|
6 |
|
7 | const path = require("path");
|
8 | const ParserHelpers = require("./ParserHelpers");
|
9 | const ConstDependency = require("./dependencies/ConstDependency");
|
10 |
|
11 | const NullFactory = require("./NullFactory");
|
12 |
|
13 | class NodeStuffPlugin {
|
14 | constructor(options) {
|
15 | this.options = options;
|
16 | }
|
17 |
|
18 | apply(compiler) {
|
19 | const options = this.options;
|
20 | compiler.hooks.compilation.tap(
|
21 | "NodeStuffPlugin",
|
22 | (compilation, { normalModuleFactory }) => {
|
23 | compilation.dependencyFactories.set(ConstDependency, new NullFactory());
|
24 | compilation.dependencyTemplates.set(
|
25 | ConstDependency,
|
26 | new ConstDependency.Template()
|
27 | );
|
28 |
|
29 | const handler = (parser, parserOptions) => {
|
30 | if (parserOptions.node === false) return;
|
31 |
|
32 | let localOptions = options;
|
33 | if (parserOptions.node) {
|
34 | localOptions = Object.assign({}, localOptions, parserOptions.node);
|
35 | }
|
36 |
|
37 | const setConstant = (expressionName, value) => {
|
38 | parser.hooks.expression
|
39 | .for(expressionName)
|
40 | .tap("NodeStuffPlugin", () => {
|
41 | parser.state.current.addVariable(
|
42 | expressionName,
|
43 | JSON.stringify(value)
|
44 | );
|
45 | return true;
|
46 | });
|
47 | };
|
48 |
|
49 | const setModuleConstant = (expressionName, fn) => {
|
50 | parser.hooks.expression
|
51 | .for(expressionName)
|
52 | .tap("NodeStuffPlugin", () => {
|
53 | parser.state.current.addVariable(
|
54 | expressionName,
|
55 | JSON.stringify(fn(parser.state.module))
|
56 | );
|
57 | return true;
|
58 | });
|
59 | };
|
60 | const context = compiler.context;
|
61 | if (localOptions.__filename === "mock") {
|
62 | setConstant("__filename", "/index.js");
|
63 | } else if (localOptions.__filename) {
|
64 | setModuleConstant("__filename", module =>
|
65 | path.relative(context, module.resource)
|
66 | );
|
67 | }
|
68 | parser.hooks.evaluateIdentifier
|
69 | .for("__filename")
|
70 | .tap("NodeStuffPlugin", expr => {
|
71 | if (!parser.state.module) return;
|
72 | const resource = parser.state.module.resource;
|
73 | const i = resource.indexOf("?");
|
74 | return ParserHelpers.evaluateToString(
|
75 | i < 0 ? resource : resource.substr(0, i)
|
76 | )(expr);
|
77 | });
|
78 | if (localOptions.__dirname === "mock") {
|
79 | setConstant("__dirname", "/");
|
80 | } else if (localOptions.__dirname) {
|
81 | setModuleConstant("__dirname", module =>
|
82 | path.relative(context, module.context)
|
83 | );
|
84 | }
|
85 | parser.hooks.evaluateIdentifier
|
86 | .for("__dirname")
|
87 | .tap("NodeStuffPlugin", expr => {
|
88 | if (!parser.state.module) return;
|
89 | return ParserHelpers.evaluateToString(
|
90 | parser.state.module.context
|
91 | )(expr);
|
92 | });
|
93 | parser.hooks.expression
|
94 | .for("require.main")
|
95 | .tap(
|
96 | "NodeStuffPlugin",
|
97 | ParserHelpers.toConstantDependencyWithWebpackRequire(
|
98 | parser,
|
99 | "__webpack_require__.c[__webpack_require__.s]"
|
100 | )
|
101 | );
|
102 | parser.hooks.expression
|
103 | .for("require.extensions")
|
104 | .tap(
|
105 | "NodeStuffPlugin",
|
106 | ParserHelpers.expressionIsUnsupported(
|
107 | parser,
|
108 | "require.extensions is not supported by webpack. Use a loader instead."
|
109 | )
|
110 | );
|
111 | parser.hooks.expression
|
112 | .for("require.main.require")
|
113 | .tap(
|
114 | "NodeStuffPlugin",
|
115 | ParserHelpers.expressionIsUnsupported(
|
116 | parser,
|
117 | "require.main.require is not supported by webpack."
|
118 | )
|
119 | );
|
120 | parser.hooks.expression
|
121 | .for("module.parent.require")
|
122 | .tap(
|
123 | "NodeStuffPlugin",
|
124 | ParserHelpers.expressionIsUnsupported(
|
125 | parser,
|
126 | "module.parent.require is not supported by webpack."
|
127 | )
|
128 | );
|
129 | parser.hooks.expression
|
130 | .for("module.loaded")
|
131 | .tap("NodeStuffPlugin", expr => {
|
132 | parser.state.module.buildMeta.moduleConcatenationBailout =
|
133 | "module.loaded";
|
134 | return ParserHelpers.toConstantDependency(parser, "module.l")(
|
135 | expr
|
136 | );
|
137 | });
|
138 | parser.hooks.expression
|
139 | .for("module.id")
|
140 | .tap("NodeStuffPlugin", expr => {
|
141 | parser.state.module.buildMeta.moduleConcatenationBailout =
|
142 | "module.id";
|
143 | return ParserHelpers.toConstantDependency(parser, "module.i")(
|
144 | expr
|
145 | );
|
146 | });
|
147 | parser.hooks.expression
|
148 | .for("module.exports")
|
149 | .tap("NodeStuffPlugin", () => {
|
150 | const module = parser.state.module;
|
151 | const isHarmony =
|
152 | module.buildMeta && module.buildMeta.exportsType;
|
153 | if (!isHarmony) return true;
|
154 | });
|
155 | parser.hooks.evaluateIdentifier
|
156 | .for("module.hot")
|
157 | .tap(
|
158 | "NodeStuffPlugin",
|
159 | ParserHelpers.evaluateToIdentifier("module.hot", false)
|
160 | );
|
161 | parser.hooks.expression.for("module").tap("NodeStuffPlugin", () => {
|
162 | const module = parser.state.module;
|
163 | const isHarmony = module.buildMeta && module.buildMeta.exportsType;
|
164 | let moduleJsPath = path.join(
|
165 | __dirname,
|
166 | "..",
|
167 | "buildin",
|
168 | isHarmony ? "harmony-module.js" : "module.js"
|
169 | );
|
170 | if (module.context) {
|
171 | moduleJsPath = path.relative(
|
172 | parser.state.module.context,
|
173 | moduleJsPath
|
174 | );
|
175 | if (!/^[A-Z]:/i.test(moduleJsPath)) {
|
176 | moduleJsPath = `./${moduleJsPath.replace(/\\/g, "/")}`;
|
177 | }
|
178 | }
|
179 | return ParserHelpers.addParsedVariableToModule(
|
180 | parser,
|
181 | "module",
|
182 | `require(${JSON.stringify(moduleJsPath)})(module)`
|
183 | );
|
184 | });
|
185 | };
|
186 |
|
187 | normalModuleFactory.hooks.parser
|
188 | .for("javascript/auto")
|
189 | .tap("NodeStuffPlugin", handler);
|
190 | normalModuleFactory.hooks.parser
|
191 | .for("javascript/dynamic")
|
192 | .tap("NodeStuffPlugin", handler);
|
193 | }
|
194 | );
|
195 | }
|
196 | }
|
197 | module.exports = NodeStuffPlugin;
|