Skip to content

Commit

Permalink
fix: improve perf (#760)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait authored Jan 11, 2024
1 parent f2a5db3 commit 55036ab
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 24 deletions.
85 changes: 62 additions & 23 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,48 @@
const path = require("path");

const { validate } = require("schema-utils");
const serialize = require("serialize-javascript");
const normalizePath = require("normalize-path");
const globParent = require("glob-parent");
const fastGlob = require("fast-glob");

// @ts-ignore
const { version } = require("../package.json");

const schema = require("./options.json");
const { readFile, stat, throttleAll } = require("./utils");
const {
readFile,
stat,
throttleAll,
memoize,
asyncMemoize,
} = require("./utils");

const template = /\[\\*([\w:]+)\\*\]/i;

const getNormalizePath = memoize(() =>
// eslint-disable-next-line global-require
require("normalize-path"),
);

const getGlobParent = memoize(() =>
// eslint-disable-next-line global-require
require("glob-parent"),
);

const getSerializeJavascript = memoize(() =>
// eslint-disable-next-line global-require
require("serialize-javascript"),
);

const getFastGlob = memoize(() =>
// eslint-disable-next-line global-require
require("fast-glob"),
);

const getGlobby = asyncMemoize(async () => {
// @ts-ignore
const { globby } = await import("globby");

return globby;
});

/** @typedef {import("schema-utils/declarations/validate").Schema} Schema */
/** @typedef {import("webpack").Compiler} Compiler */
/** @typedef {import("webpack").Compilation} Compilation */
Expand Down Expand Up @@ -334,7 +363,9 @@ class CopyPlugin {

pattern.context = absoluteFrom;
glob = path.posix.join(
fastGlob.escapePath(normalizePath(path.resolve(absoluteFrom))),
getFastGlob().escapePath(
getNormalizePath()(path.resolve(absoluteFrom)),
),
"**/*",
);
absoluteFrom = path.join(absoluteFrom, "**/*");
Expand All @@ -349,15 +380,19 @@ class CopyPlugin {
logger.debug(`added '${absoluteFrom}' as a file dependency`);

pattern.context = path.dirname(absoluteFrom);
glob = fastGlob.escapePath(normalizePath(path.resolve(absoluteFrom)));
glob = getFastGlob().escapePath(
getNormalizePath()(path.resolve(absoluteFrom)),
);

if (typeof globOptions.dot === "undefined") {
globOptions.dot = true;
}
break;
case "glob":
default: {
const contextDependencies = path.normalize(globParent(absoluteFrom));
const contextDependencies = path.normalize(
getGlobParent()(absoluteFrom),
);

compilation.contextDependencies.add(contextDependencies);

Expand All @@ -366,7 +401,9 @@ class CopyPlugin {
glob = path.isAbsolute(originalFrom)
? originalFrom
: path.posix.join(
fastGlob.escapePath(normalizePath(path.resolve(pattern.context))),
getFastGlob().escapePath(
getNormalizePath()(path.resolve(pattern.context)),
),
originalFrom,
);
}
Expand Down Expand Up @@ -481,7 +518,7 @@ class CopyPlugin {
`determined that '${from}' should write to '${filename}'`,
);

const sourceFilename = normalizePath(
const sourceFilename = getNormalizePath()(
path.relative(compiler.context, absoluteFilename),
);

Expand Down Expand Up @@ -628,7 +665,7 @@ class CopyPlugin {
contentHash: hasher.update(buffer).digest("hex"),
index,
};
const cacheKeys = `transform|${serialize(
const cacheKeys = `transform|${getSerializeJavascript()(
typeof transformObj.cache === "boolean"
? defaultCacheKeys
: typeof transformObj.cache.keys === "function"
Expand Down Expand Up @@ -708,7 +745,7 @@ class CopyPlugin {
const base = path.basename(sourceFilename);
const name = base.slice(0, base.length - ext.length);
const data = {
filename: normalizePath(
filename: getNormalizePath()(
path.relative(pattern.context, absoluteFilename),
),
contentHash,
Expand All @@ -719,7 +756,7 @@ class CopyPlugin {
},
};
const { path: interpolatedFilename, info: assetInfo } =
compilation.getPathWithInfo(normalizePath(filename), data);
compilation.getPathWithInfo(getNormalizePath()(filename), data);

info = { ...info, ...assetInfo };
filename = interpolatedFilename;
Expand All @@ -728,7 +765,7 @@ class CopyPlugin {
`interpolated template '${filename}' for '${sourceFilename}'`,
);
} else {
filename = normalizePath(filename);
filename = getNormalizePath()(filename);
}

// eslint-disable-next-line consistent-return
Expand Down Expand Up @@ -798,8 +835,7 @@ class CopyPlugin {
async (unusedAssets, callback) => {
if (typeof globby === "undefined") {
try {
// @ts-ignore
({ globby } = await import("globby"));
globby = await getGlobby();
} catch (error) {
callback(/** @type {Error} */ (error));

Expand Down Expand Up @@ -925,7 +961,7 @@ class CopyPlugin {
);

const cacheItem = cache.getItemCache(
`transformAll|${serialize({
`transformAll|${getSerializeJavascript()({
version,
from: normalizedPattern.from,
to: normalizedPattern.to,
Expand Down Expand Up @@ -970,13 +1006,16 @@ class CopyPlugin {
);

const { path: interpolatedFilename, info: assetInfo } =
compilation.getPathWithInfo(normalizePath(filename), {
contentHash,
chunk: {
id: "unknown-copied-asset",
hash: contentHash,
compilation.getPathWithInfo(
getNormalizePath()(filename),
{
contentHash,
chunk: {
id: "unknown-copied-asset",
hash: contentHash,
},
},
});
);

transformedAsset.filename = interpolatedFilename;
transformedAsset.info = assetInfo;
Expand Down
55 changes: 54 additions & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,57 @@ function throttleAll(limit, tasks) {
});
}

module.exports = { stat, readFile, throttleAll };
/**
* @template T
* @param fn {(function(): any) | undefined}
* @returns {function(): T}
*/
function memoize(fn) {
let cache = false;
/** @type {T} */
let result;

return () => {
if (cache) {
return result;
}

result = /** @type {function(): any} */ (fn)();
cache = true;
// Allow to clean up memory for fn
// and all dependent resources
// eslint-disable-next-line no-undefined, no-param-reassign
fn = undefined;

return result;
};
}

/**
* @template T
* @param fn {(function(): any) | undefined}
* @returns {function(): Promise<T>}
*/
function asyncMemoize(fn) {
let cache = false;
/** @type {T} */
let result;

return async () => {
if (cache) {
return result;
}

result = await /** @type {function(): any} */ (fn)();
cache = true;

// Allow to clean up memory for fn
// and all dependent resources
// eslint-disable-next-line no-undefined, no-param-reassign
fn = undefined;

return result;
};
}

module.exports = { stat, readFile, throttleAll, memoize, asyncMemoize };
12 changes: 12 additions & 0 deletions types/utils.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,15 @@ export function readFile(
* @returns {Promise<T[]>} A promise that fulfills to an array of the results
*/
export function throttleAll<T>(limit: number, tasks: Task<T>[]): Promise<T[]>;
/**
* @template T
* @param fn {(function(): any) | undefined}
* @returns {function(): T}
*/
export function memoize<T>(fn: (() => any) | undefined): () => T;
/**
* @template T
* @param fn {(function(): any) | undefined}
* @returns {function(): Promise<T>}
*/
export function asyncMemoize<T>(fn: (() => any) | undefined): () => Promise<T>;

0 comments on commit 55036ab

Please sign in to comment.