UNPKG

5.4 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 NodeStuffInWebError = require("./NodeStuffInWebError");
9const RuntimeGlobals = require("./RuntimeGlobals");
10const CachedConstDependency = require("./dependencies/CachedConstDependency");
11const ConstDependency = require("./dependencies/ConstDependency");
12const {
13 evaluateToString,
14 expressionIsUnsupported
15} = require("./javascript/JavascriptParserHelpers");
16const { relative } = require("./util/fs");
17const { parseResource } = require("./util/identifier");
18
19/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
20/** @typedef {import("./Compiler")} Compiler */
21/** @typedef {import("./Dependency")} Dependency */
22/** @typedef {import("./DependencyTemplates")} DependencyTemplates */
23/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
24
25class NodeStuffPlugin {
26 constructor(options) {
27 this.options = options;
28 }
29
30 /**
31 * Apply the plugin
32 * @param {Compiler} compiler the compiler instance
33 * @returns {void}
34 */
35 apply(compiler) {
36 const options = this.options;
37 compiler.hooks.compilation.tap(
38 "NodeStuffPlugin",
39 (compilation, { normalModuleFactory }) => {
40 const handler = (parser, parserOptions) => {
41 if (parserOptions.node === false) return;
42
43 let localOptions = options;
44 if (parserOptions.node) {
45 localOptions = { ...localOptions, ...parserOptions.node };
46 }
47
48 if (localOptions.global !== false) {
49 const withWarning = localOptions.global === "warn";
50 parser.hooks.expression
51 .for("global")
52 .tap("NodeStuffPlugin", expr => {
53 const dep = new ConstDependency(
54 RuntimeGlobals.global,
55 expr.range,
56 [RuntimeGlobals.global]
57 );
58 dep.loc = expr.loc;
59 parser.state.module.addPresentationalDependency(dep);
60
61 // TODO webpack 6 remove
62 if (withWarning) {
63 parser.state.module.addWarning(
64 new NodeStuffInWebError(
65 dep.loc,
66 "global",
67 "The global namespace object is Node.js feature and doesn't present in browser."
68 )
69 );
70 }
71 });
72 parser.hooks.rename.for("global").tap("NodeStuffPlugin", expr => {
73 const dep = new ConstDependency(
74 RuntimeGlobals.global,
75 expr.range,
76 [RuntimeGlobals.global]
77 );
78 dep.loc = expr.loc;
79 parser.state.module.addPresentationalDependency(dep);
80 return false;
81 });
82 }
83
84 const setModuleConstant = (expressionName, fn, warning) => {
85 parser.hooks.expression
86 .for(expressionName)
87 .tap("NodeStuffPlugin", expr => {
88 const dep = new CachedConstDependency(
89 JSON.stringify(fn(parser.state.module)),
90 expr.range,
91 expressionName
92 );
93 dep.loc = expr.loc;
94 parser.state.module.addPresentationalDependency(dep);
95
96 // TODO webpack 6 remove
97 if (warning) {
98 parser.state.module.addWarning(
99 new NodeStuffInWebError(dep.loc, expressionName, warning)
100 );
101 }
102
103 return true;
104 });
105 };
106
107 const setConstant = (expressionName, value, warning) =>
108 setModuleConstant(expressionName, () => value, warning);
109
110 const context = compiler.context;
111 if (localOptions.__filename) {
112 switch (localOptions.__filename) {
113 case "mock":
114 setConstant("__filename", "/index.js");
115 break;
116 case "warn-mock":
117 setConstant(
118 "__filename",
119 "/index.js",
120 "The __filename is Node.js feature and doesn't present in browser."
121 );
122 break;
123 case true:
124 setModuleConstant("__filename", module =>
125 relative(compiler.inputFileSystem, context, module.resource)
126 );
127 break;
128 }
129
130 parser.hooks.evaluateIdentifier
131 .for("__filename")
132 .tap("NodeStuffPlugin", expr => {
133 if (!parser.state.module) return;
134 const resource = parseResource(parser.state.module.resource);
135 return evaluateToString(resource.path)(expr);
136 });
137 }
138 if (localOptions.__dirname) {
139 switch (localOptions.__dirname) {
140 case "mock":
141 setConstant("__dirname", "/");
142 break;
143 case "warn-mock":
144 setConstant(
145 "__dirname",
146 "/",
147 "The __dirname is Node.js feature and doesn't present in browser."
148 );
149 break;
150 case true:
151 setModuleConstant("__dirname", module =>
152 relative(compiler.inputFileSystem, context, module.context)
153 );
154 break;
155 }
156
157 parser.hooks.evaluateIdentifier
158 .for("__dirname")
159 .tap("NodeStuffPlugin", expr => {
160 if (!parser.state.module) return;
161 return evaluateToString(parser.state.module.context)(expr);
162 });
163 }
164 parser.hooks.expression
165 .for("require.extensions")
166 .tap(
167 "NodeStuffPlugin",
168 expressionIsUnsupported(
169 parser,
170 "require.extensions is not supported by webpack. Use a loader instead."
171 )
172 );
173 };
174
175 normalModuleFactory.hooks.parser
176 .for("javascript/auto")
177 .tap("NodeStuffPlugin", handler);
178 normalModuleFactory.hooks.parser
179 .for("javascript/dynamic")
180 .tap("NodeStuffPlugin", handler);
181 }
182 );
183 }
184}
185
186module.exports = NodeStuffPlugin;