replace micromatch with glob-to-regexp for sideEffects flag

This commit is contained in:
Tobias Koppers 2019-05-16 21:12:59 +02:00
parent 9b849e8d9c
commit a3f2314a63
4 changed files with 114 additions and 55 deletions

View File

@ -5,7 +5,7 @@
"use strict";
const mm = require("micromatch");
const glob2regexp = require("glob-to-regexp");
const { STAGE_DEFAULT } = require("../OptimizationStages");
const HarmonyExportImportedSpecifierDependency = require("../dependencies/HarmonyExportImportedSpecifierDependency");
const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportSpecifierDependency");
@ -20,12 +20,38 @@ const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportS
* @property {string} exportName the name of the export
*/
/** @type {WeakMap<any, Map<string, RegExp>>} */
const globToRegexpCache = new WeakMap();
/**
* @param {string} glob the pattern
* @param {Map<string, RegExp>} 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;
};
class SideEffectsFlagPlugin {
/**
* @param {Compiler} compiler webpack compiler
* @returns {void}
*/
apply(compiler) {
let cache = globToRegexpCache.get(compiler.root);
if (cache === undefined) {
cache = new Map();
globToRegexpCache.set(compiler.root, cache);
}
compiler.hooks.normalModuleFactory.tap("SideEffectsFlagPlugin", nmf => {
nmf.hooks.module.tap("SideEffectsFlagPlugin", (module, data) => {
const resolveData = data.resourceResolveData;
@ -37,7 +63,8 @@ class SideEffectsFlagPlugin {
const sideEffects = resolveData.descriptionFileData.sideEffects;
const hasSideEffects = SideEffectsFlagPlugin.moduleHasSideEffects(
resolveData.relativePath,
sideEffects
sideEffects,
cache
);
if (!hasSideEffects) {
module.factoryMeta.sideEffectFree = true;
@ -137,22 +164,17 @@ class SideEffectsFlagPlugin {
});
}
static moduleHasSideEffects(moduleName, flagValue) {
static moduleHasSideEffects(moduleName, flagValue, cache) {
switch (typeof flagValue) {
case "undefined":
return true;
case "boolean":
return flagValue;
case "string":
if (process.platform === "win32") {
flagValue = flagValue.replace(/\\/g, "/");
}
return mm.isMatch(moduleName, flagValue, {
matchBase: true
});
return globToRegexp(flagValue, cache).test(moduleName);
case "object":
return flagValue.some(glob =>
SideEffectsFlagPlugin.moduleHasSideEffects(moduleName, glob)
SideEffectsFlagPlugin.moduleHasSideEffects(moduleName, glob, cache)
);
}
}

View File

@ -18,11 +18,11 @@
"eslint-scope": "^4.0.0",
"events": "^3.0.0",
"find-cache-dir": "^2.1.0",
"glob-to-regexp": "^0.4.1",
"json-parse-better-errors": "^1.0.2",
"loader-runner": "3.0.0",
"loader-utils": "^1.1.0",
"memory-fs": "~0.4.1",
"micromatch": "^3.1.8",
"mkdirp": "~0.5.0",
"neo-async": "^2.5.0",
"schema-utils": "^1.0.0",

View File

@ -5,16 +5,28 @@ const SideEffectsFlagPlugin = require("../lib/optimize/SideEffectsFlagPlugin");
describe("SideEffectsFlagPlugin", () => {
it("should assume true", () => {
expect(
SideEffectsFlagPlugin.moduleHasSideEffects("./foo/bar.js", undefined)
SideEffectsFlagPlugin.moduleHasSideEffects(
"./foo/bar.js",
undefined,
new Map()
)
).toBe(true);
});
it("should understand boolean values", () => {
expect(
SideEffectsFlagPlugin.moduleHasSideEffects("./foo/bar.js", true)
SideEffectsFlagPlugin.moduleHasSideEffects(
"./foo/bar.js",
true,
new Map()
)
).toBe(true);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects("./foo/bar.js", false)
SideEffectsFlagPlugin.moduleHasSideEffects(
"./foo/bar.js",
false,
new Map()
)
).toBe(false);
});
@ -22,90 +34,110 @@ describe("SideEffectsFlagPlugin", () => {
expect(
SideEffectsFlagPlugin.moduleHasSideEffects(
"./src/x/y/z.js",
"./src/**/*.js"
"./src/**/*.js",
new Map()
)
).toBe(true);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects("./x.js", "./src/**/*.js")
SideEffectsFlagPlugin.moduleHasSideEffects(
"./x.js",
"./src/**/*.js",
new Map()
)
).toBe(false);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects(
"./src/x/y/z.js",
"./**/src/x/y/z.js"
)
).toBe(true);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects("./src/x/y/z.js", "**.js")
).toBe(true);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects(
"./src/x/y/z.js",
"./src/**/z.js"
"./**/src/x/y/z.js",
new Map()
)
).toBe(true);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects(
"./src/x/y/z.js",
"./**/x/**/z.js"
"**.js",
new Map()
)
).toBe(true);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects(
"./src/x/y/z.js",
"./**/src/**"
"./src/**/z.js",
new Map()
)
).toBe(true);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects("./src/x/y/z.js", "./**/src/*")
).toBe(false);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects("./src/x/y/z.js", "*.js")
SideEffectsFlagPlugin.moduleHasSideEffects(
"./src/x/y/z.js",
"./**/x/**/z.js",
new Map()
)
).toBe(true);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects("./src/x/y/z.js", "x/**/z.js")
SideEffectsFlagPlugin.moduleHasSideEffects(
"./src/x/y/z.js",
"./**/src/**",
new Map()
)
).toBe(true);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects(
"./src/x/y/z.js",
"./**/src/*",
new Map()
)
).toBe(false);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects(
"./src/x/y/z.js",
"src/**/z.js"
"*.js",
new Map()
)
).toBe(true);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects(
"./src/x/y/z.js",
"src/**/{x,y,z}.js"
"x/**/z.js",
new Map()
)
).toBe(true);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects(
"./src/x/y/z.js",
"src/**/[x-z].js"
)
).toBe(true);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects(
"./src/x/y/z.js",
"src/**/[[:lower:]].js"
)
).toBe(true);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects("./src/x/y/z.js", "!*.js")
).toBe(false);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects("./src/x/y/z.js", "!**/*.js")
).toBe(false);
SideEffectsFlagPlugin.moduleHasSideEffects(
"./src/x/y/z.js",
"src/**/z.js",
new Map()
)
).toBe(true);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects(
"./src/x/y/z.js",
"src/**/{x,y,z}.js",
new Map()
)
).toBe(true);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects(
"./src/x/y/z.js",
"src/**/[x-z].js",
new Map()
)
).toBe(true);
});
it("should understand arrays", () => {
const array = ["./src/**/*.js", "./dirty.js"];
expect(
SideEffectsFlagPlugin.moduleHasSideEffects("./src/x/y/z.js", array)
SideEffectsFlagPlugin.moduleHasSideEffects(
"./src/x/y/z.js",
array,
new Map()
)
).toBe(true);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects("./dirty.js", array)
SideEffectsFlagPlugin.moduleHasSideEffects("./dirty.js", array, new Map())
).toBe(true);
expect(
SideEffectsFlagPlugin.moduleHasSideEffects("./clean.js", array)
SideEffectsFlagPlugin.moduleHasSideEffects("./clean.js", array, new Map())
).toBe(false);
});
});

View File

@ -2226,6 +2226,11 @@ getpass@^0.1.1:
dependencies:
assert-plus "^1.0.0"
glob-to-regexp@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
glob@^5.0.15:
version "5.0.15"
resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"