这是我参与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作为模板。
为了做实验找一些三种类型的文件,在页面中引入其中两个,分别是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方法。
这时,我们重新打包运行后发现,图片出来了,样式也出来了。
但是打开打包目录发现我们txt文件并没有引入也打包进来了,因为刚刚让整个文件夹做了拷贝,里面的所有文件也被拷贝了进来不管你用没用到,接下来,就针对这个问题讲解一下怎么过滤这些文件。
过滤
globOptions
new CopyPlugin({
patterns: [{
// ...
globOptions: {
dot: true,
gitignore: true,
ignore: ["**/omg.*"],
}
}]
}
globOptions是传递给 glob 模式匹配库的选项,我们用ignore把要无视的文件写上就可以不进行拷贝此文件。
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仓库里自行发掘。