将现有单个文件或整个目录复制到构建目录。
首先,你需要安装 copy-webpack-plugin
npm install copy-webpack-plugin --save-dev
或
yarn add -D copy-webpack-plugin
或
pnpm add -D copy-webpack-plugin
然后将插件添加到你的 webpack
配置中。例如:
webpack.config.js
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{ from: "source", to: "dest" },
{ from: "other", to: "public" },
],
}),
],
};
[!注意]
copy-webpack-plugin
的设计目的不是复制构建过程中生成的文件。相反,它旨在复制源目录中已存在的文件,作为构建过程的一部分。
[!注意]
如果你希望
webpack-dev-server
在开发过程中将文件写入输出目录,你可以启用writeToDisk
选项或使用write-file-webpack-plugin
。
[!注意]
你可以从 webpack 统计信息 API 中的 资产对象 中获取原始源文件名。
插件用法
webpack.config.js
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{ from: "source", to: "dest" },
"path/to/source", // Absolute or relative path, can be files, directories or globs. See examples below.
],
options: {
concurrency: 100,
},
}),
],
};
模式
from
to
context
globOptions
filter
toType
force
priority
transform
transformAll
noErrorOnMissing
info
源
类型
type from = string;
默认值:undefined
要复制文件的 glob 或路径。glob 遵循 fast-glob 模式语法。注意:glob 必须是 string
类型。
[!警告]
如果
from
选项是glob
模式(即path\to\file.ext
),请不要直接在其中使用\\
,因为在 UNIX 系统上,反斜杠被视为普通字符(而不是路径分隔符)。在 Windows 上,正斜杠和反斜杠都用作分隔符。请改用/
,或使用 Node 的path
工具来规范化路径。
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: "**/*",
},
// If absolute path is a `glob` we replace backslashes with forward slashes, because only forward slashes can be used in the `glob`
path.posix.join(
path.resolve(__dirname, "src").replace(/\\/g, "/"),
"*.txt",
),
],
}),
],
};
适用于 Windows
如果你在 Windows
上的 from
选项中使用绝对文件或文件夹路径,可以使用 Windows 路径分隔符 (\\
)
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, "file.txt"),
},
],
}),
],
};
然而,在编写 glob
表达式时,请始终使用正斜杠。有关更多详细信息,请参阅 fast-glob 手册。
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
// If absolute path is a `glob` we replace backslashes with forward slashes, because only forward slashes can be used in the `glob`
from: path.posix.join(
path.resolve(__dirname, "fixtures").replace(/\\/g, "/"),
"*.txt",
),
},
],
}),
],
};
context
选项的行为取决于 from
值是 glob
、file
还是 dir
。查看更多示例
。
目标
类型
type to =
| string
| ((pathData: { context: string; absoluteFilename?: string }) => string);
默认值:compiler.options.output
string
指定输出路径。
[!警告]
不要直接在
to
路径(即path\to\dest
)选项中使用\\
,因为在 UNIX 系统上,反斜杠被视为普通字符(而不是路径分隔符)。在 Windows 上,正斜杠和反斜杠都用作分隔符。请改用/
,或使用 Node 的path
工具来规范化路径。
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
允许修改写入路径。
[!警告]
不要直接在
to
路径(即path\to\newFile
)选项中使用\\
,因为在 UNIX 系统上,反斜杠被视为普通字符(而不是路径分隔符)。在 Windows 上,正斜杠和反斜杠都用作分隔符。请改用/
,或使用 Node 的path
工具来规范化路径。
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 context = string;
默认值:options.context|compiler.options.context
定义用于两个目的的基础目录
它被前置到 from
路径。
它从结果路径的开头移除。
[!警告]
不要直接在
to
路径(即path\to\newFile
)选项中使用\\
,因为在 UNIX 系统上,反斜杠被视为普通字符(而不是路径分隔符)。在 Windows 上,正斜杠和反斜杠都用作分隔符。请改用/
,或使用 Node 的path
工具来规范化路径。
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/*.txt",
to: "dest/",
context: "app/",
},
],
}),
],
};
context
可以是绝对路径或相对路径。如果它是相对路径,则会基于 compiler.options.context
转换为绝对路径。
当 from
使用 glob 模式时,你应该明确定义 context
。否则,插件将根据 from
的性质自动设置它。
如果 from
是文件,则 context
默认为文件所在目录。结果路径将仅是文件名。
如果 from
是目录,context
将设置为同一目录。结果路径将包含该目录的内容(包括子目录),相对于它。
context
的用法通过这些 示例
进行了说明。
globOptions
[!警告]
onlyDirectories 无效,因为此插件旨在复制文件,而非单独复制目录。
类型
type globOptions = import("tinyglobby").GlobOptions;
默认值:undefined
允许你配置插件使用的 glob 模式匹配库。查看支持的选项列表。要排除要复制的文件,请使用 globOptions.ignore 选项。
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "public/**/*",
globOptions: {
dot: true,
gitignore: true,
ignore: ["**/file.*", "**/ignored-directory/**"],
},
},
],
}),
],
};
filter
类型
type filter = (filepath: string) => boolean;
默认值:undefined
[!注意]
要按路径(例如,按扩展名或名称)忽略文件,请优先使用 [
globOptions.ignore
] 选项。
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 toType = "dir" | "file" | "template";
默认值:undefined
确定 to
选项的类型——它是目录、文件还是模板。有时很难判断 to
是什么,例如 path/to/dir-with.ext
。如果你想将文件复制到目录中,应该明确将类型设置为 dir
。在大多数情况下,插件会自动确定正确的 type
,因此你通常不需要手动设置此选项。
名称 | 类型 | 默认值 | 描述 |
---|---|---|---|
'dir' | string | undefined | 使用的 to 没有扩展名或以 '/' 结尾。 |
'file' | string | undefined | 当 to 是一个文件路径,而不是目录或模板时使用。 |
'template' | string | undefined | 当 to 包含 模板模式 时使用。 |
'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 force = boolean;
默认值:false
覆盖 compilation.assets
中已存在的文件(通常由其他插件或加载器添加)。
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/**/*",
to: "dest/",
force: true,
},
],
}),
],
};
priority
类型
type priority = number;
默认值:0
允许指定具有相同目标文件名的文件复制优先级。优先级较高的模式的文件将稍后复制。要启用覆盖,必须将 force
选项设置为 true
。webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
// Copied second and will overwrite "dir_2/file.txt"
{
from: "dir_1/file.txt",
to: "newfile.txt",
force: true,
priority: 10,
},
// Copied first
{
from: "dir_2/file.txt",
to: "newfile.txt",
priority: 5,
},
],
}),
],
};
transform
类型
type transform =
| {
transformer: (input: string, absoluteFilename: string) => string | Buffer;
cache?: boolean | TransformerCacheObject | undefined;
}
| ((input: string, absoluteFilename: string) => string | Buffer);
默认值:undefined
允许你在文件写入输出目录之前修改其内容。
function
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/*.png",
to: "dest/",
// The `content` argument is a [`Buffer`](https://node.org.cn/api/buffer.html) object, it could be converted to a `String` to be processed using `content.toString()`
// The `absoluteFrom` argument is a `String`, it is absolute path from where the file is being copied
transform(content, absoluteFrom) {
return optimize(content);
},
},
],
}),
],
};
object
名称 | 默认值 | 描述 |
---|---|---|
transformer | undefined | 允许你修改文件内容。 |
cache | false | 为 transform 启用缓存。你可以使用 transform: { cache: { key: 'my-cache-key' } } 在需要时手动使缓存失效。 |
transformer
类型
type transformer = (input: string, absoluteFilename: string) => string;
默认值:undefined
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/*.png",
to: "dest/",
// The `content` argument is a [`Buffer`](https://node.org.cn/api/buffer.html) object, it could be converted to a `String` to be processed using `content.toString()`
// The `absoluteFrom` argument is a `String`, it is absolute path from where the file is being copied
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 cache =
| boolean
| {
keys: {
[key: string]: any;
};
}
| {
keys: (
defaultCacheKeys: {
[key: string]: any;
},
absoluteFilename: string,
) => Promise<{
[key: string]: any;
}>;
}
| undefined;
默认值:false
webpack.config.js
启用或禁用缓存并配置其行为。默认情况下,缓存目录位于:node_modules/.cache/copy-webpack-plugin
。
boolean
启用/禁用 transform
缓存。
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/*.png",
to: "dest/",
transform: {
transformer(content, path) {
return optimize(content);
},
cache: true,
},
},
],
}),
],
};
object
启用 transform
缓存并设置失效键。
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/*.png",
to: "dest/",
transform: {
transformer(content, path) {
return optimize(content);
},
cache: {
keys: {
// May be useful for invalidating cache based on external values
// For example, you can invalid cache based on `process.version` - { node: process.version }
key: "value",
},
},
},
},
],
}),
],
};
你可以使用函数设置失效键。
简单函数
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,
};
},
},
},
},
],
}),
],
};
异步函数
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 transformAll = (
data: {
data: Buffer;
sourceFilename: string;
absoluteFilename: string;
}[],
) => any;
默认值:undefined
允许你修改多个文件的内容并将合并结果保存到一个文件中。
[!注意]
必须指定
to
选项并指向一个文件。文件名中只允许使用[contenthash]
和[fullhash]
模板字符串。
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/**/*.txt",
to: "dest/file.txt",
// The `assets` argument is an array of assets matched by the pattern `from` ("src/**/*.txt")
transformAll(assets) {
const result = assets.reduce((accumulator, asset) => {
// The asset content can be obtained from `asset.source` using `source` method.
// The asset content is a [`Buffer`](https://node.org.cn/api/buffer.html) object, it could be converted to a `String` to be processed using `content.toString()`
const content = asset.data;
accumulator = `${accumulator}${content}\n`;
return accumulator;
}, "");
return result;
},
},
],
}),
],
};
noErrorOnMissing
类型
type noErrorOnMissing = boolean;
默认值:false
如果文件缺失,不生成错误。
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, "missing-file.txt"),
noErrorOnMissing: true,
},
],
}),
],
};
info
类型
type info =
| Record<string, any>
| ((item: {
absoluteFilename: string;
sourceFilename: string;
filename: string;
toType: ToType;
}) => Record<string, any>);
默认值:undefined
允许添加资产信息。
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
"relative/path/to/file.ext",
{
from: "**/*",
// Terser skip this file for minification
info: { minimized: true },
},
],
}),
],
};
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
"relative/path/to/file.ext",
{
from: "**/*",
// Terser skip this file for minimization
info: (file) => ({ minimized: true }),
},
],
}),
],
};
concurrency
type
type concurrency = number;
默认值:100
限制同时对文件系统进行请求的数量。
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [...patterns],
options: { concurrency: 50 },
}),
],
};
from
的不同变体(glob
、file
或 dir
)。考虑以下文件结构
src/directory-nested/deep-nested/deepnested-file.txt
src/directory-nested/nested-file.txt
你在 from
中指定的所有内容都将包含在结果中
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/directory-nested/**/*",
},
],
}),
],
};
结果
src/directory-nested/deep-nested/deepnested-file.txt,
src/directory-nested/nested-file.txt
如果你不希望结果路径以 src/directory-nested/
开头,那么你应该将 src/directory-nested/
移动到 context
,这样 from
中只剩下 glob 模式 **/*
。
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "**/*",
context: path.resolve(__dirname, "src", "directory-nested"),
},
],
}),
],
};
结果
deep-nested/deepnested-file.txt,
nested-file.txt
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, "src", "directory-nested"),
},
],
}),
],
};
结果
deep-nested/deepnested-file.txt,
nested-file.txt
从技术上讲,这等同于使用 **/*
并将预定义上下文设置为指定目录。
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "**/*",
context: path.resolve(__dirname, "src", "directory-nested"),
},
],
}),
],
};
结果
deep-nested/deepnested-file.txt,
nested-file.txt
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: path.resolve(
__dirname,
"src",
"directory-nested",
"nested-file.txt",
),
},
],
}),
],
};
结果
nested-file.txt
从技术上讲,这是一个文件名,其预定义上下文等于文件所在目录 path.dirname(pathToFile)
。
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "nested-file.txt",
context: path.resolve(__dirname, "src", "directory-nested"),
},
],
}),
],
};
结果
nested-file.txt
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: path.posix.join(
path.resolve(__dirname, "src").replace(/\\/g, "/"),
"**/*",
),
globOptions: {
ignore: [
// Ignore all `txt` files
"**/*.txt",
// Ignore all files in all subdirectories
"**/subdir/**",
],
},
},
],
}),
],
};
移除所有目录引用,只复制文件名。
[!警告]
如果文件同名,结果将是不确定的。
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/**/*",
to: "[name][ext]",
},
],
}),
],
};
结果
file-1.txt
file-2.txt
nested-file.txt
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
// When copying files starting with a dot, must specify the toType option
// toType: "file",
to({ context, absoluteFilename }) {
return `newdirectory/${path.relative(context, absoluteFilename)}`;
},
from: "directory",
},
],
}),
],
};
结果
"newdirectory/file-1.txt",
"newdirectory/nestedfile.txt",
"newdirectory/nested/deep-nested/deepnested.txt",
"newdirectory/nested/nestedfile.txt",
如果你需要简单地将 *.js
文件“原样”复制到目标目录,而无需使用 Terser 对其进行评估和最小化,这会很有用。
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
"relative/path/to/file.ext",
{
from: "**/*",
// Terser skip this file for minimization
info: { minimized: true },
},
],
}),
],
};
yarn workspaces
和 monorepos
当使用 yarn workspaces
或 monorepos
时,由于包提升的方式,从 node_modules
的相对复制路径可能会中断。为避免这种情况,你应该通过使用 require.resolve
明确指定从何处复制文件。
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: `${path.dirname(
require.resolve(`${moduleName}/package.json`),
)}/target`,
to: "target",
},
],
}),
],
};
我们欢迎所有贡献!
如果你是新用户,请在提交问题或拉取请求之前花一些时间阅读我们的贡献指南。