2020-06-23 05:53:13 +08:00
/ *
MIT License http : //www.opensource.org/licenses/mit-license.php
Author Ivan Kopeykin @ vankop
* /
"use strict" ;
2020-06-26 05:37:40 +08:00
const { pathToFileURL } = require ( "url" ) ;
2020-07-06 23:13:09 +08:00
const ModuleDependencyWarning = require ( "../ModuleDependencyWarning" ) ;
2023-04-01 01:56:32 +08:00
const {
JAVASCRIPT _MODULE _TYPE _AUTO ,
JAVASCRIPT _MODULE _TYPE _ESM
} = require ( "../ModuleTypeConstants" ) ;
2020-07-06 23:13:09 +08:00
const Template = require ( "../Template" ) ;
2020-06-25 03:47:43 +08:00
const BasicEvaluatedExpression = require ( "../javascript/BasicEvaluatedExpression" ) ;
2020-06-23 05:53:13 +08:00
const {
2020-06-25 03:47:43 +08:00
evaluateToIdentifier ,
2025-07-03 17:06:45 +08:00
evaluateToNumber ,
2020-07-06 23:13:09 +08:00
evaluateToString ,
2025-07-03 17:06:45 +08:00
toConstantDependency
2020-06-23 05:53:13 +08:00
} = require ( "../javascript/JavascriptParserHelpers" ) ;
2020-12-27 05:32:57 +08:00
const memoize = require ( "../util/memoize" ) ;
2020-07-06 23:13:09 +08:00
const propertyAccess = require ( "../util/propertyAccess" ) ;
2020-06-25 03:47:43 +08:00
const ConstDependency = require ( "./ConstDependency" ) ;
2020-06-23 05:53:13 +08:00
2020-07-06 23:13:09 +08:00
/** @typedef {import("estree").MemberExpression} MemberExpression */
2022-01-28 03:27:10 +08:00
/** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
2020-06-23 05:53:13 +08:00
/** @typedef {import("../Compiler")} Compiler */
2023-06-17 04:24:34 +08:00
/** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
2020-06-25 03:47:43 +08:00
/** @typedef {import("../NormalModule")} NormalModule */
2020-06-23 05:53:13 +08:00
/** @typedef {import("../javascript/JavascriptParser")} Parser */
2023-06-17 04:24:34 +08:00
/** @typedef {import("../javascript/JavascriptParser").Range} Range */
2025-09-11 08:10:10 +08:00
/** @typedef {import("../javascript/JavascriptParser").Members} Members */
2020-06-23 05:53:13 +08:00
2020-12-27 05:32:57 +08:00
const getCriticalDependencyWarning = memoize ( ( ) =>
2020-07-06 23:13:09 +08:00
require ( "./CriticalDependencyWarning" )
) ;
2023-04-01 01:56:32 +08:00
const PLUGIN _NAME = "ImportMetaPlugin" ;
2020-06-23 05:53:13 +08:00
class ImportMetaPlugin {
/ * *
* @ param { Compiler } compiler compiler
* /
apply ( compiler ) {
compiler . hooks . compilation . tap (
2023-04-01 01:56:32 +08:00
PLUGIN _NAME ,
2020-06-23 05:53:13 +08:00
( compilation , { normalModuleFactory } ) => {
2020-06-25 03:47:43 +08:00
/ * *
* @ param { NormalModule } module module
2020-06-26 20:04:18 +08:00
* @ returns { string } file url
2020-06-25 03:47:43 +08:00
* /
2025-07-17 00:13:14 +08:00
const getUrl = ( module ) => pathToFileURL ( module . resource ) . toString ( ) ;
2020-06-23 05:53:13 +08:00
/ * *
2022-01-28 03:27:10 +08:00
* @ param { Parser } parser parser parser
* @ param { JavascriptParserOptions } parserOptions parserOptions
2020-06-23 05:53:13 +08:00
* @ returns { void }
* /
2022-01-28 03:27:10 +08:00
const parserHandler = ( parser , { importMeta } ) => {
if ( importMeta === false ) {
const { importMetaName } = compilation . outputOptions ;
2022-01-28 13:59:28 +08:00
if ( importMetaName === "import.meta" ) return ;
2022-01-28 03:27:10 +08:00
parser . hooks . expression
. for ( "import.meta" )
2025-07-17 00:13:14 +08:00
. tap ( PLUGIN _NAME , ( metaProperty ) => {
2022-01-28 03:27:10 +08:00
const dep = new ConstDependency (
2023-06-17 04:24:34 +08:00
/** @type {string} */ ( importMetaName ) ,
/** @type {Range} */ ( metaProperty . range )
2022-01-28 03:27:10 +08:00
) ;
2023-06-17 04:24:34 +08:00
dep . loc = /** @type {DependencyLocation} */ ( metaProperty . loc ) ;
2022-01-28 03:27:10 +08:00
parser . state . module . addPresentationalDependency ( dep ) ;
return true ;
} ) ;
return ;
}
2022-01-25 23:08:56 +08:00
2024-07-31 12:23:44 +08:00
// import.meta direct
2024-08-02 02:36:27 +08:00
const webpackVersion = Number . parseInt (
2023-04-13 23:47:52 +08:00
require ( "../../package.json" ) . version ,
10
) ;
const importMetaUrl = ( ) =>
JSON . stringify ( getUrl ( parser . state . module ) ) ;
const importMetaWebpackVersion = ( ) => JSON . stringify ( webpackVersion ) ;
2023-06-17 04:24:34 +08:00
/ * *
2025-09-11 08:10:10 +08:00
* @ param { Members } members members
2023-06-17 04:24:34 +08:00
* @ returns { string } error message
* /
2025-07-17 00:13:14 +08:00
const importMetaUnknownProperty = ( members ) =>
2023-04-13 23:47:52 +08:00
` ${ Template . toNormalComment (
2024-07-31 10:39:30 +08:00
` unsupported import.meta. ${ members . join ( "." ) } `
2023-04-13 23:47:52 +08:00
) } undefined $ { propertyAccess ( members , 1 ) } ` ;
2020-06-23 05:53:13 +08:00
parser . hooks . typeof
. for ( "import.meta" )
. tap (
2023-04-01 01:56:32 +08:00
PLUGIN _NAME ,
2020-06-23 05:53:13 +08:00
toConstantDependency ( parser , JSON . stringify ( "object" ) )
) ;
2025-08-17 23:10:08 +08:00
parser . hooks . collectDestructuringAssignmentProperties . tap (
PLUGIN _NAME ,
( expr ) => {
if ( expr . type === "MetaProperty" ) return true ;
}
) ;
2020-08-27 19:03:56 +08:00
parser . hooks . expression
2020-08-16 15:26:14 +08:00
. for ( "import.meta" )
2025-07-17 00:13:14 +08:00
. tap ( PLUGIN _NAME , ( metaProperty ) => {
2023-04-13 23:47:52 +08:00
const referencedPropertiesInDestructuring =
parser . destructuringAssignmentPropertiesFor ( metaProperty ) ;
if ( ! referencedPropertiesInDestructuring ) {
const CriticalDependencyWarning =
getCriticalDependencyWarning ( ) ;
parser . state . module . addWarning (
new ModuleDependencyWarning (
parser . state . module ,
new CriticalDependencyWarning (
2025-09-30 22:32:35 +08:00
"'import.meta' cannot be used as a standalone expression. For static analysis, its properties must be accessed directly (e.g., 'import.meta.url') or through destructuring."
2023-04-13 23:47:52 +08:00
) ,
2023-06-17 04:24:34 +08:00
/** @type {DependencyLocation} */ ( metaProperty . loc )
2023-04-13 23:47:52 +08:00
)
) ;
const dep = new ConstDependency (
` ${
2023-06-17 04:24:34 +08:00
parser . isAsiPosition (
/** @type {Range} */ ( metaProperty . range ) [ 0 ]
)
? ";"
: ""
2023-04-13 23:47:52 +08:00
} ( { } ) ` ,
2023-06-17 04:24:34 +08:00
/** @type {Range} */ ( metaProperty . range )
2023-04-13 23:47:52 +08:00
) ;
2023-06-17 04:24:34 +08:00
dep . loc = /** @type {DependencyLocation} */ ( metaProperty . loc ) ;
2023-04-13 23:47:52 +08:00
parser . state . module . addPresentationalDependency ( dep ) ;
return true ;
}
let str = "" ;
2024-04-13 02:40:28 +08:00
for ( const { id : prop } of referencedPropertiesInDestructuring ) {
2023-04-13 23:47:52 +08:00
switch ( prop ) {
case "url" :
str += ` url: ${ importMetaUrl ( ) } , ` ;
break ;
case "webpack" :
str += ` webpack: ${ importMetaWebpackVersion ( ) } , ` ;
break ;
default :
str += ` [ ${ JSON . stringify (
prop
) } ] : $ { importMetaUnknownProperty ( [ prop ] ) } , ` ;
break ;
}
}
2023-06-17 04:24:34 +08:00
const dep = new ConstDependency (
` ({ ${ str } }) ` ,
/** @type {Range} */ ( metaProperty . range )
) ;
dep . loc = /** @type {DependencyLocation} */ ( metaProperty . loc ) ;
2020-08-16 15:26:14 +08:00
parser . state . module . addPresentationalDependency ( dep ) ;
return true ;
} ) ;
2020-07-06 23:13:09 +08:00
parser . hooks . evaluateTypeof
. for ( "import.meta" )
2023-04-01 01:56:32 +08:00
. tap ( PLUGIN _NAME , evaluateToString ( "object" ) ) ;
2020-06-25 03:47:43 +08:00
parser . hooks . evaluateIdentifier . for ( "import.meta" ) . tap (
2023-04-01 01:56:32 +08:00
PLUGIN _NAME ,
2020-07-06 23:13:09 +08:00
evaluateToIdentifier ( "import.meta" , "import.meta" , ( ) => [ ] , true )
2020-06-25 03:47:43 +08:00
) ;
2024-07-31 12:23:44 +08:00
// import.meta.url
2020-06-23 05:53:13 +08:00
parser . hooks . typeof
. for ( "import.meta.url" )
. tap (
2023-04-01 01:56:32 +08:00
PLUGIN _NAME ,
2020-06-23 05:53:13 +08:00
toConstantDependency ( parser , JSON . stringify ( "string" ) )
) ;
parser . hooks . expression
. for ( "import.meta.url" )
2025-07-17 00:13:14 +08:00
. tap ( PLUGIN _NAME , ( expr ) => {
2023-06-17 04:24:34 +08:00
const dep = new ConstDependency (
importMetaUrl ( ) ,
/** @type {Range} */ ( expr . range )
) ;
dep . loc = /** @type {DependencyLocation} */ ( expr . loc ) ;
2022-01-28 03:27:10 +08:00
parser . state . module . addPresentationalDependency ( dep ) ;
2020-06-23 05:53:13 +08:00
return true ;
} ) ;
2020-07-06 23:13:09 +08:00
parser . hooks . evaluateTypeof
. for ( "import.meta.url" )
2023-04-01 01:56:32 +08:00
. tap ( PLUGIN _NAME , evaluateToString ( "string" ) ) ;
2022-01-26 17:48:01 +08:00
parser . hooks . evaluateIdentifier
. for ( "import.meta.url" )
2025-07-17 00:13:14 +08:00
. tap ( PLUGIN _NAME , ( expr ) =>
2024-07-31 11:31:11 +08:00
new BasicEvaluatedExpression ( )
2022-01-26 17:48:01 +08:00
. setString ( getUrl ( parser . state . module ) )
2024-07-31 11:31:11 +08:00
. setRange ( /** @type {Range} */ ( expr . range ) )
) ;
2022-01-28 03:27:10 +08:00
2024-07-31 12:23:44 +08:00
// import.meta.webpack
2020-07-06 23:13:09 +08:00
parser . hooks . typeof
. for ( "import.meta.webpack" )
. tap (
2023-04-01 01:56:32 +08:00
PLUGIN _NAME ,
2020-07-06 23:13:09 +08:00
toConstantDependency ( parser , JSON . stringify ( "number" ) )
) ;
parser . hooks . expression
. for ( "import.meta.webpack" )
. tap (
2023-04-01 01:56:32 +08:00
PLUGIN _NAME ,
2023-04-13 23:47:52 +08:00
toConstantDependency ( parser , importMetaWebpackVersion ( ) )
2020-07-06 23:13:09 +08:00
) ;
parser . hooks . evaluateTypeof
. for ( "import.meta.webpack" )
2023-04-01 01:56:32 +08:00
. tap ( PLUGIN _NAME , evaluateToString ( "number" ) ) ;
2020-07-06 23:13:09 +08:00
parser . hooks . evaluateIdentifier
. for ( "import.meta.webpack" )
2023-04-01 01:56:32 +08:00
. tap ( PLUGIN _NAME , evaluateToNumber ( webpackVersion ) ) ;
2020-07-06 23:13:09 +08:00
2024-07-31 12:23:44 +08:00
// Unknown properties
2020-07-06 23:13:09 +08:00
parser . hooks . unhandledExpressionMemberChain
. for ( "import.meta" )
2023-04-01 01:56:32 +08:00
. tap ( PLUGIN _NAME , ( expr , members ) => {
2020-07-06 23:13:09 +08:00
const dep = new ConstDependency (
2023-04-13 23:47:52 +08:00
importMetaUnknownProperty ( members ) ,
2023-06-17 04:24:34 +08:00
/** @type {Range} */ ( expr . range )
2020-07-06 23:13:09 +08:00
) ;
2023-06-17 04:24:34 +08:00
dep . loc = /** @type {DependencyLocation} */ ( expr . loc ) ;
2020-07-06 23:13:09 +08:00
parser . state . module . addPresentationalDependency ( dep ) ;
return true ;
} ) ;
parser . hooks . evaluate
. for ( "MemberExpression" )
2025-07-17 00:13:14 +08:00
. tap ( PLUGIN _NAME , ( expression ) => {
2020-07-06 23:13:09 +08:00
const expr = /** @type {MemberExpression} */ ( expression ) ;
if (
expr . object . type === "MetaProperty" &&
2021-01-06 04:26:28 +08:00
expr . object . meta . name === "import" &&
expr . object . property . name === "meta" &&
2020-07-06 23:13:09 +08:00
expr . property . type ===
( expr . computed ? "Literal" : "Identifier" )
) {
return new BasicEvaluatedExpression ( )
. setUndefined ( )
2023-06-17 04:24:34 +08:00
. setRange ( /** @type {Range} */ ( expr . range ) ) ;
2020-07-06 23:13:09 +08:00
}
} ) ;
2020-06-23 05:53:13 +08:00
} ;
normalModuleFactory . hooks . parser
2023-04-01 01:56:32 +08:00
. for ( JAVASCRIPT _MODULE _TYPE _AUTO )
. tap ( PLUGIN _NAME , parserHandler ) ;
2020-06-23 05:53:13 +08:00
normalModuleFactory . hooks . parser
2023-04-01 01:56:32 +08:00
. for ( JAVASCRIPT _MODULE _TYPE _ESM )
. tap ( PLUGIN _NAME , parserHandler ) ;
2020-06-23 05:53:13 +08:00
}
) ;
}
}
module . exports = ImportMetaPlugin ;