77
88const {
99 JAVASCRIPT_MODULE_TYPE_AUTO ,
10- JAVASCRIPT_MODULE_TYPE_DYNAMIC
10+ JAVASCRIPT_MODULE_TYPE_DYNAMIC ,
11+ JAVASCRIPT_MODULE_TYPE_ESM
1112} = require ( "./ModuleTypeConstants" ) ;
1213const NodeStuffInWebError = require ( "./NodeStuffInWebError" ) ;
1314const RuntimeGlobals = require ( "./RuntimeGlobals" ) ;
@@ -16,7 +17,7 @@ const ConstDependency = require("./dependencies/ConstDependency");
1617const ExternalModuleDependency = require ( "./dependencies/ExternalModuleDependency" ) ;
1718const {
1819 evaluateToString,
19- expressionIsUnsupported
20+ toConstantDependency
2021} = require ( "./javascript/JavascriptParserHelpers" ) ;
2122const { relative } = require ( "./util/fs" ) ;
2223const { parseResource } = require ( "./util/identifier" ) ;
@@ -61,7 +62,7 @@ class NodeStuffPlugin {
6162 * @param {JavascriptParserOptions } parserOptions options
6263 * @returns {void }
6364 */
64- const handler = ( parser , parserOptions ) => {
65+ const globalHandler = ( parser , parserOptions ) => {
6566 if ( parserOptions . node === false ) return ;
6667
6768 let localOptions = options ;
@@ -90,12 +91,12 @@ class NodeStuffPlugin {
9091 } ;
9192
9293 const withWarning = localOptions . global === "warn" ;
94+
9395 parser . hooks . expression . for ( "global" ) . tap ( PLUGIN_NAME , ( expr ) => {
9496 const dep = getGlobalDep ( expr ) ;
9597 dep . loc = /** @type {DependencyLocation } */ ( expr . loc ) ;
9698 parser . state . module . addPresentationalDependency ( dep ) ;
9799
98- // TODO webpack 6 remove
99100 if ( withWarning ) {
100101 parser . state . module . addWarning (
101102 new NodeStuffInWebError (
@@ -106,29 +107,56 @@ class NodeStuffPlugin {
106107 ) ;
107108 }
108109 } ) ;
110+
109111 parser . hooks . rename . for ( "global" ) . tap ( PLUGIN_NAME , ( expr ) => {
110112 const dep = getGlobalDep ( expr ) ;
111113 dep . loc = /** @type {DependencyLocation } */ ( expr . loc ) ;
112114 parser . state . module . addPresentationalDependency ( dep ) ;
113115 return false ;
114116 } ) ;
115117 }
118+ } ;
119+
120+ /**
121+ * @param {JavascriptParser } parser the parser
122+ * @param {JavascriptParserOptions } parserOptions options
123+ * @param {{ dirname: string, filename: string } } identifiers options
124+ * @returns {void }
125+ */
126+ const dirnameAndFilenameHandler = (
127+ parser ,
128+ parserOptions ,
129+ { dirname, filename }
130+ ) => {
131+ if ( parserOptions . node === false ) return ;
132+
133+ let localOptions = options ;
134+
135+ if ( parserOptions . node ) {
136+ localOptions = { ...localOptions , ...parserOptions . node } ;
137+ }
116138
117139 /**
118140 * @param {string } expressionName expression name
119141 * @param {(module: NormalModule) => string } fn function
142+ * @param {string } identifier identifier
120143 * @param {string= } warning warning
121144 * @returns {void }
122145 */
123- const setModuleConstant = ( expressionName , fn , warning ) => {
146+ const setModuleConstant = (
147+ expressionName ,
148+ fn ,
149+ identifier ,
150+ warning
151+ ) => {
124152 parser . hooks . expression
125153 . for ( expressionName )
126154 . tap ( PLUGIN_NAME , ( expr ) => {
127155 const dep = new CachedConstDependency (
128156 JSON . stringify ( fn ( parser . state . module ) ) ,
129157 /** @type {Range } */
130158 ( expr . range ) ,
131- expressionName
159+ identifier
132160 ) ;
133161 dep . loc = /** @type {DependencyLocation } */ ( expr . loc ) ;
134162 parser . state . module . addPresentationalDependency ( dep ) ;
@@ -147,19 +175,31 @@ class NodeStuffPlugin {
147175 /**
148176 * @param {string } expressionName expression name
149177 * @param {(value: string) => string } fn function
178+ * @param {"dirname" | "filename" } property property
150179 * @returns {void }
151180 */
152- const setUrlModuleConstant = ( expressionName , fn ) => {
181+ const setUrlModuleConstant = ( expressionName , fn , property ) => {
153182 parser . hooks . expression
154183 . for ( expressionName )
155184 . tap ( PLUGIN_NAME , ( expr ) => {
156- const dep = compilation . outputOptions . environment
157- . importMetaDirnameAndFilename
185+ const { importMetaName, environment, module } =
186+ compilation . outputOptions ;
187+
188+ if (
189+ module &&
190+ importMetaName === "import.meta" &&
191+ expressionName . startsWith ( "import.meta" ) &&
192+ environment . importMetaDirnameAndFilename
193+ ) {
194+ return true ;
195+ }
196+
197+ const dep = environment . importMetaDirnameAndFilename
158198 ? new CachedConstDependency (
159- `${ compilation . outputOptions . importMetaName } .${ expressionName . slice ( 2 ) } ` ,
199+ `${ compilation . outputOptions . importMetaName } .${ property } ` ,
160200 /** @type {Range } */
161201 ( expr . range ) ,
162- expressionName
202+ `__webpack_ ${ property } __`
163203 )
164204 : new ExternalModuleDependency (
165205 "url" ,
@@ -172,7 +212,7 @@ class NodeStuffPlugin {
172212 undefined ,
173213 fn ( "__webpack_fileURLToPath__" ) ,
174214 /** @type {Range } */ ( expr . range ) ,
175- expressionName
215+ `__webpack_ ${ property } __`
176216 ) ;
177217 dep . loc = /** @type {DependencyLocation } */ ( expr . loc ) ;
178218 parser . state . module . addPresentationalDependency ( dep ) ;
@@ -184,41 +224,80 @@ class NodeStuffPlugin {
184224 /**
185225 * @param {string } expressionName expression name
186226 * @param {string } value value
227+ * @param {string } identifier identifier
187228 * @param {string= } warning warning
188229 * @returns {void }
189230 */
190- const setConstant = ( expressionName , value , warning ) =>
191- setModuleConstant ( expressionName , ( ) => value , warning ) ;
231+ const setConstant = ( expressionName , value , identifier , warning ) =>
232+ setModuleConstant ( expressionName , ( ) => value , identifier , warning ) ;
192233
193234 const context = compiler . context ;
235+
236+ // Keep `import.meta.filename` in code
237+ if (
238+ localOptions . __filename === false &&
239+ filename === "import.meta.filename"
240+ ) {
241+ parser . hooks . expression
242+ . for ( filename )
243+ . tap ( PLUGIN_NAME , toConstantDependency ( parser , filename ) ) ;
244+ }
245+
194246 if ( localOptions . __filename ) {
195247 switch ( localOptions . __filename ) {
196248 case "mock" :
197- setConstant ( "__filename" , "/index.js" ) ;
249+ setConstant ( filename , "/index.js" , "__webpack_filename__ ") ;
198250 break ;
199251 case "warn-mock" :
200252 setConstant (
201- "__filename" ,
253+ filename ,
202254 "/index.js" ,
255+ "__webpack_filename__" ,
203256 "__filename is a Node.js feature and isn't available in browsers."
204257 ) ;
205258 break ;
206259 case "node-module" : {
207260 const importMetaName = compilation . outputOptions . importMetaName ;
208261
209262 setUrlModuleConstant (
210- "__filename" ,
211- ( functionName ) => `${ functionName } (${ importMetaName } .url)`
263+ filename ,
264+ ( functionName ) => `${ functionName } (${ importMetaName } .url)` ,
265+ "filename"
212266 ) ;
213267 break ;
214268 }
269+ case "eval-only" :
270+ // Keep `import.meta.filename` in the source code for the ES module output
271+ if ( compilation . outputOptions . module ) {
272+ const { importMetaName } = compilation . outputOptions ;
273+
274+ parser . hooks . expression
275+ . for ( filename )
276+ . tap (
277+ PLUGIN_NAME ,
278+ toConstantDependency ( parser , `${ importMetaName } .filename` )
279+ ) ;
280+ }
281+ // Replace `import.meta.filename` with `__filename` for the non-ES module output
282+ else if ( filename === "import.meta.filename" ) {
283+ parser . hooks . expression
284+ . for ( filename )
285+ . tap (
286+ PLUGIN_NAME ,
287+ toConstantDependency ( parser , "__filename" )
288+ ) ;
289+ }
290+ break ;
215291 case true :
216- setModuleConstant ( "__filename" , ( module ) =>
217- relative (
218- /** @type {InputFileSystem } */ ( compiler . inputFileSystem ) ,
219- context ,
220- module . resource
221- )
292+ setModuleConstant (
293+ filename ,
294+ ( module ) =>
295+ relative (
296+ /** @type {InputFileSystem } */ ( compiler . inputFileSystem ) ,
297+ context ,
298+ module . resource
299+ ) ,
300+ "__webpack_filename__"
222301 ) ;
223302 break ;
224303 }
@@ -231,41 +310,79 @@ class NodeStuffPlugin {
231310 return evaluateToString ( resource . path ) ( expr ) ;
232311 } ) ;
233312 }
313+
314+ // Keep `import.meta.dirname` in code
315+ if (
316+ localOptions . __dirname === false &&
317+ dirname === "import.meta.dirname"
318+ ) {
319+ parser . hooks . expression
320+ . for ( dirname )
321+ . tap ( PLUGIN_NAME , toConstantDependency ( parser , dirname ) ) ;
322+ }
323+
234324 if ( localOptions . __dirname ) {
235325 switch ( localOptions . __dirname ) {
236326 case "mock" :
237- setConstant ( "__dirname ", "/ " ) ;
327+ setConstant ( dirname , "/ ", "__webpack_dirname__ " ) ;
238328 break ;
239329 case "warn-mock" :
240330 setConstant (
241- "__dirname" ,
331+ dirname ,
242332 "/" ,
333+ "__webpack_dirname__" ,
243334 "__dirname is a Node.js feature and isn't available in browsers."
244335 ) ;
245336 break ;
246337 case "node-module" : {
247338 const importMetaName = compilation . outputOptions . importMetaName ;
248339
249340 setUrlModuleConstant (
250- "__dirname" ,
341+ dirname ,
251342 ( functionName ) =>
252- `${ functionName } (${ importMetaName } .url + "/..").slice(0, -1)`
343+ `${ functionName } (${ importMetaName } .url.replace(/\\/(?:[^\\/]*)$/, ""))` ,
344+ "dirname"
253345 ) ;
254346 break ;
255347 }
348+ case "eval-only" :
349+ // Keep `import.meta.dirname` in the source code for the ES module output and replace `__dirname` on `import.meta.dirname`
350+ if ( compilation . outputOptions . module ) {
351+ const { importMetaName } = compilation . outputOptions ;
352+
353+ parser . hooks . expression
354+ . for ( dirname )
355+ . tap (
356+ PLUGIN_NAME ,
357+ toConstantDependency ( parser , `${ importMetaName } .dirname` )
358+ ) ;
359+ }
360+ // Replace `import.meta.dirname` with `__dirname` for the non-ES module output
361+ else if ( dirname === "import.meta.dirname" ) {
362+ parser . hooks . expression
363+ . for ( dirname )
364+ . tap (
365+ PLUGIN_NAME ,
366+ toConstantDependency ( parser , "__dirname" )
367+ ) ;
368+ }
369+ break ;
256370 case true :
257- setModuleConstant ( "__dirname" , ( module ) =>
258- relative (
259- /** @type {InputFileSystem } */ ( compiler . inputFileSystem ) ,
260- context ,
261- /** @type {string } */ ( module . context )
262- )
371+ setModuleConstant (
372+ dirname ,
373+ ( module ) =>
374+ relative (
375+ /** @type {InputFileSystem } */ ( compiler . inputFileSystem ) ,
376+ context ,
377+ /** @type {string } */ ( module . context )
378+ ) ,
379+ "__webpack_dirname__"
263380 ) ;
264381 break ;
265382 }
266383
267384 parser . hooks . evaluateIdentifier
268- . for ( "__dirname" )
385+ . for ( dirname )
269386 . tap ( PLUGIN_NAME , ( expr ) => {
270387 if ( ! parser . state . module ) return ;
271388 return evaluateToString (
@@ -274,23 +391,39 @@ class NodeStuffPlugin {
274391 ) ( expr ) ;
275392 } ) ;
276393 }
277- parser . hooks . expression
278- . for ( "require.extensions" )
279- . tap (
280- PLUGIN_NAME ,
281- expressionIsUnsupported (
282- parser ,
283- "require.extensions is not supported by webpack. Use a loader instead."
284- )
285- ) ;
286394 } ;
287395
288396 normalModuleFactory . hooks . parser
289397 . for ( JAVASCRIPT_MODULE_TYPE_AUTO )
290- . tap ( PLUGIN_NAME , handler ) ;
398+ . tap ( PLUGIN_NAME , ( parser , parserOptions ) => {
399+ globalHandler ( parser , parserOptions ) ;
400+ dirnameAndFilenameHandler ( parser , parserOptions , {
401+ dirname : "__dirname" ,
402+ filename : "__filename"
403+ } ) ;
404+ dirnameAndFilenameHandler ( parser , parserOptions , {
405+ dirname : "import.meta.dirname" ,
406+ filename : "import.meta.filename"
407+ } ) ;
408+ } ) ;
291409 normalModuleFactory . hooks . parser
292410 . for ( JAVASCRIPT_MODULE_TYPE_DYNAMIC )
293- . tap ( PLUGIN_NAME , handler ) ;
411+ . tap ( PLUGIN_NAME , ( parser , parserOptions ) => {
412+ globalHandler ( parser , parserOptions ) ;
413+ dirnameAndFilenameHandler ( parser , parserOptions , {
414+ dirname : "__dirname" ,
415+ filename : "__filename"
416+ } ) ;
417+ } ) ;
418+ normalModuleFactory . hooks . parser
419+ . for ( JAVASCRIPT_MODULE_TYPE_ESM )
420+ . tap ( PLUGIN_NAME , ( parser , parserOptions ) => {
421+ globalHandler ( parser , parserOptions ) ;
422+ dirnameAndFilenameHandler ( parser , parserOptions , {
423+ dirname : "import.meta.dirname" ,
424+ filename : "import.meta.filename"
425+ } ) ;
426+ } ) ;
294427 }
295428 ) ;
296429 }
0 commit comments