CopyWebpackPlugin

免责声明:CopyWebpackPlugin 是由社区成员维护的第三方包,它可能不支持 webpack 的相同支持、安全策略或许可证,并且它不是由 webpack 维护的。

npm node tests cover discussion size

将已存在的单个文件或整个目录复制到构建目录。

入门

首先,你需要安装 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 的内容(globfiledir)而有所不同。更多 示例

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
名称默认值描述
转换器未定义允许修改文件内容。
cachefalse启用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的不同变体(globfiledir)。

以以下文件结构为例

src/directory-nested/deep-nested/deepnested-file.txt
src/directory-nested/nested-file.txt
From 是 Glob

你在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",

跳过通过最小化程序运行 JavaScript 文件

如果你需要简单地将 *.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 workspacesmonorepos

使用 yarn workspacesmonorepos 时,由于包提升的方式,来自 node_modules 的相对复制路径可能会中断。为避免这种情况,应使用 require.resolve 明确指定从何处复制文件。

webpack.config.js

module.exports = {
  plugins: [
    new CopyPlugin({
      patterns: [
        {
          from: `${path.dirname(
            require.resolve(`${moduleName}/package.json`),
          )}/target`,
          to: "target",
        },
      ],
    }),
  ],
};

贡献

如果你尚未阅读我们的贡献指南,请花点时间阅读。

贡献

许可证

MIT