UNPKG

5.07 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 }
73
74 const setModuleConstant = (expressionName, fn, warning) => {
75 parser.hooks.expression
76 .for(expressionName)
77 .tap("NodeStuffPlugin", expr => {
78 const dep = new CachedConstDependency(
79 JSON.stringify(fn(parser.state.module)),
80 expr.range,
81 expressionName
82 );
83 dep.loc = expr.loc;
84 parser.state.module.addPresentationalDependency(dep);
85
86 // TODO webpack 6 remove
87 if (warning) {
88 parser.state.module.addWarning(
89 new NodeStuffInWebError(dep.loc, expressionName, warning)
90 );
91 }
92
93 return true;
94 });
95 };
96
97 const setConstant = (expressionName, value, warning) =>
98 setModuleConstant(expressionName, () => value, warning);
99
100 const context = compiler.context;
101 if (localOptions.__filename) {
102 switch (localOptions.__filename) {
103 case "mock":
104 setConstant("__filename", "/index.js");
105 break;
106 case "warn-mock":
107 setConstant(
108 "__filename",
109 "/index.js",
110 "The __filename is Node.js feature and doesn't present in browser."
111 );
112 break;
113 case true:
114 setModuleConstant("__filename", module =>
115 relative(compiler.inputFileSystem, context, module.resource)
116 );
117 break;
118 }
119
120 parser.hooks.evaluateIdentifier
121 .for("__filename")
122 .tap("NodeStuffPlugin", expr => {
123 if (!parser.state.module) return;
124 const resource = parseResource(parser.state.module.resource);
125 return evaluateToString(resource.path)(expr);
126 });
127 }
128 if (localOptions.__dirname) {
129 switch (localOptions.__dirname) {
130 case "mock":
131 setConstant("__dirname", "/");
132 break;
133 case "warn-mock":
134 setConstant(
135 "__dirname",
136 "/",
137 "The __dirname is Node.js feature and doesn't present in browser."
138 );
139 break;
140 case true:
141 setModuleConstant("__dirname", module =>
142 relative(compiler.inputFileSystem, context, module.context)
143 );
144 break;
145 }
146
147 parser.hooks.evaluateIdentifier
148 .for("__dirname")
149 .tap("NodeStuffPlugin", expr => {
150 if (!parser.state.module) return;
151 return evaluateToString(parser.state.module.context)(expr);
152 });
153 }
154 parser.hooks.expression
155 .for("require.extensions")
156 .tap(
157 "NodeStuffPlugin",
158 expressionIsUnsupported(
159 parser,
160 "require.extensions is not supported by webpack. Use a loader instead."
161 )
162 );
163 };
164
165 normalModuleFactory.hooks.parser
166 .for("javascript/auto")
167 .tap("NodeStuffPlugin", handler);
168 normalModuleFactory.hooks.parser
169 .for("javascript/dynamic")
170 .tap("NodeStuffPlugin", handler);
171 }
172 );
173 }
174}
175
176module.exports = NodeStuffPlugin;