From d5f14083061f2ce6a42313188443a42e30796320 Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Tue, 31 Oct 2023 15:37:35 +0800 Subject: added make browserlist(autoprefixer) work fixed --- .../webpack/lib/optimize/SideEffectsFlagPlugin.js | 346 +++++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100644 node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js (limited to 'node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js') diff --git a/node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js b/node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js new file mode 100644 index 00000000..5628ed38 --- /dev/null +++ b/node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js @@ -0,0 +1,346 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const glob2regexp = require("glob-to-regexp"); +const { + JAVASCRIPT_MODULE_TYPE_AUTO, + JAVASCRIPT_MODULE_TYPE_ESM, + JAVASCRIPT_MODULE_TYPE_DYNAMIC +} = require("../ModuleTypeConstants"); +const { STAGE_DEFAULT } = require("../OptimizationStages"); +const HarmonyExportImportedSpecifierDependency = require("../dependencies/HarmonyExportImportedSpecifierDependency"); +const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportSpecifierDependency"); +const formatLocation = require("../formatLocation"); + +/** @typedef {import("estree").ModuleDeclaration} ModuleDeclaration */ +/** @typedef {import("estree").Statement} Statement */ +/** @typedef {import("../Compiler")} Compiler */ +/** @typedef {import("../Dependency")} Dependency */ +/** @typedef {import("../Module")} Module */ +/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */ + +/** + * @typedef {Object} ExportInModule + * @property {Module} module the module + * @property {string} exportName the name of the export + * @property {boolean} checked if the export is conditional + */ + +/** + * @typedef {Object} ReexportInfo + * @property {Map} static + * @property {Map>} dynamic + */ + +/** @type {WeakMap>} */ +const globToRegexpCache = new WeakMap(); + +/** + * @param {string} glob the pattern + * @param {Map} cache the glob to RegExp cache + * @returns {RegExp} a regular expression + */ +const globToRegexp = (glob, cache) => { + const cacheEntry = cache.get(glob); + if (cacheEntry !== undefined) return cacheEntry; + if (!glob.includes("/")) { + glob = `**/${glob}`; + } + const baseRegexp = glob2regexp(glob, { globstar: true, extended: true }); + const regexpSource = baseRegexp.source; + const regexp = new RegExp("^(\\./)?" + regexpSource.slice(1)); + cache.set(glob, regexp); + return regexp; +}; + +const PLUGIN_NAME = "SideEffectsFlagPlugin"; + +class SideEffectsFlagPlugin { + /** + * @param {boolean} analyseSource analyse source code for side effects + */ + constructor(analyseSource = true) { + this._analyseSource = analyseSource; + } + /** + * Apply the plugin + * @param {Compiler} compiler the compiler instance + * @returns {void} + */ + apply(compiler) { + let cache = globToRegexpCache.get(compiler.root); + if (cache === undefined) { + cache = new Map(); + globToRegexpCache.set(compiler.root, cache); + } + compiler.hooks.compilation.tap( + PLUGIN_NAME, + (compilation, { normalModuleFactory }) => { + const moduleGraph = compilation.moduleGraph; + normalModuleFactory.hooks.module.tap(PLUGIN_NAME, (module, data) => { + const resolveData = data.resourceResolveData; + if ( + resolveData && + resolveData.descriptionFileData && + resolveData.relativePath + ) { + const sideEffects = resolveData.descriptionFileData.sideEffects; + if (sideEffects !== undefined) { + if (module.factoryMeta === undefined) { + module.factoryMeta = {}; + } + const hasSideEffects = SideEffectsFlagPlugin.moduleHasSideEffects( + resolveData.relativePath, + sideEffects, + cache + ); + module.factoryMeta.sideEffectFree = !hasSideEffects; + } + } + + return module; + }); + normalModuleFactory.hooks.module.tap(PLUGIN_NAME, (module, data) => { + if (typeof data.settings.sideEffects === "boolean") { + if (module.factoryMeta === undefined) { + module.factoryMeta = {}; + } + module.factoryMeta.sideEffectFree = !data.settings.sideEffects; + } + return module; + }); + if (this._analyseSource) { + /** + * @param {JavascriptParser} parser the parser + * @returns {void} + */ + const parserHandler = parser => { + /** @type {undefined | Statement | ModuleDeclaration} */ + let sideEffectsStatement; + parser.hooks.program.tap(PLUGIN_NAME, () => { + sideEffectsStatement = undefined; + }); + parser.hooks.statement.tap( + { name: PLUGIN_NAME, stage: -100 }, + statement => { + if (sideEffectsStatement) return; + if (parser.scope.topLevelScope !== true) return; + switch (statement.type) { + case "ExpressionStatement": + if ( + !parser.isPure(statement.expression, statement.range[0]) + ) { + sideEffectsStatement = statement; + } + break; + case "IfStatement": + case "WhileStatement": + case "DoWhileStatement": + if (!parser.isPure(statement.test, statement.range[0])) { + sideEffectsStatement = statement; + } + // statement hook will be called for child statements too + break; + case "ForStatement": + if ( + !parser.isPure(statement.init, statement.range[0]) || + !parser.isPure( + statement.test, + statement.init + ? statement.init.range[1] + : statement.range[0] + ) || + !parser.isPure( + statement.update, + statement.test + ? statement.test.range[1] + : statement.init + ? statement.init.range[1] + : statement.range[0] + ) + ) { + sideEffectsStatement = statement; + } + // statement hook will be called for child statements too + break; + case "SwitchStatement": + if ( + !parser.isPure(statement.discriminant, statement.range[0]) + ) { + sideEffectsStatement = statement; + } + // statement hook will be called for child statements too + break; + case "VariableDeclaration": + case "ClassDeclaration": + case "FunctionDeclaration": + if (!parser.isPure(statement, statement.range[0])) { + sideEffectsStatement = statement; + } + break; + case "ExportNamedDeclaration": + case "ExportDefaultDeclaration": + if ( + !parser.isPure(statement.declaration, statement.range[0]) + ) { + sideEffectsStatement = statement; + } + break; + case "LabeledStatement": + case "BlockStatement": + // statement hook will be called for child statements too + break; + case "EmptyStatement": + break; + case "ExportAllDeclaration": + case "ImportDeclaration": + // imports will be handled by the dependencies + break; + default: + sideEffectsStatement = statement; + break; + } + } + ); + parser.hooks.finish.tap(PLUGIN_NAME, () => { + if (sideEffectsStatement === undefined) { + parser.state.module.buildMeta.sideEffectFree = true; + } else { + const { loc, type } = sideEffectsStatement; + moduleGraph + .getOptimizationBailout(parser.state.module) + .push( + () => + `Statement (${type}) with side effects in source code at ${formatLocation( + loc + )}` + ); + } + }); + }; + for (const key of [ + JAVASCRIPT_MODULE_TYPE_AUTO, + JAVASCRIPT_MODULE_TYPE_ESM, + JAVASCRIPT_MODULE_TYPE_DYNAMIC + ]) { + normalModuleFactory.hooks.parser + .for(key) + .tap(PLUGIN_NAME, parserHandler); + } + } + compilation.hooks.optimizeDependencies.tap( + { + name: PLUGIN_NAME, + stage: STAGE_DEFAULT + }, + modules => { + const logger = compilation.getLogger( + "webpack.SideEffectsFlagPlugin" + ); + + logger.time("update dependencies"); + for (const module of modules) { + if (module.getSideEffectsConnectionState(moduleGraph) === false) { + const exportsInfo = moduleGraph.getExportsInfo(module); + for (const connection of moduleGraph.getIncomingConnections( + module + )) { + const dep = connection.dependency; + let isReexport; + if ( + (isReexport = + dep instanceof + HarmonyExportImportedSpecifierDependency) || + (dep instanceof HarmonyImportSpecifierDependency && + !dep.namespaceObjectAsContext) + ) { + // TODO improve for export * + if (isReexport && dep.name) { + const exportInfo = moduleGraph.getExportInfo( + /** @type {Module} */ (connection.originModule), + dep.name + ); + exportInfo.moveTarget( + moduleGraph, + ({ module }) => + module.getSideEffectsConnectionState(moduleGraph) === + false, + ({ module: newModule, export: exportName }) => { + moduleGraph.updateModule(dep, newModule); + moduleGraph.addExplanation( + dep, + "(skipped side-effect-free modules)" + ); + const ids = dep.getIds(moduleGraph); + dep.setIds( + moduleGraph, + exportName + ? [...exportName, ...ids.slice(1)] + : ids.slice(1) + ); + return moduleGraph.getConnection(dep); + } + ); + continue; + } + // TODO improve for nested imports + const ids = dep.getIds(moduleGraph); + if (ids.length > 0) { + const exportInfo = exportsInfo.getExportInfo(ids[0]); + const target = exportInfo.getTarget( + moduleGraph, + ({ module }) => + module.getSideEffectsConnectionState(moduleGraph) === + false + ); + if (!target) continue; + + moduleGraph.updateModule(dep, target.module); + moduleGraph.addExplanation( + dep, + "(skipped side-effect-free modules)" + ); + dep.setIds( + moduleGraph, + target.export + ? [...target.export, ...ids.slice(1)] + : ids.slice(1) + ); + } + } + } + } + } + logger.timeEnd("update dependencies"); + } + ); + } + ); + } + + /** + * @param {string} moduleName the module name + * @param {undefined | boolean | string | string[]} flagValue the flag value + * @param {Map} cache cache for glob to regexp + * @returns {boolean | undefined} true, when the module has side effects, undefined or false when not + */ + static moduleHasSideEffects(moduleName, flagValue, cache) { + switch (typeof flagValue) { + case "undefined": + return true; + case "boolean": + return flagValue; + case "string": + return globToRegexp(flagValue, cache).test(moduleName); + case "object": + return flagValue.some(glob => + SideEffectsFlagPlugin.moduleHasSideEffects(moduleName, glob, cache) + ); + } + } +} +module.exports = SideEffectsFlagPlugin; -- cgit v1.2.3