WXL
4 天以前 9bce51f651aad297ef9eb6df832bfdaf1de05d84
node_modules/webpack/lib/dependencies/ImportMetaPlugin.js
@@ -8,7 +8,7 @@
const { pathToFileURL } = require("url");
const { SyncBailHook } = require("tapable");
const Compilation = require("../Compilation");
const ModuleDependencyWarning = require("../ModuleDependencyWarning");
const DefinePlugin = require("../DefinePlugin");
const {
   JAVASCRIPT_MODULE_TYPE_AUTO,
   JAVASCRIPT_MODULE_TYPE_ESM
@@ -22,11 +22,12 @@
   evaluateToString,
   toConstantDependency
} = require("../javascript/JavascriptParserHelpers");
const memoize = require("../util/memoize");
const propertyAccess = require("../util/propertyAccess");
const { propertyAccess } = require("../util/property");
const ConstDependency = require("./ConstDependency");
const ModuleInitFragmentDependency = require("./ModuleInitFragmentDependency");
/** @typedef {import("estree").MemberExpression} MemberExpression */
/** @typedef {import("estree").Identifier} Identifier */
/** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
@@ -37,13 +38,43 @@
/** @typedef {import("../javascript/JavascriptParser").DestructuringAssignmentProperty} DestructuringAssignmentProperty */
/** @typedef {import("./ConstDependency").RawRuntimeRequirements} RawRuntimeRequirements */
const getCriticalDependencyWarning = memoize(() =>
   require("./CriticalDependencyWarning")
);
const PLUGIN_NAME = "ImportMetaPlugin";
/** @type {WeakMap<Compilation, { stringify: string, env: Record<string, string> }>} */
const compilationMetaEnvMap = new WeakMap();
/**
 * Collect import.meta.env definitions from DefinePlugin and build JSON string
 * @param {Compilation} compilation the compilation
 * @returns {{ stringify: string, env: Record<string, string> }} env object as JSON string
 */
const collectImportMetaEnvDefinitions = (compilation) => {
   const cached = compilationMetaEnvMap.get(compilation);
   if (cached) {
      return cached;
   }
   const definePluginHooks = DefinePlugin.getCompilationHooks(compilation);
   const definitions = definePluginHooks.definitions.call({});
   /** @type {Record<string, string>} */
   const env = {};
   /** @type {string[]} */
   const pairs = [];
   for (const key of Object.keys(definitions)) {
      if (key.startsWith("import.meta.env.")) {
         const envKey = key.slice("import.meta.env.".length);
         const value = definitions[key];
         pairs.push(`${JSON.stringify(envKey)}:${value}`);
         env[envKey] = /** @type {string} */ (value);
      }
   }
   const result = { stringify: `{${pairs.join(",")}}`, env };
   compilationMetaEnvMap.set(compilation, result);
   return result;
};
/**
 * Defines the import meta plugin hooks type used by this module.
 * @typedef {object} ImportMetaPluginHooks
 * @property {SyncBailHook<[DestructuringAssignmentProperty], string | void>} propertyInDestructuring
 */
@@ -53,6 +84,7 @@
class ImportMetaPlugin {
   /**
    * Returns the attached hooks.
    * @param {Compilation} compilation the compilation
    * @returns {ImportMetaPluginHooks} the attached hooks
    */
@@ -73,6 +105,7 @@
   }
   /**
    * Applies the plugin by registering its hooks on the compiler.
    * @param {Compiler} compiler compiler
    */
   apply(compiler) {
@@ -81,12 +114,19 @@
         (compilation, { normalModuleFactory }) => {
            const hooks = ImportMetaPlugin.getCompilationHooks(compilation);
            compilation.dependencyTemplates.set(
               ModuleInitFragmentDependency,
               new ModuleInitFragmentDependency.Template()
            );
            /**
             * Returns file url.
             * @param {NormalModule} module module
             * @returns {string} file url
             */
            const getUrl = (module) => pathToFileURL(module.resource).toString();
            /**
             * Processes the provided parser.
             * @param {Parser} parser parser parser
             * @param {JavascriptParserOptions} parserOptions parserOptions
             * @returns {void}
@@ -119,13 +159,19 @@
                  JSON.stringify(getUrl(parser.state.module));
               const importMetaWebpackVersion = () => JSON.stringify(webpackVersion);
               /**
                * Import meta unknown property.
                * @param {Members} members members
                * @returns {string} error message
                */
               const importMetaUnknownProperty = (members) =>
                  `${Template.toNormalComment(
               const importMetaUnknownProperty = (members) => {
                  if (importMeta === "preserve-unknown") {
                     return `import.meta${propertyAccess(members, 0)}`;
                  }
                  return `${Template.toNormalComment(
                     `unsupported import.meta.${members.join(".")}`
                  )} undefined${propertyAccess(members, 1)}`;
               };
               parser.hooks.typeof
                  .for("import.meta")
                  .tap(
@@ -141,37 +187,47 @@
               parser.hooks.expression
                  .for("import.meta")
                  .tap(PLUGIN_NAME, (metaProperty) => {
                     /** @type {RawRuntimeRequirements} */
                     const runtimeRequirements = [];
                     const moduleArgument = parser.state.module.moduleArgument;
                     const referencedPropertiesInDestructuring =
                        parser.destructuringAssignmentPropertiesFor(metaProperty);
                     if (!referencedPropertiesInDestructuring) {
                        const CriticalDependencyWarning =
                           getCriticalDependencyWarning();
                        parser.state.module.addWarning(
                           new ModuleDependencyWarning(
                              parser.state.module,
                              new CriticalDependencyWarning(
                                 "'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."
                              ),
                              /** @type {DependencyLocation} */ (metaProperty.loc)
                           )
                        const varName = "__webpack_import_meta__";
                        const { stringify: envStringify } =
                           collectImportMetaEnvDefinitions(compilation);
                        const knownProps =
                           `{url: ${importMetaUrl()}, ` +
                           `webpack: ${importMetaWebpackVersion()}, ` +
                           `main: ${RuntimeGlobals.moduleCache}[${RuntimeGlobals.entryModuleId}] === ${moduleArgument}, ` +
                           `env: ${envStringify}}`;
                        const initCode =
                           importMeta === "preserve-unknown"
                              ? `var ${varName} = Object.assign(import.meta, ${knownProps});\n`
                              : `var ${varName} = ${knownProps};\n`;
                        const initDep = new ModuleInitFragmentDependency(
                           initCode,
                           [
                              RuntimeGlobals.moduleCache,
                              RuntimeGlobals.entryModuleId,
                              RuntimeGlobals.module
                           ],
                           varName
                        );
                        initDep.loc = /** @type {DependencyLocation} */ (
                           metaProperty.loc
                        );
                        parser.state.module.addPresentationalDependency(initDep);
                        const dep = new ConstDependency(
                           `${
                              parser.isAsiPosition(
                                 /** @type {Range} */ (metaProperty.range)[0]
                              )
                                 ? ";"
                                 : ""
                           }({})`,
                           /** @type {Range} */ (metaProperty.range)
                           varName,
                           /** @type {Range} */ (metaProperty.range),
                           runtimeRequirements
                        );
                        dep.loc = /** @type {DependencyLocation} */ (metaProperty.loc);
                        parser.state.module.addPresentationalDependency(dep);
                        return true;
                     }
                     /** @type {RawRuntimeRequirements} */
                     const runtimeRequirements = [];
                     let str = "";
                     for (const prop of referencedPropertiesInDestructuring) {
@@ -190,12 +246,15 @@
                              str += `webpack: ${importMetaWebpackVersion()},`;
                              break;
                           case "main":
                              str += `main: ${RuntimeGlobals.moduleCache}[${RuntimeGlobals.entryModuleId}] === ${RuntimeGlobals.module},`;
                              str += `main: ${RuntimeGlobals.moduleCache}[${RuntimeGlobals.entryModuleId}] === ${moduleArgument},`;
                              runtimeRequirements.push(
                                 RuntimeGlobals.moduleCache,
                                 RuntimeGlobals.entryModuleId,
                                 RuntimeGlobals.module
                              );
                              break;
                           case "env":
                              str += `env: ${collectImportMetaEnvDefinitions(compilation).stringify},`;
                              break;
                           default:
                              str += `[${JSON.stringify(
@@ -294,10 +353,65 @@
                  .for("import.meta.main")
                  .tap(PLUGIN_NAME, evaluateToString("boolean"));
               // import.meta.env
               parser.hooks.typeof
                  .for("import.meta.env")
                  .tap(
                     PLUGIN_NAME,
                     toConstantDependency(parser, JSON.stringify("object"))
                  );
               parser.hooks.expressionMemberChain
                  .for("import.meta")
                  .tap(PLUGIN_NAME, (expr, members) => {
                     if (members[0] === "env" && members[1]) {
                        const name = members[1];
                        const { env } = collectImportMetaEnvDefinitions(compilation);
                        if (!Object.prototype.hasOwnProperty.call(env, name)) {
                           const dep = new ConstDependency(
                              "undefined",
                              /** @type {Range} */ (expr.range)
                           );
                           dep.loc = /** @type {DependencyLocation} */ (expr.loc);
                           parser.state.module.addPresentationalDependency(dep);
                           return true;
                        }
                     }
                  });
               parser.hooks.expression
                  .for("import.meta.env")
                  .tap(PLUGIN_NAME, (expr) => {
                     const { stringify } =
                        collectImportMetaEnvDefinitions(compilation);
                     const dep = new ConstDependency(
                        stringify,
                        /** @type {Range} */ (expr.range)
                     );
                     dep.loc = /** @type {DependencyLocation} */ (expr.loc);
                     parser.state.module.addPresentationalDependency(dep);
                     return true;
                  });
               parser.hooks.evaluateTypeof
                  .for("import.meta.env")
                  .tap(PLUGIN_NAME, evaluateToString("object"));
               parser.hooks.evaluateIdentifier
                  .for("import.meta.env")
                  .tap(PLUGIN_NAME, (expr) =>
                     new BasicEvaluatedExpression()
                        .setTruthy()
                        .setSideEffects(false)
                        .setRange(/** @type {Range} */ (expr.range))
                  );
               // Unknown properties
               parser.hooks.unhandledExpressionMemberChain
                  .for("import.meta")
                  .tap(PLUGIN_NAME, (expr, members) => {
                     // unknown import.meta properties should be determined at runtime
                     if (importMeta === "preserve-unknown") {
                        return true;
                     }
                     // keep import.meta.env unknown property
                     // don't evaluate import.meta.env.UNKNOWN_PROPERTY -> undefined.UNKNOWN_PROPERTY
                     // `dirname` and `filename` logic in NodeStuffPlugin
@@ -316,6 +430,7 @@
                     parser.state.module.addPresentationalDependency(dep);
                     return true;
                  });
               parser.hooks.evaluate
                  .for("MemberExpression")
                  .tap(PLUGIN_NAME, (expression) => {