New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

copy-webpack-plugin

Package Overview
Dependencies
Maintainers
3
Versions
81
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

copy-webpack-plugin - npm Package Compare versions

Comparing version

to
13.0.0

160

dist/index.js

@@ -29,12 +29,5 @@ "use strict";

require("serialize-javascript"));
const getFastGlob = memoize(() =>
const getTinyGlobby = memoize(() =>
// eslint-disable-next-line global-require
require("fast-glob"));
const getGlobby = memoize(async () => {
// @ts-ignore
const {
globby
} = await import("globby");
return globby;
});
require("tinyglobby"));

@@ -46,4 +39,3 @@ /** @typedef {import("schema-utils/declarations/validate").Schema} Schema */

/** @typedef {import("webpack").Asset} Asset */
/** @typedef {import("globby").Options} GlobbyOptions */
/** @typedef {import("globby").GlobEntry} GlobEntry */
/** @typedef {import("tinyglobby").GlobOptions} GlobbyOptions */
/** @typedef {ReturnType<Compilation["getLogger"]>} WebpackLogger */

@@ -166,2 +158,3 @@ /** @typedef {ReturnType<Compilation["getCache"]>} CacheFacade */

const PLUGIN_NAME = "CopyPlugin";
class CopyPlugin {

@@ -174,3 +167,3 @@ /**

}) {
validate( /** @type {Schema} */schema, options, {
validate(/** @type {Schema} */schema, options, {
name: "Copy Plugin",

@@ -213,3 +206,3 @@ baseDataPath: "options"

}
resolve( /** @type {Snapshot} */snapshot);
resolve(/** @type {Snapshot} */snapshot);
});

@@ -255,3 +248,3 @@ });

} = outputOptions;
const hash = compiler.webpack.util.createHash( /** @type {string} */hashFunction);
const hash = compiler.webpack.util.createHash(/** @type {string} */hashFunction);
if (hashSalt) {

@@ -267,3 +260,3 @@ hash.update(hashSalt);

* @private
* @param {typeof import("globby").globby} globby
* @param {typeof import("tinyglobby").glob} globby
* @param {Compiler} compiler

@@ -273,2 +266,3 @@ * @param {Compilation} compilation

* @param {CacheFacade} cache
* @param {number} concurrency
* @param {ObjectPattern & { context: string }} inputPattern

@@ -278,3 +272,3 @@ * @param {number} index

*/
static async runPattern(globby, compiler, compilation, logger, cache, inputPattern, index) {
static async glob(globby, compiler, compilation, logger, cache, concurrency, inputPattern, index) {
const {

@@ -301,2 +295,3 @@ RawSource

try {
// @ts-ignore
stats = await stat(inputFileSystem, absoluteFrom);

@@ -328,14 +323,12 @@ } catch (error) {

/** @type {GlobbyOptions & { objectMode: true }} */
/** @type {GlobbyOptions} */
const globOptions = {
...{
followSymbolicLinks: true
},
absolute: true,
followSymbolicLinks: true,
...(pattern.globOptions || {}),
...{
cwd: pattern.context,
objectMode: true
}
cwd: pattern.context,
onlyFiles: true
};
// Will work when https://github.com/SuperchupuDev/tinyglobby/issues/81 will be resolved, so let's pass it to `tinyglobby` right now
// @ts-ignore

@@ -349,3 +342,3 @@ globOptions.fs = inputFileSystem;

pattern.context = absoluteFrom;
glob = path.posix.join(getFastGlob().escapePath(getNormalizePath()(path.resolve(absoluteFrom))), "**/*");
glob = path.posix.join(getTinyGlobby().escapePath(getNormalizePath()(path.resolve(absoluteFrom))), "**/*");
absoluteFrom = path.join(absoluteFrom, "**/*");

@@ -360,3 +353,3 @@ if (typeof globOptions.dot === "undefined") {

pattern.context = path.dirname(absoluteFrom);
glob = getFastGlob().escapePath(getNormalizePath()(path.resolve(absoluteFrom)));
glob = getTinyGlobby().escapePath(getNormalizePath()(path.resolve(absoluteFrom)));
if (typeof globOptions.dot === "undefined") {

@@ -372,3 +365,3 @@ globOptions.dot = true;

logger.debug(`added '${contextDependencies}' as a context dependency`);
glob = path.isAbsolute(originalFrom) ? originalFrom : path.posix.join(getFastGlob().escapePath(getNormalizePath()(path.resolve(pattern.context))), originalFrom);
glob = path.isAbsolute(originalFrom) ? originalFrom : path.posix.join(getTinyGlobby().escapePath(getNormalizePath()(path.resolve(pattern.context))), originalFrom);
}

@@ -379,3 +372,3 @@ }

/**
* @type {GlobEntry[]}
* @type {string[]}
*/

@@ -386,3 +379,3 @@ let globEntries;

} catch (error) {
compilation.errors.push( /** @type {WebpackError} */error);
compilation.errors.push(/** @type {WebpackError} */error);
return;

@@ -396,3 +389,3 @@ }

const missingError = new Error(`unable to locate '${glob}' glob`);
compilation.errors.push( /** @type {WebpackError} */missingError);
compilation.errors.push(/** @type {WebpackError} */missingError);
return;

@@ -406,26 +399,17 @@ }

try {
copiedResult = await Promise.all(globEntries.map(
/**
* @param {GlobEntry} globEntry
* @returns {Promise<CopiedResult | undefined>}
*/
async globEntry => {
// Exclude directories
if (!globEntry.dirent.isFile()) {
return;
}
copiedResult = await throttleAll(concurrency, globEntries.map(globEntry => async () => {
if (pattern.filter) {
let isFiltered;
try {
isFiltered = await pattern.filter(globEntry.path);
isFiltered = await pattern.filter(globEntry);
} catch (error) {
compilation.errors.push( /** @type {WebpackError} */error);
compilation.errors.push(/** @type {WebpackError} */error);
return;
}
if (!isFiltered) {
logger.log(`skip '${globEntry.path}', because it was filtered`);
logger.log(`skip '${globEntry}', because it was filtered`);
return;
}
}
const from = globEntry.path;
const from = globEntry;
logger.debug(`found '${from}'`);

@@ -444,3 +428,3 @@

if (path.isAbsolute(filename)) {
filename = path.relative( /** @type {string} */compiler.options.output.path, filename);
filename = path.relative(/** @type {string} */compiler.options.output.path, filename);
}

@@ -460,3 +444,3 @@ logger.log(`determined that '${from}' should write to '${filename}'`);

} catch (error) {
compilation.errors.push( /** @type {WebpackError} */error);
compilation.errors.push(/** @type {WebpackError} */error);
return;

@@ -476,3 +460,3 @@ }

} catch (error) {
compilation.errors.push( /** @type {WebpackError} */error);
compilation.errors.push(/** @type {WebpackError} */error);
return;

@@ -496,5 +480,6 @@ }

try {
// @ts-ignore
data = await readFile(inputFileSystem, absoluteFilename);
} catch (error) {
compilation.errors.push( /** @type {WebpackError} */error);
compilation.errors.push(/** @type {WebpackError} */error);
return;

@@ -509,3 +494,3 @@ }

} catch (error) {
compilation.errors.push( /** @type {WebpackError} */error);
compilation.errors.push(/** @type {WebpackError} */error);
return;

@@ -522,3 +507,3 @@ }

} catch (error) {
compilation.errors.push( /** @type {WebpackError} */error);
compilation.errors.push(/** @type {WebpackError} */error);
return;

@@ -540,6 +525,4 @@ }

if (transformObj.cache) {
// TODO: remove in the next major release
const hasher = compiler.webpack && compiler.webpack.util && compiler.webpack.util.createHash ? compiler.webpack.util.createHash("xxhash64") :
// eslint-disable-next-line global-require
require("crypto").createHash("md4");
const hasher = compiler.webpack.util.createHash(/** @type {string} */
compilation.outputOptions.hashFunction);
const defaultCacheKeys = {

@@ -589,3 +572,3 @@ version,

name,
id: ( /** @type {string} */sourceFilename),
id: (/** @type {string} */sourceFilename),
hash: contentHash

@@ -619,3 +602,3 @@ }

} catch (error) {
compilation.errors.push( /** @type {WebpackError} */error);
compilation.errors.push(/** @type {WebpackError} */error);
return;

@@ -629,3 +612,3 @@ }

const missingError = new Error(`unable to locate '${glob}' glob after filtering paths`);
compilation.errors.push( /** @type {WebpackError} */missingError);
compilation.errors.push(/** @type {WebpackError} */missingError);
return;

@@ -649,7 +632,7 @@ }

/**
* @type {typeof import("globby").globby}
* @type {typeof import("tinyglobby").glob}
*/
let globby;
compilation.hooks.processAssets.tapAsync({
name: "copy-webpack-plugin",
name: PLUGIN_NAME,
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL

@@ -659,5 +642,5 @@ }, async (unusedAssets, callback) => {

try {
globby = await getGlobby();
globby = await getTinyGlobby().glob;
} catch (error) {
callback( /** @type {Error} */error);
callback(/** @type {Error} */error);
return;

@@ -667,14 +650,9 @@ }

logger.log("starting to add additional assets...");
const concurrency = this.options.concurrency || 100;
/** @type {Map<number, Map<number, CopiedResult[]>>} */
const copiedResultMap = new Map();
/**
* @type {(() => Promise<void>)[]}
*/
const scheduledTasks = [];
this.patterns.map(
/**
* @param {Pattern} item
* @param {number} index
* @return {number}
*/
(item, index) => scheduledTasks.push(async () => {
await throttleAll(
// Should be enough, it might be worth considering an option for this, but in real configurations it usually doesn't exceed this value
// https://github.com/webpack-contrib/copy-webpack-plugin/issues/627
2, this.patterns.map((item, index) => async () => {
/**

@@ -696,6 +674,6 @@ * @type {ObjectPattern}

try {
copiedResult = await CopyPlugin.runPattern(globby, compiler, compilation, logger, cache, /** @type {ObjectPattern & { context: string }} */
copiedResult = await CopyPlugin.glob(globby, compiler, compilation, logger, cache, concurrency, /** @type {ObjectPattern & { context: string }} */
normalizedPattern, index);
} catch (error) {
compilation.errors.push( /** @type {WebpackError} */error);
compilation.errors.push(/** @type {WebpackError} */error);
return;

@@ -718,3 +696,3 @@ }

if (typeof normalizedPattern.to === "undefined") {
compilation.errors.push( /** @type {WebpackError} */
compilation.errors.push(/** @type {WebpackError} */

@@ -735,3 +713,3 @@ new Error(`Invalid "pattern.to" for the "pattern.from": "${normalizedPattern.from}" and "pattern.transformAll" function. The "to" option must be specified.`));

// eslint-disable-next-line no-param-reassign
accumulator = cache.mergeEtags(i === 1 ? cache.getLazyHashedEtag( /** @type {CopiedResult}*/accumulator.source) : accumulator, cache.getLazyHashedEtag(asset.source));
accumulator = cache.mergeEtags(i === 1 ? cache.getLazyHashedEtag(/** @type {CopiedResult}*/accumulator.source) : accumulator, cache.getLazyHashedEtag(asset.source));
return accumulator;

@@ -759,3 +737,3 @@ });

} catch (error) {
compilation.errors.push( /** @type {WebpackError} */error);
compilation.errors.push(/** @type {WebpackError} */error);
return;

@@ -792,17 +770,21 @@ }

if (!copiedResultMap.has(priority)) {
copiedResultMap.set(priority, []);
copiedResultMap.set(priority, new Map());
}
copiedResultMap.get(priority).push(...filteredCopiedResult);
/** @type {Map<index, CopiedResult[]>} */
copiedResultMap.get(priority).set(index, filteredCopiedResult);
}));
await throttleAll(this.options.concurrency || 100, scheduledTasks);
const copiedResult = [...copiedResultMap.entries()].sort((a, b) => a[0] - b[0]);
// Avoid writing assets inside `p-limit`, because it creates concurrency.
// Avoid writing assets inside `throttleAll`, because it creates concurrency.
// It could potentially lead to an error - 'Multiple assets emit different content to the same filename'
copiedResult.reduce((acc, val) => acc.concat(val[1]), []).filter(Boolean).forEach(
/**
* @param {CopiedResult} result
* @returns {void}
*/
result => {
copiedResult.reduce((acc, val) => {
const sortedByIndex = [...val[1]].sort((a, b) => a[0] - b[0]);
for (const [, item] of sortedByIndex) {
// eslint-disable-next-line no-param-reassign
acc = acc.concat(item);
}
return acc;
}, /** @type {CopiedResult[]} */
[]).filter(Boolean).forEach(result => {
const {

@@ -849,6 +831,6 @@ absoluteFilename,

compilation.hooks.statsPrinter.tap(pluginName, stats => {
stats.hooks.print.for("asset.info.copied").tap("copy-webpack-plugin", (copied, {
stats.hooks.print.for("asset.info.copied").tap(PLUGIN_NAME, (copied, {
green,
formatFlag
}) => copied ? /** @type {Function} */green( /** @type {Function} */formatFlag("copied")) : "");
}) => copied ? /** @type {Function} */green(/** @type {Function} */formatFlag("copied")) : "");
});

@@ -855,0 +837,0 @@ }

@@ -46,3 +46,3 @@ "use strict";

}
resolve( /** @type {string | Buffer} */data);
resolve(/** @type {string | Buffer} */data);
});

@@ -83,3 +83,3 @@ });

if (isLast) {
resolve( /** @type{T[]} **/result);
resolve(/** @type{T[]} **/result);
}

@@ -86,0 +86,0 @@ return;

{
"name": "copy-webpack-plugin",
"version": "12.0.2",
"version": "13.0.0",
"description": "Copy files && directories with webpack",

@@ -36,3 +36,3 @@ "license": "MIT",

"fix": "npm-run-all -l fix:js fix:prettier",
"test:only": "cross-env NODE_ENV=test jest",
"test:only": "cross-env NODE_ENV=test node --experimental-vm-modules node_modules/jest/bin/jest.js",
"test:watch": "npm run test:only -- --watch",

@@ -42,3 +42,3 @@ "test:coverage": "npm run test:only -- --collectCoverageFrom=\"src/**/*.js\" --coverage",

"test": "npm run test:coverage",
"prepare": "husky install && npm run build",
"prepare": "husky && npm run build",
"release": "standard-version"

@@ -54,18 +54,17 @@ },

"dependencies": {
"fast-glob": "^3.3.2",
"glob-parent": "^6.0.1",
"globby": "^14.0.0",
"normalize-path": "^3.0.0",
"schema-utils": "^4.2.0",
"serialize-javascript": "^6.0.2"
"serialize-javascript": "^6.0.2",
"tinyglobby": "^0.2.12"
},
"devDependencies": {
"@babel/cli": "^7.23.4",
"@babel/core": "^7.23.7",
"@babel/eslint-parser": "^7.23.3",
"@babel/preset-env": "^7.23.7",
"@commitlint/cli": "^18.4.4",
"@commitlint/config-conventional": "^18.4.4",
"@babel/cli": "^7.24.6",
"@babel/core": "^7.25.2",
"@babel/eslint-parser": "^7.25.1",
"@babel/preset-env": "^7.25.3",
"@commitlint/cli": "^19.3.0",
"@commitlint/config-conventional": "^19.2.2",
"@types/glob-parent": "^5.1.3",
"@types/node": "^20.10.8",
"@types/node": "^22.13.5",
"@types/normalize-path": "^3.0.2",

@@ -76,19 +75,19 @@ "@types/serialize-javascript": "^5.0.4",

"cross-env": "^7.0.3",
"cspell": "^8.3.2",
"cspell": "^8.15.6",
"del": "^6.1.1",
"del-cli": "^5.1.0",
"eslint": "^8.56.0",
"del-cli": "^6.0.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"file-loader": "^6.2.0",
"husky": "^8.0.3",
"husky": "^9.1.4",
"is-gzip": "^2.0.0",
"jest": "^29.7.0",
"lint-staged": "^15.2.0",
"memfs": "^4.6.0",
"lint-staged": "^15.2.8",
"memfs": "^4.11.1",
"npm-run-all": "^4.1.5",
"prettier": "^3.1.1",
"prettier": "^3.2.5",
"standard-version": "^9.3.1",
"typescript": "^5.3.3",
"webpack": "^5.89.0"
"typescript": "^5.4.5",
"webpack": "^5.91.0"
},

@@ -95,0 +94,0 @@ "keywords": [

@@ -58,11 +58,11 @@ <div align="center">

> **Note**
> [!NOTE]
>
> `copy-webpack-plugin` is not designed to copy files generated from the build process; rather, it is to copy files that already exist in the source tree, as part of the build process.
> **Note**
> [!NOTE]
>
> If you want `webpack-dev-server` to write files to the output directory during development, you can force it with the [`writeToDisk`](https://github.com/webpack/webpack-dev-middleware#writetodisk) option or the [`write-file-webpack-plugin`](https://github.com/gajus/write-file-webpack-plugin).
> **Note**
> [!NOTE]
>

@@ -127,3 +127,3 @@ > You can get the original source filename from [Asset Objects](https://webpack.js.org/api/stats/#asset-objects).

> **Warning**
> [!WARNING]
>

@@ -218,3 +218,3 @@ > Don't use directly `\\` in `from` option if it is a `glob` (i.e `path\to\file.ext`) option because on UNIX the backslash is a valid character inside a path component, i.e., it's not a separator.

> **Warning**
> [!WARNING]
>

@@ -254,3 +254,3 @@ > Don't use directly `\\` in `to` (i.e `path\to\dest`) option because on UNIX the backslash is a valid character inside a path component, i.e., it's not a separator.

> **Warning**
> [!WARNING]
>

@@ -311,3 +311,3 @@ > Don't return directly `\\` in `to` (i.e `path\to\newFile`) option because on UNIX the backslash is a valid character inside a path component, i.e., it's not a separator.

> **Warning**
> [!WARNING]
>

@@ -348,6 +348,10 @@ > Don't use directly `\\` in `context` (i.e `path\to\context`) option because on UNIX the backslash is a valid character inside a path component, i.e., it's not a separator.

> [!WARNING]
>
> The _onlyDirectories_ does not work because the plugin is designed to copy files.
Type:
```ts
type globOptions = import("globby").Options;
type globOptions = import("tinyglobby").GlobOptions;
```

@@ -391,3 +395,3 @@

> **Note**
> [!NOTE]
>

@@ -859,3 +863,3 @@ > To ignore files by path please use the [`globOptions.ignore`](#globoptions) option.

> **Note**
> [!NOTE]
>

@@ -950,3 +954,3 @@ > The `to` option must be specified and point to a file. It is allowed to use only `[contenthash]` and `[fullhash]` template strings.

from: "**/*",
// Terser skip this file for minimization
// Terser skip this file for minification
info: { minimized: true },

@@ -991,5 +995,5 @@ },

default: `100`
Default: `100`
limits the number of simultaneous requests to fs
Limits the number of simultaneous requests to fs.

@@ -1209,3 +1213,3 @@ **webpack.config.js**

> **Warning**
> [!WARNING]
>

@@ -1340,2 +1344,2 @@ > If files have the same name, the result is non-deterministic.

[size-url]: https://packagephobia.now.sh/result?p=copy-webpack-plugin
[glob-options]: https://github.com/sindresorhus/globby#options
[glob-options]: https://github.com/SuperchupuDev/tinyglobby#options
export = CopyPlugin;
/** @typedef {import("schema-utils/declarations/validate").Schema} Schema */
/** @typedef {import("webpack").Compiler} Compiler */
/** @typedef {import("webpack").Compilation} Compilation */
/** @typedef {import("webpack").WebpackError} WebpackError */
/** @typedef {import("webpack").Asset} Asset */
/** @typedef {import("globby").Options} GlobbyOptions */
/** @typedef {import("globby").GlobEntry} GlobEntry */
/** @typedef {ReturnType<Compilation["getLogger"]>} WebpackLogger */
/** @typedef {ReturnType<Compilation["getCache"]>} CacheFacade */
/** @typedef {ReturnType<ReturnType<Compilation["getCache"]>["getLazyHashedEtag"]>} Etag */
/** @typedef {ReturnType<Compilation["fileSystemInfo"]["mergeSnapshots"]>} Snapshot */
/**
* @typedef {boolean} Force
*/
/**
* @typedef {Object} CopiedResult
* @property {string} sourceFilename
* @property {string} absoluteFilename
* @property {string} filename
* @property {Asset["source"]} source
* @property {Force | undefined} force
* @property {Record<string, any>} info
*/
/**
* @typedef {string} StringPattern
*/
/**
* @typedef {boolean} NoErrorOnMissing
*/
/**
* @typedef {string} Context
*/
/**
* @typedef {string} From
*/
/**
* @callback ToFunction
* @param {{ context: string, absoluteFilename?: string }} pathData
* @return {string | Promise<string>}
*/
/**
* @typedef {string | ToFunction} To
*/
/**
* @typedef {"dir" | "file" | "template"} ToType
*/
/**
* @callback TransformerFunction
* @param {Buffer} input
* @param {string} absoluteFilename
* @returns {string | Buffer | Promise<string> | Promise<Buffer>}
*/
/**
* @typedef {{ keys: { [key: string]: any } } | { keys: ((defaultCacheKeys: { [key: string]: any }, absoluteFilename: string) => Promise<{ [key: string]: any }>) }} TransformerCacheObject
*/
/**
* @typedef {Object} TransformerObject
* @property {TransformerFunction} transformer
* @property {boolean | TransformerCacheObject} [cache]
*/
/**
* @typedef {TransformerFunction | TransformerObject} Transform
*/
/**
* @callback Filter
* @param {string} filepath
* @returns {boolean | Promise<boolean>}
*/
/**
* @callback TransformAllFunction
* @param {{ data: Buffer, sourceFilename: string, absoluteFilename: string }[]} data
* @returns {string | Buffer | Promise<string> | Promise<Buffer>}
*/
/**
* @typedef { Record<string, any> | ((item: { absoluteFilename: string, sourceFilename: string, filename: string, toType: ToType }) => Record<string, any>) } Info
*/
/**
* @typedef {Object} ObjectPattern
* @property {From} from
* @property {GlobbyOptions} [globOptions]
* @property {Context} [context]
* @property {To} [to]
* @property {ToType} [toType]
* @property {Info} [info]
* @property {Filter} [filter]
* @property {Transform} [transform]
* @property {TransformAllFunction} [transformAll]
* @property {Force} [force]
* @property {number} [priority]
* @property {NoErrorOnMissing} [noErrorOnMissing]
*/
/**
* @typedef {StringPattern | ObjectPattern} Pattern
*/
/**
* @typedef {Object} AdditionalOptions
* @property {number} [concurrency]
*/
/**
* @typedef {Object} PluginOptions
* @property {Pattern[]} patterns
* @property {AdditionalOptions} [options]
*/
declare class CopyPlugin {

@@ -131,3 +28,3 @@ /**

* @private
* @param {typeof import("globby").globby} globby
* @param {typeof import("tinyglobby").glob} globby
* @param {Compiler} compiler

@@ -137,2 +34,3 @@ * @param {Compilation} compilation

* @param {CacheFacade} cache
* @param {number} concurrency
* @param {ObjectPattern & { context: string }} inputPattern

@@ -142,7 +40,7 @@ * @param {number} index

*/
private static runPattern;
private static glob;
/**
* @param {PluginOptions} [options]
*/
constructor(options?: PluginOptions | undefined);
constructor(options?: PluginOptions);
/**

@@ -171,3 +69,2 @@ * @private

GlobbyOptions,
GlobEntry,
WebpackLogger,

@@ -204,4 +101,3 @@ CacheFacade,

type Asset = import("webpack").Asset;
type GlobbyOptions = import("globby").Options;
type GlobEntry = import("globby").GlobEntry;
type GlobbyOptions = import("tinyglobby").GlobOptions;
type WebpackLogger = ReturnType<Compilation["getLogger"]>;

@@ -275,3 +171,3 @@ type CacheFacade = ReturnType<Compilation["getCache"]>;

from: From;
globOptions?: import("globby").Options | undefined;
globOptions?: import("tinyglobby").GlobOptions | undefined;
context?: string | undefined;

@@ -278,0 +174,0 @@ to?: To | undefined;