copy-webpack-plugin
Copies individual files or entire directories, which already exist, to the build directory.
Getting Started
To begin, you'll need to install copy-webpack-plugin
:
npm install copy-webpack-plugin --save-dev
or
yarn add -D copy-webpack-plugin
or
pnpm add -D copy-webpack-plugin
Then add the plugin to your webpack
config. For example:
webpack.config.js
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{ from: "source", to: "dest" },
{ from: "other", to: "public" },
],
}),
],
};
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
If you want webpack-dev-server
to write files to the output directory during development, you can force it with the writeToDisk
option or the write-file-webpack-plugin
.
Note
You can get the original source filename from Asset Objects.
Options
The plugin's signature:
webpack.config.js
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{ from: "source", to: "dest" },
"path/to/source",
],
options: {
concurrency: 100,
},
}),
],
};
Patterns
from
Type:
type from = string;
Default: undefined
Glob or path from where we copy files.
Globs accept fast-glob pattern-syntax.
Glob can only be a string
.
Warning
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.
On Windows, the forward slash and the backward slash are both separators.
Instead please use /
.
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
"relative/path/to/file.ext",
"relative/path/to/dir",
path.resolve(__dirname, "src", "file.ext"),
path.resolve(__dirname, "src", "dir"),
"**/*",
{
from: "**/*",
},
path.posix.join(
path.resolve(__dirname, "src").replace(/\\/g, "/"),
"*.txt",
),
],
}),
],
};
For windows
If you define from
as absolute file path or absolute folder path on Windows
, you can use windows path segment (\\
)
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, "file.txt"),
},
],
}),
],
};
But you should always use forward-slashes in glob
expressions
See fast-glob manual.
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: path.posix.join(
path.resolve(__dirname, "fixtures").replace(/\\/g, "/"),
"*.txt",
),
},
],
}),
],
};
The context
behaves differently depending on what the from
is (glob
, file
or dir
).
More examples
to
Type:
type to =
| string
| ((pathData: { context: string; absoluteFilename?: string }) => string);
Default: compiler.options.output
string
Output path.
Warning
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.
On Windows, the forward slash and the backward slash are both separators.
Instead please use /
or path
methods.
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "**/*",
to: "relative/path/to/dest/",
},
{
from: "**/*",
to: "/absolute/path/to/dest/",
},
{
from: "**/*",
to: "[path][name].[contenthash][ext]",
},
],
}),
],
};
function
Allows to modify the writing path.
Warning
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.
On Windows, the forward slash and the backward slash are both separators.
Instead please use /
or path
methods.
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/*.png",
to({ context, absoluteFilename }) {
return "dest/newPath/[name][ext]";
},
},
],
}),
],
};
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/*.png",
to({ context, absoluteFilename }) {
return Promise.resolve("dest/newPath/[name][ext]");
},
},
],
}),
],
};
context
Type:
type context = string;
Default: options.context|compiler.options.context
A path to be (1) prepended to from
and (2) removed from the start of the result path(s).
Warning
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.
On Windows, the forward slash and the backward slash are both separators.
Instead please use /
or path
methods.
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/*.txt",
to: "dest/",
context: "app/",
},
],
}),
],
};
context
can be an absolute path or a relative path. If it is a relative path, then it will be converted to an absolute path based on compiler.options.context
.
context
should be explicitly set only when from
contains a glob. Otherwise, context
is automatically set, based on whether from
is a file or a directory:
If from
is a file, then context
is its directory. The result path will be the filename alone.
If from
is a directory, then context
equals from
. The result paths will be the paths of the directory's contents (including nested contents), relative to the directory.
The use of context
is illustrated by these examples
.
globOptions
Type:
type globOptions = import("globby").Options;
Default: undefined
Allows to configure the glob pattern matching library used by the plugin. See the list of supported options
To exclude files from the selection, you should use globOptions.ignore option
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "public/**/*",
globOptions: {
dot: true,
gitignore: true,
ignore: ["**/file.*", "**/ignored-directory/**"],
},
},
],
}),
],
};
filter
Type:
type filter = (filepath: string) => boolean;
Default: undefined
Note
To ignore files by path please use the globOptions.ignore
option.
webpack.config.js
const fs = require("fs").promise;
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "public/**/*",
filter: async (resourcePath) => {
const data = await fs.promises.readFile(resourcePath);
const content = data.toString();
if (content === "my-custom-content") {
return false;
}
return true;
},
},
],
}),
],
};
toType
Type:
type toType = "dir" | "file" | "template";
Default: undefined
Determinate what is to
option - directory, file or template.
Sometimes it is hard to say what is to
, example path/to/dir-with.ext
.
If you want to copy files in directory you need use dir
option.
We try to automatically determine the type
so you most likely do not need this option.
Name | Type | Default | Description |
---|
'dir' | string | undefined | If to has no extension or ends on '/' |
'file' | string | undefined | If to is not a directory and is not a template |
'template' | string | undefined | If to contains a template pattern |
'dir'
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "path/to/file.txt",
to: "directory/with/extension.ext",
toType: "dir",
},
],
}),
],
};
'file'
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "path/to/file.txt",
to: "file/without/extension",
toType: "file",
},
],
}),
],
};
'template'
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/",
to: "dest/[name].[contenthash][ext]",
toType: "template",
},
],
}),
],
};
force
Type:
type force = boolean;
Default: false
Overwrites files already in compilation.assets
(usually added by other plugins/loaders).
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/**/*",
to: "dest/",
force: true,
},
],
}),
],
};
priority
Type:
type priority = number;
Default: 0
Allows to specify the priority of copying files with the same destination name.
Files for patterns with higher priority will be copied later.
To overwrite files, the force
option must be enabled.
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "dir_1/file.txt",
to: "newfile.txt",
force: true,
priority: 10,
},
{
from: "dir_2/file.txt",
to: "newfile.txt",
priority: 5,
},
],
}),
],
};
transform
Type:
type transform =
| {
transformer: (input: string, absoluteFilename: string) => string | Buffer;
cache?: boolean | TransformerCacheObject | undefined;
}
| ((input: string, absoluteFilename: string) => string | Buffer);
Default: undefined
Allows to modify the file contents.
function
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/*.png",
to: "dest/",
transform(content, absoluteFrom) {
return optimize(content);
},
},
],
}),
],
};
object
Name | Default | Description |
---|
transformer | undefined | Allows to modify the file contents. |
cache | false | Enable transform caching. You can use transform: { cache: { key: 'my-cache-key' } } to invalidate the cache. |
transformer
Type:
type transformer = (input: string, absoluteFilename: string) => string;
Default: undefined
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/*.png",
to: "dest/",
transform: {
transformer(content, absoluteFrom) {
return optimize(content);
},
},
},
],
}),
],
};
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/*.png",
to: "dest/",
transform: {
transformer(content, path) {
return Promise.resolve(optimize(content));
},
},
},
],
}),
],
};
cache
Type:
type cache =
| boolean
| {
keys: {
[key: string]: any;
};
}
| {
keys: (
defaultCacheKeys: {
[key: string]: any;
},
absoluteFilename: string,
) => Promise<{
[key: string]: any;
}>;
}
| undefined;
Default: false
webpack.config.js
Enable/disable and configure caching.
Default path to cache directory: node_modules/.cache/copy-webpack-plugin
.
boolean
Enables/Disable transform
caching.
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/*.png",
to: "dest/",
transform: {
transformer(content, path) {
return optimize(content);
},
cache: true,
},
},
],
}),
],
};
object
Enables transform
caching and setup invalidation keys.
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/*.png",
to: "dest/",
transform: {
transformer(content, path) {
return optimize(content);
},
cache: {
keys: {
key: "value",
},
},
},
},
],
}),
],
};
You can setup invalidation keys using a function.
Simple function:
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/*.png",
to: "dest/",
transform: {
transformer(content, path) {
return optimize(content);
},
cache: {
keys: (defaultCacheKeys, absoluteFrom) => {
const keys = getCustomCacheInvalidationKeysSync();
return {
...defaultCacheKeys,
keys,
};
},
},
},
},
],
}),
],
};
Async function:
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/*.png",
to: "dest/",
transform: {
transformer(content, path) {
return optimize(content);
},
cache: {
keys: async (defaultCacheKeys, absoluteFrom) => {
const keys = await getCustomCacheInvalidationKeysAsync();
return {
...defaultCacheKeys,
keys,
};
},
},
},
},
],
}),
],
};
transformAll
Type:
type transformAll = (
data: {
data: Buffer;
sourceFilename: string;
absoluteFilename: string;
}[],
) => any;
Default: undefined
Allows you to modify the contents of multiple files and save the result to one file.
Note
The to
option must be specified and point to a file. It is allowed to use only [contenthash]
and [fullhash]
template strings.
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/**/*.txt",
to: "dest/file.txt",
transformAll(assets) {
const result = assets.reduce((accumulator, asset) => {
const content = asset.data;
accumulator = `${accumulator}${content}\n`;
return accumulator;
}, "");
return result;
},
},
],
}),
],
};
noErrorOnMissing
Type:
type noErrorOnMissing = boolean;
Default: false
Doesn't generate an error on missing file(s).
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, "missing-file.txt"),
noErrorOnMissing: true,
},
],
}),
],
};
info
Type:
type info =
| Record<string, any>
| ((item: {
absoluteFilename: string;
sourceFilename: string;
filename: string;
toType: ToType;
}) => Record<string, any>);
Default: undefined
Allows to add assets info.
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
"relative/path/to/file.ext",
{
from: "**/*",
info: { minimized: true },
},
],
}),
],
};
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
"relative/path/to/file.ext",
{
from: "**/*",
info: (file) => ({ minimized: true }),
},
],
}),
],
};
Options
concurrency
type:
type concurrency = number;
default: 100
limits the number of simultaneous requests to fs
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [...patterns],
options: { concurrency: 50 },
}),
],
};
Examples
Different variants of from
(glob
, file
or dir
).
Take for example the following file structure:
src/directory-nested/deep-nested/deepnested-file.txt
src/directory-nested/nested-file.txt
From is a Glob
Everything that you specify in from
will be included in the result:
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/directory-nested/**/*",
},
],
}),
],
};
Result:
src/directory-nested/deep-nested/deepnested-file.txt,
src/directory-nested/nested-file.txt
If you don't want the result paths to start with src/directory-nested/
, then you should move src/directory-nested/
to context
, such that only the glob pattern **/*
remains in from
:
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "**/*",
context: path.resolve(__dirname, "src", "directory-nested"),
},
],
}),
],
};
Result:
deep-nested/deepnested-file.txt,
nested-file.txt
From is a Dir
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, "src", "directory-nested"),
},
],
}),
],
};
Result:
deep-nested/deepnested-file.txt,
nested-file.txt
Technically, this is **/*
with a predefined context equal to the specified directory.
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "**/*",
context: path.resolve(__dirname, "src", "directory-nested"),
},
],
}),
],
};
Result:
deep-nested/deepnested-file.txt,
nested-file.txt
From is a File
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: path.resolve(
__dirname,
"src",
"directory-nested",
"nested-file.txt",
),
},
],
}),
],
};
Result:
nested-file.txt
Technically, this is a filename with a predefined context equal to path.dirname(pathToFile)
.
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "nested-file.txt",
context: path.resolve(__dirname, "src", "directory-nested"),
},
],
}),
],
};
Result:
nested-file.txt
Ignoring files
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: path.posix.join(
path.resolve(__dirname, "src").replace(/\\/g, "/"),
"**/*",
),
globOptions: {
ignore: [
"**/*.txt",
"**/subdir/**",
],
},
},
],
}),
],
};
Flatten copy
Removes all directory references and only copies file names.
Warning
If files have the same name, the result is non-deterministic.
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/**/*",
to: "[name][ext]",
},
],
}),
],
};
Result:
file-1.txt
file-2.txt
nested-file.txt
Copy in new directory
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
to({ context, absoluteFilename }) {
return `newdirectory/${path.relative(context, absoluteFilename)}`;
},
from: "directory",
},
],
}),
],
};
Result:
"newdirectory/file-1.txt",
"newdirectory/nestedfile.txt",
"newdirectory/nested/deep-nested/deepnested.txt",
"newdirectory/nested/nestedfile.txt",
Skip running JavaScript files through a minimizer
Useful if you need to simply copy *.js
files to destination "as is" without evaluating and minimizing them using Terser.
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
"relative/path/to/file.ext",
{
from: "**/*",
info: { minimized: true },
},
],
}),
],
};
yarn workspaces
and monorepos
When using yarn workspaces
or monorepos
, relative copy paths from node_modules can be broken due to the way packages are hoisting.
To avoid this, should explicitly specify where to copy the files from using require.resolve
.
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: `${path.dirname(
require.resolve(`${moduleName}/package.json`),
)}/target`,
to: "target",
},
],
}),
],
};
Contributing
Please take a moment to read our contributing guidelines if you haven't yet done so.
CONTRIBUTING
License
MIT