wabpack 中 loader 和 plugins 的区别
前言
webpack 是现在最流行的打包工具。使用过 webpack 的人对 loader 与 plugins 一定不会陌生。虽然在 webpack 中万物皆模块,但是 webpack 真正认识的也只不过 js 文件而已。那么其他的文件比如 CSS 或者图片也想打包成模块应该怎么办呢,这就需要借助 loader 工具了。 另外,如果想对文件进行压缩减小体积应该怎么办呢,这时候 plugins 就可以登场了。那么 loader 与 plugins 到底有什么区别呢?
1. loader
1.1 loader 职能
loader 主要提供编译或者转换的职能。
- babel-loader :将 ES6 语法编译成 ES5 语法。
- style-loader 和 css-loader:编译 CSS 语法(前面提到 webpack 只认识 JS 文件)。这两个 loader 可以将 CSS 文件插入到
<style></style>
中。 - postcss-loader:在样式前加浏览器前缀。
- less-loader :将 Less 语法编译成普通的 CSS 语法。
- sass-loader :将 Sass 语法编译成普通的 CSS 语法。
- url-loader :将图片文件转换成 Base64 字符串,这样可以有效地减少 HTTP 请求。
- file-loader :没有转换成 Base64 的文件(通常是比较大的文件)就使用该 loader 进行编译。
url-loader 依赖于 file-loader。其功能是建立在 file-loader 基础之上的。配置 url-loader 时会有一个 limit 属性。假设 limit 属性值为 10000,则表示在10000B以内的文件会转换成 Base 64 字符串。从而减少请求提升性能。而大于 10000B 以内的文件就由 file-loader 从服务器作为静态资源调用。
1.2 loader 配置
配置示例:
module:{
rules:[
{
test: /\.js$/,//正则匹配文件类型
loader: 'babel-loader?cacheDirectory=true',//使用的 loader
include: [
resolve('src'),//包含的文件夹
],
exclude:path.resolve(__dirname, 'node_modules')//排除的文件夹
},
{
test:/\.css$/,
use:[
'style-loader',
'css-loader',
'postcss-loader'
]
},
{
test:/\.(png|svg|jpg|gif)$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
}
]
}
loader 参数解析:
test
表示正则匹配。
loader
表示要使用的loader,babel-loader?cacheDirectory=true
表示未更改的 babel 将会被缓存,可以加快打包速度。
use
表示需要用到的 loader 组。
include
表示只搜索该文件夹下的文件。
exclude
表示排除某个目录下的文件。
options
其他配置项,limit 表示区间值大小限制。比如图片格式配置了此项则在此区间内的图片会转换成 Base 64 字符串,name 表示打包之后的路径及名称。
2. plugins
2.1 plugins 职能
plugins 主要是拓展 webpack 功能,某种程度上也可以理解为是对 webpack 的一种优化。
- html-webpack-plugin:生成 HTML 模板,并将打包后的 JS 和 CSS 文件使用 script 标签和 link 标签引入。
const HtmlWebpackPlugin= require('html-webpack-plugin')
new HtmlWebpackPlugin({
title:"react-app",//生成 html 模板的标题
template:'./index.html',//模板路径
filename:index.html,//模块文件名
inject:true,//向模板中引入静态资源。
//true 表示所有JavaScript资源插入到body元素的底部,
//head 表示所有JavaScript资源插入到body元素的头部 head 中,
//false 表示不会引入静态资源
favicon:false,//添加特定favicon 路径到 html 模板中
hash:true, //是否为静态资源添加hash值
chunks:'all',//是否为模板加入所有的chunks,如果时多页面应用,需要单独配置不同的chunk。
}),
- extract-text-webpack-plugin:将 JS 中的 CSS 抽离出来,成为单独的 CSS 文件,JS 与 CSS 并行下载;
const ExtractTextPlugin = require('extract-text-webpack-plugin')
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",//如果提取失败,就使用 style-loader 提取到页面的style 标签中
use: "css-loader"//使用的 loader 配置
})
}
]
},
plugins: [
new ExtractTextPlugin({
filename: utils.assetsPath('css/[name].[hash].css'),//文件路径
allChunks: true,//是否抽取其他附加的 chunks 的style。
}),
]
- commons-chunk-plugin:提取第三方库或者公共资源到单独的模块,避免 bundle文件过大,导致首屏或者按需加载太慢;在 webpack 4 中使用内置的 splitChunks 进行配置。
output: {
...........
chunkFilename: "[name].[hash:7].chunk.js",
},
new webpack.optimize.CommonsChunkPlugin({
name: 'app',//chunk 名称
async: 'vendor-async',//异步加载children模块
children: true,//通过入口文件抽离chunk,与chunks不能同时设置
chunks:[],//从哪些业务模块中抽离chunk,与children不能同时设置
minChunks: 3//模块被多少个公共chunk引用才被抽离出来作为单独的chunk
}),
- DLLPlugin 和 DllReferencePlugin :对不经常改动的库进行单独配置,减少打包次数。
首先需要单独配置一个webpack.config.dll.js文件,在该文件中配置 DLLPlugin。其次在 package.json 中的 scripts 配置项中添加命令"dll":"node_modules/.bin/webpack --config build/webpack.config.dll.js",
,然后执行该命令。打包生成 manifest.json 文件。
const path = require('path');
const DllPlugin = require('webpack/lib/DllPlugin');
module.exports = {
entry:{
vendor:['vue','element-ui','vue-router','axios'],
},
mode:"production",
output:{
filename:'[name].js',
path: path.resolve(__dirname, '../public/static/lib'),
library:'[name]', //dll的全局变量名
},
plugins:[
new DllPlugin({
name:'[name]', //dll的全局变量名
path:path.join(__dirname,'../public/static/lib','[name].manifest.json'),//描述生成的manifest文件
})
]
}
在 webpack.base.conf 配置中引用 manifest.json 文件。
const manifest = require('../public/static/lib/vendor.manifest.json');
new DllReferencePlugin({
manifest
}),
- optimize-css-assets-webpack-plugin :对 CSS 进行压缩,最小化处理。
new OptimizeCSSPlugin({
assetNameRegExp:/\.css$/g,//正则表达式,匹配需要压缩的资源。
cssProcessor:require('cssnano'),//用于压缩和优化CSS 的处理器。
cssProcessorOptions: { safe: true },
canPrint:true,//表示能否在console.log中打印信息。
}),
- uglifyjs-webpack-plugin :对 JS 进行压缩(webpack 4已废弃,不再维护);在 webpack 4 中使用 teaser-webpack-plugin 进行压缩。
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
optimization: {
minimize: true,
minimizer: [
new UglifyJsPlugin({
test: /\.js(\?.*)?$/i, //测试匹配文件,
include: /\/includes/, //包含哪些文件
excluce: /\/excludes/, //不包含哪些文件
uglifyOptions: {
compress: {
warnings: false //是否有warning提示
}
},
sourceMap: false,//使用sourceMap将错误消息位置映射到模块(这会减慢编译速度)
//允许过滤哪些块应该被压缩(默认情况下,所有块都是会被压缩)。
//返回true以uglify块,否则返回false。
chunkFilter: (chunk) => {
// `vendor` 模块不压缩
if (chunk.name === 'vendor') {
return false;
}
return true;
}
cache: false,//是否启用文件缓存,默认缓存在node_modules/.cache/uglifyjs-webpack-plugin.目录
parallel: true,//使用多进程并行运行来提高构建速度
})],
terser-webpack-plugin 参数同 uglifyjs-webpack-plugin
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
test: /\.js(\?.*)?$/i,//要匹配的文件类型
parallel: true,//使用多进程并行运行来提高构建速度
})],
},
};
2.2 plugins 配置
plugins:[
new HtmlWebpackPlugin({
template:'./index.html',
filename:index.html,
chunks: ['manifest', 'vendor', filename],
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'app',
async: 'vendor-async',
children: true,
minChunks: 3
}),
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false
}
},
sourceMap: config.build.productionSourceMap,
parallel: true
}),
new ExtractTextPlugin({
filename: utils.assetsPath('css/[name].[hash].css'),
allChunks: true,
}),
new OptimizeCSSPlugin({
cssProcessorOptions:{ safe: true }
}),
new DllReferencePlugin({
manifest
}),
]