1. 简介
loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。简言之,我们利用 loader 来处理非 js 类型的模块,用 plugin 来简化我们的打包工作。
2. htmlWebpackPlugin
前面,我们将 index.html 放在 src 和 build 目录之外,就是因为考虑到index.html的复用性,不用每次生成 build 文件夹,都要专门手动 copy 一份 index.html 到build。但是事实上,index.html 和index.js一样都属于源文件,应该放在src之下,而输出目录也应该包含 index.html。那么,有没有办法能自动帮我们生成index.html到build目录,帮助我们简化打包流程呢?答案是有的,就是htmlWebpackPlugin插件。
插件也是npm包,使用前需要安装。
cnpm install --save-dev html-webpack-plugin
这个插件会我们自动生成 html 文件到指定目录,并且会自动引入打包好的js脚本和 css 文件。
只需进行如下配置:
var HtmlWebpackPlugin = require('html-webpack-plugin');
var path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build'),
publicPath: 'build/'
},
plugins: [new HtmlWebpackPlugin()],
module: {...} // 这里忽略module详细内容,大家可以参考前面章节补全
};
然后我们开始打包,发现 build 目录下,确实多出了index.html.
并且自动引入了打包好的bundle.js。但是我们打开 index.html。发现页面什么也没有,看一下src 目录的index.html:
发现区别在于 build 目录下的 index.html 少了 id="root"的div。其实,src 下面即使没有index.html文件,打包后同样会生成上述index.html文件。也就是生成的index.html和源文件的html并无关系,这显然不是我们想要的效果。那么有没有办法让生成的 index.html 是根据 src 下的 index.html 内容来决定的呢。答案是有的。
如下,我们在src下面建立一个最简单的html文件,注意我们并不需要显示引入最后的打包js文件,这为我们创造了极大的便利:
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>esmodule-oop</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
然后在配置文件增加如下配置:
plugins: [new HtmlWebpackPlugin({
template: './src/index.html'
})],
再次打包。如下:
竟然还是什么也没有。问题很明显,src引用路径报错了。原因在于3-2 使用loader打包静态资源(图片)
中,为了保证图片的引用地址正确,我们加了publicPath这一配置。当时一笔带过,现在为大家详细讲述一下这个配置的用途。
3. publicPath
为什么有了path的情况下还需要一个publicPath呢。我们先来解释一下什么是path就是输出文件的目标路径,也就是打包好的代码我们能在哪里找到。如果打包好的html文件和其他静态资源都放在一起,在生成资源引用路径时只要按照他们处在同格目录下即可。不管丢到哪里都能正常运行。但事实上,我们生成的html文件,往往和其他资源并不放在一处,另外,它们也并不都是处在同级目录,我们很可能为这些资源文件单独生成一个父目录,然后丢在其他地方。如果这些资源换了位置,那么之前的引用路径就会出错。
publicPath 就是针对这种情况,用来指明资源文件最终的引用地址。它并不影响我们打包文件的输出地址,只是会影响打包后生成文件内的引用路径。如果我们更换了发布时的静态资源服务器地址,只需在打包前修改publicPath即可。
这里,由于html和其他静态资源在一起,我们可以不配置publickPath,也可以如下配置:
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build'),
publicPath: '/webpack-study/build/'
}
这里之所以这么配置,是因为webstorm点开html时,根目录对应整个项目文件的父目录。
当然,更复杂的情况是,我的js文件,css文件,图片文件,并不想放在一起。这种情况是很常见的,就比如我们的图片经常放在cdn。这时,我们就需要区分不同的资源文件,配置不同的publicPath了,如下:
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build')
},
plugins: [new HtmlWebpackPlugin({
template: './src/index.html'
})],
module: {
rules: [
{
test: /\.(jpg|jpeg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]',
limit: 2048,
publicPath: '/images/'
}
}
},
...
]
}
};
js资源和图片资源的引用目录就不一样了。
4. clean-webpack-plugin
这里,再为大家介绍一个简单常用的插件。试想这种情况,我们修改了输出文件的名称,重新打包:
可以看到生成了新的dist.js,但是老的bundle.js也还存在。如果存在多个文件的变动,导致旧的生成文件不需要时,webpack并不能为我们智能的删除。这就会造成无用文件遗留,打包文件增大。最好是,每次生成新的打包文件时,能够先清理一下打包目录。这个时候就可以借助clean-webpack-plugin。
先安装:
cnpm i clean-webpack-plugin -D
用法和html-webpack-plugin类似。
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'dist.js',
path: path.resolve(__dirname, 'build')
},
plugins: [new HtmlWebpackPlugin({
template: './src/index.html'
}), new CleanWebpackPlugin(['build'])],
...
打包,发现报错了。
翻开https://www.npmjs.com/package/clean-webpack-plugin,我们发现原来clean-webpack-plugin插件导出和导入方法已发生变化,改成如下即可:
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
打包后bundle.js不见了。
5 plugins
可以看到,其实plugins就是允许我们在打包的不同阶段,插入一些指定的操作。
参考
https://www.webpackjs.com/concepts/#%E6%8F%92%E4%BB%B6-plugins-
https://www.webpackjs.com/api/plugins/
https://www.webpackjs.com/plugins/
https://www.webpackjs.com/plugins/html-webpack-plugin/
https://www.webpackjs.com/configuration/
https://www.webpackjs.com/guides/output-management/