将已存在的单个文件或整个目录复制到构建目录。
首先,你需要安装 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.config.js
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{ from: "source", to: "dest" },
"path/to/source", // absolute or relative, files/directories/globs - see below for examples
],
options: {
concurrency: 100,
},
}),
],
};
模式
来自
类型
type from = string;
默认值:undefined
从其复制文件的 glob 或路径。Glob 接受 fast-glob 模式语法。Glob 只能是 string
。
警告
如果
from
选项是glob
(即path\to\file.ext
)选项,请不要直接在from
选项中使用\\
,因为在 UNIX 中,反斜杠是路径组件中的有效字符,即它不是分隔符。在 Windows 中,正斜杠和反斜杠都是分隔符。请改用/
。
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
)而有所不同。更多 示例
to
类型
type to =
| string
| ((pathData: { context: string; absoluteFilename?: string }) => string);
默认值:compiler.options.output
字符串
输出路径。
警告
不要在
to
(即path\to\dest
)选项中直接使用\\
,因为在 UNIX 中,反斜杠是路径组件中的有效字符,即它不是分隔符。在 Windows 中,正斜杠和反斜杠都是分隔符。请使用/
或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]",
},
],
}),
],
};
函数
允许修改写入路径。
警告
不要在
to
(即path\to\newFile
)选项中直接返回\\
,因为在 UNIX 中,反斜杠是路径组件中的有效字符,即它不是分隔符。在 Windows 中,正斜杠和反斜杠都是分隔符。请使用/
或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
要 (1) 添加到 from
前面,以及 (2) 从结果路径的开头移除的路径。
警告
不要在
context
(即path\to\context
)选项中直接使用\\
,因为在 UNIX 中,反斜杠是路径组件中的有效字符,即它不是分隔符。在 Windows 中,正斜杠和反斜杠都是分隔符。请使用/
或path
方法。
webpack.config.js
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: "src/*.txt",
to: "dest/",
context: "app/",
},
],
}),
],
};
context
可以是绝对路径或相对路径。如果它是相对路径,则它将基于 compiler.options.context
转换为绝对路径。
仅当 from
包含 glob 时,才应显式设置 context
。否则,context
会根据 from
是文件还是目录自动设置
如果 from
是文件,则 context
是其目录。结果路径将仅为文件名。
如果 from
是目录,则 context
等于 from
。结果路径将是目录内容的路径(包括嵌套内容),相对于目录。
这些 示例
说明了 context
的用法。
globOptions
类型
type globOptions = import("globby").Options;
默认值: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' | 字符串 | 未定义 | 如果 to 没有扩展名或以 '/' 结尾 |
'file' | 字符串 | 未定义 | 如果 to 不是目录也不是模板 |
'template' | 字符串 | 未定义 | 如果 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
选项。
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
名称 | 默认值 | 描述 |
---|---|---|
转换器 | 未定义 | 允许修改文件内容。 |
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 assets array for 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 minimization
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
限制对 fs 的并发请求数量
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",
},
],
}),
],
};
如果你尚未阅读我们的贡献指南,请花点时间阅读。