webpack文件拷贝插件安装及使用

3,560 阅读4分钟

这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战

介绍

相信很多刚入行的小伙伴搭建webpack时,在模板index.html上引入了一些静态资源,但是打包后发现这些静态资源并没有进入打包目录,这时候我们就要去安装配置相应的文件拷贝的功能了。

本期我们将介绍一种webpack拷贝文件的插件——copy-webpack-plugin,它的作用就是将已存在的单个文件或整个目录复制到构建目录。

安装

# NPM
npm install --save-dev copy-webpack-plugin
# Yarn 
yarn add -D copy-webpack-plugin

使用

因为我们将构建一个单页面应用,所以先建立一个index.html作为模板。

微信截图_20220118162524.png

微信截图_20220118162447.png

为了做实验找一些三种类型的文件,在页面中引入其中两个,分别是png和css,txt我们不引入。

同时我们在css里写了一丢丢样式,方便与之前做对比:

*{
    padding: 0;
    margin: 0;
}

body{
    width: 100%;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: lightblue;
}

img{
    vertical-align: middle;
    width: 90vmin;
    height: 90vmin;
    object-fit: cover;
    box-shadow: 0 0 36px white;
}

接下来,我们就要去写webpack配置文件了。

// webpack.config.js
const plugins = [
  new CleanWebpackPlugin(),
  new HtmlWebpackPlugin({
    filename: "index.html",
    template: path.resolve(__dirname, "public/index.html")
  })
]
module.exports = {
    // ...
    plugins
}

一些基础配置我们在这里不做赘述,现在我们直接运行打包,打开界面会发现一片空白,而且dist目录下也没有出现我们刚才使用过的资源。

现在copy-webpack-plugin就可以闪亮登场了。

先引入copy-webpack-plugin,做以下配置:

// webpack.config.js
const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");
plugins.push(new CopyPlugin({ 
    patterns: [
        {
          noErrorOnMissing: false, // 默认false,不会对丢失的文件产生错误
          force: false, // 默认false,覆盖已经存在的文件
          priority: 0,   // 允许指定复制具有相同目标名称的文件的优先级
          from: path.resolve(__dirname, "public/assets"),  // 拷贝来源
          to: path.resolve(__dirname, "dist/assets"), // 拷贝到的位置
          toType: "dir",  // 目录dir、文件file或模板template
        }
     ],
      options: {
        concurrency: 100,   // 同时请求fs的数量限制
      },
})

我们目的打包时把资源文件夹拷贝到dist里面,还有同时可以发现patterns是数组也就意味着后面可以接很多拷贝的配置,目前只写了一个,至于基础的一些参数已经在注释里讲明,这里注意一下 to的路径分割符不要用\来直接返回,因为在 UNIX 上,反斜杠是路径组件内的有效字符(即它不是分隔符),而在 Windows 上,正斜杠和反斜杠都是分隔符。请改为使用 “/" 或者 path方法。

这时,我们重新打包运行后发现,图片出来了,样式也出来了。

微信截图_20220118145511.png

微信截图_20220118160422.png

但是打开打包目录发现我们txt文件并没有引入也打包进来了,因为刚刚让整个文件夹做了拷贝,里面的所有文件也被拷贝了进来不管你用没用到,接下来,就针对这个问题讲解一下怎么过滤这些文件。

过滤

globOptions

new CopyPlugin({
    patterns: [{
        // ...
        globOptions: {
            dot: true,
            gitignore: true,
            ignore: ["**/omg.*"],
        }
    }]
}

globOptions是传递给 glob 模式匹配库的选项,我们用ignore把要无视的文件写上就可以不进行拷贝此文件。

微信截图_20220118160801.png

filter

new CopyPlugin({
    patterns: [{
        // ...
        filter:async (resourcePath) => {
            const name = await path.basename(resourcePath);
            if(name === "omg.txt") return false
            return true;
          },
        }]
}

filter可以拿到其文件路径,可想而知,文件路径都拿到了就可以为所欲为了,上面是简单做了个判断如果文件名一样就过滤掉。

当然filter里面还可以做很多过滤操作,比如说判断内容是否合规然后去过滤。

举个例子:

const fs = require("fs");
new CopyPlugin({
    patterns: [{
        // ...
        filter: async (resourcePath) => {
            const data = await fs.promises.readFile(resourcePath);
            const content = data.toString();
            if (content === "123") return false;
            return true
        },
}

上面的操作就是读取文件的内容,判断文件内容是否是123这个字符串如果一样那么过滤掉。

注意

如果要开发多个互相依赖的package时,就要用yarn workspacesor或者monorepos,那么在node_modules的相对复制路径可能会由于包的提升方式而被破坏,为避免这种情况,应明确指定使用require.resolve。

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

结语

我们今天简单介绍和使用了一下copy-webpack-plugin这个插件,如果你想从头搭建一套脚手架的话,也是不容错过的。当然今天只是一些皮毛,还用更多的一些配置和使用方法等待你的发掘,可以进入其copy-webpack-plugin仓库里自行发掘。