介绍webpack
webpack诞生之初主要想解决代码拆分问题,是现代JS应用程序的静态模块打包器。
4个核心概念:
-
入口(entry)
指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始 -
输出(output)
webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件 -
loader
由于webpack只能处理javascript,所以我们需要对一些非js文件 处理成webpack能够处理的模块,比如sass文件 -
插件(plugins)
Loaders将各类型的文件处理成webpack能够处理的模块,plugins 有着很强的能力。插件的范围包括,从打包优化和压缩,一直到重新定 义环境中的变量。
安装
$> npm i webpack webpack-cli -D
$> npm i webpack-cli -D
* Tips: webpack4 中 cli 工具分离成了 webpack 核心库 与 webpack-cli 命令行工具两个模块,需要
使用 CLI,必安装 webpack-cli 至项目中
零配置
webpack4 设置了默认值,以便无配置启动项目
- entry 默认值是 ./src/
- output.path 默认值是 ./dist
- mode 默认值是 production
模式
mode: development / production / none
开发模式 development
- 浏览器调试工具
- 注释、开发阶段的详细错误日志和提示
- 快速和优化的增量构建机制
- 开启 output.pathinfo 在 bundle 中显示模块信息
- 开启 NamedModulesPlugin
- 开启 NoEmitOnErrorsPlugin
生产模式 production
- 启用所有优化代码的功能
- 更小的bundle大小
- 去除只在开发阶段运行的代码
- 关闭内存缓存
- Scope hoisting 和 Tree-shaking
- 开启 NoEmitOnErrorsPlugin
- 开启 ModuleConcatenationPlugin
- 开启 optimization.minimize
none 会禁用所有的默认设置,可以使用 optimization.* 的方式去设定更详细的配置(搭建你的自定义模式)
webpack 更新日志
配置更新:
* NoEmitOnErrorsPlugin
-> optimization.noEmitOnErrors(production 模式默认开启)
* ModuleConcatenationPlugin
-> optimization.concatenateModules(production 模式默认开启)
* NameModulesPlugin
-> optimization.nameModules(development 模式默认开启)
* CommonsChunkPlugin已经被移除
-> optimization.splitChunks,optimization.runtimeChunk
* ExtractTextWebpackPlugin调整
-> 建议选用新的CSS文件提取插件mini-css-extract-plugin
JSON:
* webpack现在能处理原生的json
1.当你需要通过loader去把json转换成js的时候,你可能需要添加
type:"javascript/auto"
2.不使用loader也可以直接使用JSON
* 允许通过ESM语法导入JSON
1.JSON模块的未使用的导出部分会被消除
其他相关细节-> webpack更新日志
基本配置 webpack.base.conf.js
1.主入口文件 entry:
entry: {
//入口文件,如果是多页项目,可配置多个
app: '.src/main.js'
}
2.输出文件 output:
output: {
// 导出目录的绝对路径,通过HtmlWebpackPlugin插件生成的html文件
存放在这个目录下面
path: path.resolve(__dirname, '../dist/' + outputDir),
// 生产模式或者开发模式下的html,js等文件内部引用的公共路径
publicPath: '/',
//导出文件的文件名,编译生成的js文件存放到根目录下面的js目录下面,
如果js目录不存在则自动创建
filename: 'js/[name]' + chunkhash + '.js’,
/*
* chunkFilename用来打包require.ensure方法中引入的模块,如果该
方法中没有引入任何模块则不会生成任何chunk块文件
* 比如在main.js文件中,require.ensure([],function(require)
{alert(11);}),这样不会打包块文件
* 只有这样才会打包生成块文件require.ensure([],function(require)
{alert(11);require('./greeter')})
* 或者这样require.ensure(['./greeter'],function(require)
{alert(11);})
* chunk的hash值只有在require.ensure中引入的模块发生变化,hash
值才会改变
* 注意:对于不是在ensure方法中引入的模块,此属性不会生效,只能用
CommonsChunkPlugin插件来提取(webpack 4中用splitChunks&runtimeChunk)
*
*/
chunkFilename: 'js/[name]' + chunkhash + '.js'
},
3.文件解析
resolve: {
//自动解析确定的扩展名,使倒入模块时不带扩展名
extensions: ['.js', '.vue', '.json'],
// 定义引用路径别名 配置别名可以加快webpack查找模块的速度
alias: {
'vue$': 'vue/dist/vue.esm.js’,
'@': path.resolve(__dirname, '../src’),
'src': path.resolve(__dirname, '../src')
}
}
4.模块解析module
{
test: /\.vue$/, //规则对vue后缀
loader: 'vue-loader’, //使用vue-loader进行处理
query:{ //query是对loader做的额外配置
limit: 10000
}
include: /src/, //必须包含src文件夹
}
loader 的用法准则:
1.单一职责,一个loader只做一件事情,这样设计的原因是因为,职责越单一,组合性就强,
可配置性就好。
2.从右到左,链式执行,上一个loader的处理结果传给下一个loader接着处理
3.模块化,一个loader就是一个模块,单独存在不依赖其他的任何模块
4.无状态,就类似于纯函数。
5.loader有实用工具loader-utils解析loader参数的和schema-utils校验格式的
6.loader的依赖
Vue-cli 升级 Q&A
1.webpack4推荐使用了最新版本的vue-loader("vue-loader": "^15.0.10"),
但是最新的vue-loader需要在webapck config文件中设置VueLoaderPlugin插件,
否则会报以下错误:
vue-loader was used without the corresponding plugin.
Make sure to include VueLoaderPlugin in your webpack config.
解决:
const { VueLoaderPlugin } = require('vue-loader');
module.exports = {
...
plugins: [
// 添加VueLoaderPlugin,以响应vue-loader
new VueLoaderPlugin()
],
...
}
2.Error: No PostCSS Config found in…
解决:在项目根目录新建postcss.config.js文件,并对postcss进行配置:
module.exports = {
plugins: [
require('autoprefixer')()
...
]
}
3.关于CSS Modules相关
现在 Vue Loader v15 使用了一个不一样的策略来推导语言块使用的 loader。
拿`< style lang="less" >` 举例:在 v14 或更低版本中,它会尝试使用
less-loader 加载这个块,并在其后面隐式地链上 css-loader
和 vue-style-loader,这一切都使用内联的 loader 字符串。
在 v15 中,`< style lang="less" >` 会完成把它当作一个真实的 *.less 文件
来加载。因此,为了这样处理它,你需要在你的主 webpack 配置中显式地提供一条规则:
{
module: {
rules: [
// ... 其它规则
{
test: /\.less$/,
use: [
'vue-style-loader',
'css-loader',
'less-loader'
]
}
]
}
}
在 v15 中你再也不用在 Vue Loader 自己的 loaders 选项中将它重复一遍~
* 关于 CSS modules: https://juejin.cn/post/6844903624456273927
4.提取 js 中的 css 部分到单独的文件
* 新的替代插件 mini-css-extract-plugin
loader 部分:
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader"
]
}
]
plugins 部分(区分环境决定hash值):
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name]' + hash + '.css',
chunkFilename: 'css/[name]' + hash + '.css'
})
],
5.影响也最大的就是webpack4使用optimization.splitChunks替代了
CommonsChunkPlugin.以前的CommonsChunkPlugin主要用来抽取代码中的共用部分,
webpack runtime之类的代码,结合chunkhash,实现最好的缓存策略。
而optimization.splitChunks则实现了相同的功能,并且配置更加灵活,具体解释如下:
optimization: {
//! 替代 CommonsChunkPlugin 提取公共代码
splitChunks: {
// chunks: "async",
// minSize: 30000, //!块生成最小大小。
// minChunks: 1, //!最小数量的块分裂之前,必须共享一个模块。
// maxAsyncRequests: 5, //!按需加载时并行请求的最大数量。
// maxInitialRequests: 3, //!最大数量的并行请求一个入口点。
// name: true, //!分割块的名称。提供true将根据块和缓存组密钥自动生成名称
//!缓存组会从splitChunks.*中继承相应的选项值,
test、priority和reuseExistingChunk则只能在缓存组层次上配置。
cacheGroups: {
// default: {
// minChunks: 2,
// priority: -20,
// reuseExistingChunk: true
// },
//!"initial"、"async"和"all"。分别用于选择初始块、按需加载的块和所有块。
vendors: {
test: /[\\/]node_modules[\\/]/, //! 不继承
priority: -10, //!不继承,该配置项是设置处理的优先级,数值越大越优先处理
chunks: 'initial',
reuseExistingChunk: true, //!不继承 ,没有默认值,选项用于配置在模块完全
匹配时重用已有的块,而不是创建新块
name: 'vendors',
},
'async-vendors': {
test: /[\\/]node_modules[\\/]/,
minChunks: 2,
chunks: 'async',
reuseExistingChunk: true,
name: 'async-vendors'
},
//!多个css chunk合并成一个css文件
styles: {
name: 'styles',
test: /\.(scss|sass|less|css)$/,
chunks: 'all',
minChunks: 1,
reuseExistingChunk: true
}
}
},
// !分离出webpack编译运行时的代码
runtimeChunk: { name: 'manifest' }
},
* webpack.optimize.UglifyJsPlugin现在也不需要了,只需要使用
optimization.minimize为true就行,
production mode下面自动为true,当然如果想使用第三方的压缩插件也可以
在optimization.minimizer的数组列表中进行配置
/** like this code **/
optimization:{
minimizer: [
new UglifyJsPlugin({
exclude: /\.min\.js$/,
cache: false, //! 文件缓存
parallel: true, //! 利用多进程并行运行提高构建速度
sourceMap: false,
extractComments: false, //! 移除注释
//! uglifyES
uglifyOptions: {
compress: {
warnings: false, //! 在UglifyJs删除没有用到的代码时不输出警告
drop_console: true, //! 删除所有的 `console` 语句,可以兼容ie浏览器
collapse_vars: true, //! 内嵌定义了但是只用到一次的变量
reduce_vars: true //! 提取出出现多次但是没有定义成变量去引用的静态值
},
output: {
beautify: false, //!不需要格式化
comments: false //!不保留注释
}
}
})
]
}
性能优化
* 使用happypack
HappyPack就能让Webpack把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程
* babel-loader设置缓存
cacheDirectory: 指定的目录将用来缓存 loader 的执行结果。之后的 webpack 构建,将会尝试读取缓存,来避免在每次执行时,可能产生的、高性能消耗的 Babel 重新编译过程
Tips
1.建议在 webpack 构建流程中使用到的 loaders 及 plugins 都升级到最新版本,
如果 pakage.json 中有相应的模块配置,可删除之后重新安装
Webpack5展望:
* ESM 模块导出支持
* 持久缓存
* WebAssembly 支持从 experimental 升级为 stable 稳定版。并增加 * tree-shaking 和未使用代码去除!
* Presets —— 基于零配置设计,任何东西都能支持零配置
* CSS 模块类型——支持 CSS 作为入口文件(再见吧 ExtractTextWebpackPlugin)
* HTML 模块类型——支持 HTML 作为入口文件
* URL/文件 模块类型
* 自定义模块类型
* 多线程
* 重新定义我们的组织章程和计划任务
* Google Summer of Code (之后单独写问说明!!!)
参考阅读:
webpack 更新日志-English
webpack4.0 升级日志-中文版
webpack-module官网
webpack 4 发布English
webpack 4 发布