| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- /*
- MIT License http://www.opensource.org/licenses/mit-license.php
- Author Tobias Koppers @sokra
- */
- "use strict";
- const Dependency = require("../Dependency");
- const RuntimeGlobals = require("../RuntimeGlobals");
- const {
- getDependencyUsedByExportsCondition
- } = require("../optimize/InnerGraph");
- const makeSerializable = require("../util/makeSerializable");
- const {
- ESM_MODULE_EXPORTS_NAME,
- getRequireEsmModuleExportsAccess,
- isRequireEsmModuleExportsModule
- } = require("./CommonJsDependencyHelpers");
- const HarmonyImportGuard = require("./HarmonyImportGuard");
- const ModuleDependency = require("./ModuleDependency");
- /** @import { ReplaceSource } from "webpack-sources" */
- /**
- * @import {
- * GetConditionFn,
- * RawReferencedExports,
- * ReferencedExports
- * } from "../Dependency"
- */
- /** @import { DependencyTemplateContext } from "../DependencyTemplate" */
- /** @import Module from "../Module" */
- /** @import ModuleGraph from "../ModuleGraph" */
- /** @import { Range } from "../javascript/JavascriptParser" */
- /** @import { UsedByExports } from "../optimize/InnerGraph" */
- /** @import { RuntimeSpec } from "../util/runtime" */
- /** @import { DependencyGuard } from "./HarmonyImportGuard" */
- /** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext<[RawReferencedExports | null, Range | undefined, DependencyGuard[] | undefined, boolean, boolean, UsedByExports | undefined]>} ObjectDeserializerContext */
- /** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext<[RawReferencedExports | null, Range | undefined, DependencyGuard[] | undefined, boolean, boolean, UsedByExports | undefined]>} ObjectSerializerContext */
- /**
- * Trims a member-access path at the first segment that is definitively not a
- * provided export of the module. Such a segment is a runtime property (e.g. an
- * array/object prototype method like `arr.includes`), so only the value up to
- * that point is observed; referencing the whole value keeps its data intact
- * instead of tree-shaking it away. Real named exports (`utils.foo`) are kept.
- * @param {import("../ExportsInfo")} exportsInfo module exports info
- * @param {string[]} name member-access path
- * @returns {string[]} the provided prefix of the path
- */
- const trimToProvidedPrefix = (exportsInfo, name) => {
- let current = exportsInfo;
- for (let i = 0; i < name.length; i++) {
- const exportInfo = current.getReadOnlyExportInfo(name[i]);
- if (exportInfo.provided === false) return name.slice(0, i);
- const nested = exportInfo.exportsInfo;
- if (!nested) return name;
- current = nested;
- }
- return name;
- };
- class CommonJsRequireDependency extends ModuleDependency {
- /**
- * Creates an instance of CommonJsRequireDependency.
- * @param {string} request request
- * @param {Range=} range location in source code of the string-literal argument (gets replaced by the module id)
- * @param {string=} context request context
- * @param {RawReferencedExports | null=} referencedExports list of referenced exports
- * @param {Range=} valueRange location in source code of the whole `require(...)` call (for `require(esm)` interop)
- */
- constructor(
- request,
- range,
- context,
- referencedExports = null,
- valueRange = undefined
- ) {
- super(request);
- this.range = range;
- /** @type {string | undefined} */
- this._context = context;
- /** @type {RawReferencedExports | null} */
- this.referencedExports = referencedExports;
- this.valueRange = valueRange;
- /** @type {DependencyGuard[] | undefined} */
- this.branchGuards = undefined;
- /** @type {UsedByExports | undefined} */
- this.usedByExports = undefined;
- /** @type {boolean} */
- this._canConcatenate = false;
- // `new require(...)`; see the template for the return-value rule
- /** @type {boolean} */
- this.callNew = false;
- }
- get type() {
- return "cjs require";
- }
- get category() {
- return "commonjs";
- }
- /**
- * Whether this require only evaluates the module (no exports read).
- * @returns {boolean} true when referencedExports is an empty list
- */
- isEvaluationOnly() {
- return (
- Array.isArray(this.referencedExports) &&
- this.referencedExports.length === 0
- );
- }
- /**
- * Returns function to determine if the connection is active.
- * @param {ModuleGraph} moduleGraph module graph
- * @returns {null | false | GetConditionFn} function to determine if the connection is active
- */
- getCondition(moduleGraph) {
- const usedByExportsCondition =
- this.usedByExports !== undefined
- ? getDependencyUsedByExportsCondition(this, moduleGraph)
- : null;
- if (usedByExportsCondition === false) return false;
- const guards = this.branchGuards;
- const evaluationOnly = this.isEvaluationOnly();
- if (
- usedByExportsCondition === null &&
- guards === undefined &&
- !evaluationOnly
- ) {
- return null;
- }
- return (connection, runtime) => {
- if (
- usedByExportsCondition !== null &&
- usedByExportsCondition(connection, runtime) === false
- ) {
- return false;
- }
- if (
- guards !== undefined &&
- HarmonyImportGuard.isDeadByGuards(guards, moduleGraph, runtime)
- ) {
- return false;
- }
- if (evaluationOnly) {
- const refModule = connection.resolvedModule;
- if (!refModule) return true;
- return refModule.getSideEffectsConnectionState(moduleGraph);
- }
- return true;
- };
- }
- /**
- * Returns list of exports referenced by this dependency
- * @param {ModuleGraph} moduleGraph module graph
- * @param {RuntimeSpec} runtime the runtime for which the module is analysed
- * @returns {ReferencedExports} referenced exports
- */
- getReferencedExports(moduleGraph, runtime) {
- const importedModule = moduleGraph.getModule(this);
- if (this.isEvaluationOnly()) {
- // Active `require(esm)` with side effects still unwraps `module.exports`.
- if (
- importedModule &&
- isRequireEsmModuleExportsModule(importedModule, moduleGraph)
- ) {
- return [{ name: [ESM_MODULE_EXPORTS_NAME], canInline: false }];
- }
- return Dependency.NO_EXPORTS_REFERENCED;
- }
- if (
- importedModule &&
- isRequireEsmModuleExportsModule(importedModule, moduleGraph)
- ) {
- // `require(esm)` will unwrap the "module.exports" named export; only
- // that export is observable through this `require()` call.
- return [{ name: [ESM_MODULE_EXPORTS_NAME], canInline: false }];
- }
- if (!this.referencedExports) return Dependency.EXPORTS_OBJECT_REFERENCED;
- const exportsInfo = importedModule
- ? moduleGraph.getExportsInfo(importedModule)
- : undefined;
- return this.referencedExports.map((name) => ({
- name: exportsInfo ? trimToProvidedPrefix(exportsInfo, name) : name,
- canMangle: false,
- canInline: false
- }));
- }
- /**
- * Returns true if this dependency can be concatenated
- * @param {boolean} concatenateCommonJsModules whether optimization.concatenateModules.commonjs is enabled
- * @returns {boolean} true if this dependency can be concatenated
- */
- canConcatenate(concatenateCommonJsModules) {
- return concatenateCommonJsModules && this._canConcatenate;
- }
- /**
- * Serializes this instance into the provided serializer context.
- * @param {ObjectSerializerContext} context context
- */
- serialize(context) {
- context
- .write(this.referencedExports)
- .write(this.valueRange)
- .write(this.branchGuards)
- .write(this._canConcatenate)
- .write(this.callNew)
- .write(this.usedByExports);
- super.serialize(context);
- }
- /**
- * Restores this instance from the provided deserializer context.
- * @param {ObjectDeserializerContext} context context
- */
- deserialize(context) {
- this.referencedExports = context.read();
- const c1 = context.rest;
- this.valueRange = c1.read();
- const c2 = c1.rest;
- this.branchGuards = c2.read();
- const c3 = c2.rest;
- this._canConcatenate = c3.read();
- const c4 = c3.rest;
- this.callNew = c4.read();
- const c5 = c4.rest;
- this.usedByExports = c5.read();
- super.deserialize(c5.rest);
- }
- }
- CommonJsRequireDependency.Template = class CommonJsRequireDependencyTemplate extends (
- ModuleDependency.Template
- ) {
- /**
- * Applies the plugin by registering its hooks on the compiler.
- * @param {Dependency} dependency the dependency for which the template should be applied
- * @param {ReplaceSource} source the current replace source which can be modified
- * @param {DependencyTemplateContext} templateContext the context object
- * @returns {void}
- */
- apply(dependency, source, templateContext) {
- const {
- runtimeTemplate,
- moduleGraph,
- chunkGraph,
- runtime,
- concatenationScope
- } = templateContext;
- const dep = /** @type {CommonJsRequireDependency} */ (dependency);
- if (!dep.range) return;
- const connection = moduleGraph.getConnection(dep);
- if (connection && !connection.isTargetActive(runtime)) {
- const guards = dep.branchGuards;
- if (
- guards !== undefined &&
- HarmonyImportGuard.isDeadByGuards(guards, moduleGraph, runtime)
- ) {
- // Dead branch: module is excluded and has no id; code is never executed.
- source.replace(
- dep.range[0],
- dep.range[1] - 1,
- "null /* dead branch */"
- );
- return;
- }
- // Unused side-effect-free require: drop the whole call expression.
- if (!dep.valueRange) return;
- source.replace(dep.valueRange[0], dep.valueRange[1] - 1, "0");
- return;
- }
- if (
- connection &&
- concatenationScope !== undefined &&
- dep.valueRange !== undefined &&
- concatenationScope.isModuleInScope(connection.module)
- ) {
- let content = concatenationScope.createModuleReference(
- connection.module,
- {
- // `require(esm)` unwraps the "module.exports" export
- ids: isRequireEsmModuleExportsModule(connection.module, moduleGraph)
- ? [ESM_MODULE_EXPORTS_NAME]
- : undefined,
- asiSafe: true,
- moduleExportsAccess: true
- }
- );
- // replacing the call drops the `new`, so apply the `new` return-value rule
- // here: object or function passes through, anything else gets a fresh instance
- if (dep.callNew) {
- templateContext.runtimeRequirements.add(
- RuntimeGlobals.constructRequire
- );
- content = `${RuntimeGlobals.constructRequire}(${content})`;
- }
- source.replace(dep.valueRange[0], dep.valueRange[1] - 1, content);
- concatenationScope.registerReplacedRequire(dep.valueRange);
- return;
- }
- const importedModule = /** @type {Module} */ (moduleGraph.getModule(dep));
- const content = runtimeTemplate.moduleId({
- module: importedModule,
- chunkGraph,
- request: dep.request,
- weak: dep.weak
- });
- source.replace(dep.range[0], dep.range[1] - 1, content);
- if (dep.valueRange && importedModule) {
- const access = getRequireEsmModuleExportsAccess(
- importedModule,
- moduleGraph,
- runtime
- );
- if (access !== null) {
- source.insert(dep.valueRange[1], access);
- }
- }
- }
- };
- makeSerializable(
- CommonJsRequireDependency,
- "webpack/lib/dependencies/CommonJsRequireDependency"
- );
- module.exports = CommonJsRequireDependency;
|