webpack
于2018年2月25日正式发布 v4.0.0
版本,代号 legato
,这将会让 webpack
的配置更加简单,构建速度更快
Webpack4 中文文档
[TOC]
Node.js >= 8.9.4
当使用 webpack4
时,必须保证 Node.js
版本 >= 8.9.4
,因为 webpack4
使用了大量的ES6语法,这些语法在 nodejs新版 v8
中得到了原生支持
npm i webpack webpack-cli -D
webpack4
中 cli 工具分离成了 webpack
核心库 与 webpack-cli
命令行工具两个模块,需要使用 CLI
,必安装 webpack-cli
至项目中
webpack4
设置了默认值,以便无配置启动项目
entry
默认值是 ./src/
output.path
默认值是 ./dist
mode
默认值是 production
mode: development / production / none
output.pathinfo
在 bundle
中显示模块信息 NamedModulesPlugin
NoEmitOnErrorsPlugin
Scope hoisting
和 Tree-shaking
NoEmitOnErrorsPlugin
ModuleConcatenationPlugin
optimization.minimize
none
会禁用所有的默认设置,可以使用 optimization.*
的方式去设定更详细的配置(搭建你的自定义模式)
新增 optimization.splitChunks
和 optimization.runtimeChunk
来替代 CommonsChunkPlugin
插件,
新增 optimization.noEmitOnErrors
来替代 NoEmitOnErrorsPlugin
插件
新增 optimization.namedModules
来替代 NamedModulesPlugin
插件
内置 optimization.minimize
来压缩代码
默认已支持加载 json
模块,不再需要 json-loader
允许通过ESM语法导入JSON,JSON模块中未使用的部分会被消除
详细升级日志请查看 webpack4.0 升级日志中文版
module.exports = {
// 定义模块引用的绝对路径前缀
context: path.resolve(__dirname, '../'),
// 输入配置
entry: {
// 入口文件,如果是多页项目,可配置多个
app: './src/main.js'
},
// 输出配置
output:{
// 输出目录
path: path.resolve(__dirname, '../dist'),
// 输出文件名 name 为 entry 的 key 值,也可以加上 hash 值, 如:[name].[hash:8].js
filename: '[name].js',
// 构建生成的 js 在html中引用时的路径
publicPath: '/'
},
// 模块引用配置
resolve: {
// 定义模块查找的后缀,方便在代码引用时可省略后缀
extensions: ['.js', '.vue', '.json'],
// 定义引用路径别名 配置别名可以加快webpack查找模块的速度
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
},
// 模块加载配置
module:{
// 指定 不同的模块使用不同的加载器处理
// 以 .css 结尾的文件,使用 css-loader 解析css模块,使用 style-loader 将生成的 css 内容以标签的形式添加到 HTML 文档中
rules:[
{
// 文件匹配正则
test://.css$/,
// 加载器,从后向前倒序使用
loader:['style-loader','css-loader']
}
]
},
// 插件
plugins:{
// 使用 HtmlWebpackPlugin 将构建好的 js/css 嵌入到模板 index.html 中
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
title: '首页',
hash: true,
})
},
// Web服务器配置
devServer:{
contentBase:'../dist',
host:'localhost',
port:'8080',
}
}
使用 HtmlWebpackPlugin
插件,需要npm安装相应模块
// 安装
npm install html-webpack-plugin -D
// 引用
const HtmlWebpackPlugin = require('html-webpack-plugin')
使用 devServer
同样需要安装相关模块
// 安装
npm install webpack-dev-server -D
// 在 package.json 中配置启动脚本
"script": {
"dev": "webpack-dev-server --open --mode development"
}
// 启动 web服务,默认会查找目录下 webpack.config.js 读取其中 devServer 的配置以启动服务
npm run dev
将ES6的代码使用babel转码为浏览器兼容的ES5
{
test: //.js$/,
loader: 'babel-loader',
include: [resolve('src')]
}
babel
的配置在项目根目录下 .babelrc
文件中,如果没有则新建,根据不同的项目要求配置
npm i babel-core babel-loader babel-preset-env babel-preset-stage-2 --save-dev
/.babelrc
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": ["transform-runtime"],
"env": {
"test": {
"presets": ["env", "stage-2"],
"plugins": ["istanbul"]
}
}
}
将 图片 转成 data:base64
,以减少页面中的图片请求
{
test: //.(png|jpe?g|gif|svg)(/?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000, // 只转码 1M以下的图片
name: 'img/[name].[hash:7].[ext]' // 发布到 dist/img 目录下,名称中添加 hash 值,避免缓存
}
},
将less文件编译为css
{
test: //.less$/,
use: ['style-loader', 'css-loader','less-loader']
}
这里先将 less-loader
转 css, 再经过 css-loader
将css模块化并解析其中的 @import
及 url()
,再通过 style-loader
将css嵌入html
webpack.DefinePlugin
用于定义在编译过程中使用的全局变量,常用来定义 process.env
用来区分开发环境和生产环境
const isProduction = process.env.NODE_ENV === 'production'
webpack.HotModuleReplacementPlugin
内置
模块热替换(HMR - Hot Module Replacement)功能会在应用程序运行过程中替换、添加或删除模块,而无需重新加载整个页面
webpack.HashedModuleIdsPlugin
内置
使用 hash
做为模块ID, 避免缓存那些没有变化的模块内容,从而实现更优的缓存策略
用 webpack 实现持久化缓存
extract-text-webpack-plugin
NPM
将所有入口 chunk
中引用的 *.css
,提取合并为独立的css,在 index.html
中使用 link:src
来引用css文件,一般用于生产模式,提取公共的css
copy-webpack-plugin
NPM
应用:将模板 index.html
中引用的静态资源,在构建时复制到 dist
指定目录下
optimize-css-assets-webpack-plugin
NPM
压缩css, 同时去除重复的样式,减少CSS打包后的体积
vue-cli
项目开发环境的 plugins
配置
plugins: [
new webpack.DefinePlugin({
'process.env': require('../config/dev.env')
}),
new webpack.HotModuleReplacementPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
favicon: resolve('favicon.ico'),
inject: true
}),
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.dev.assetsSubDirectory,
ignore: ['.*']
}
])
]
vue-cli
项目生产环境的 plugins
配置
plugins: [
new webpack.DefinePlugin({
'process.env': env
}),
new ExtractTextPlugin({
filename: utils.assetsPath('css/[name].css'),
allChunks: true,
}),
new OptimizeCSSPlugin({
cssProcessorOptions: config.build.productionSourceMap
? { safe: true, map: { inline: false } }
: { safe: true }
}),
// see https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: config.build.index,
template: 'index.html',
inject: true,
favicon: resolve('favicon.ico'),
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
},
chunksSortMode: 'dependency'
}),
new webpack.HashedModuleIdsPlugin(),
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
}
])
]
在开发过程中和后台连调时,一般需要解决跨域问题, webpack
提供了 proxy
配置用于,代理 api
请求,屏蔽浏览器跨域限制
proxy: {
'/api': {
target: 'http://192.168.1.12:5000',
pathRewrite: {'^/api' : '/api'},
changeOrigin: true
}
}
当用户访问 /api/getUser
时,代理到 http://192.168.1.12:5000/api/getUser
去请求数据
建议在 webpack
构建流程中使用到的 loaders
及 plugins
都升级到最新版本
安装
如果 pakage.json
中有相应的模块配置,可删除之后重新安装
npm i webpack webpack-cli webpack-dev-server --save-dev
还有以下模块
"copy-webpack-plugin": "^4.0.1", "extract-text-webpack-plugin": "^4.0.0-beta.0", "html-webpack-plugin": "^3.1.0", "optimize-css-assets-webpack-plugin": "^4.0.0", "webpack-bundle-analyzer": "^2.11.1", "webpack-dev-middleware": "^3.1.2", "webpack-dev-server": "^3.1.3", "webpack-merge": "^4.1.0"
build/webpack.dev.conf.js
中添加 mode
配置
注释掉 webpack.NamedModulesPlugin
及 webpack.NoEmitOnErrorsPlugin
插件,因为 webpack4
开发模式已经内置
module.exports = {
// ...
mode: 'development',
// ...
plugins: {
// new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
// new webpack.NoEmitOnErrorsPlugin(),
}
}
build/webpack.production.conf.js
中添加 mode
与 optimization
配置
同时注释掉 webpack.optimize.CommonsChunkPlugin
、 uglifyjs-webpack-plugin
、 webpack.optimize.ModuleConcatenationPlugin
相关配置及引用
const webpackConfig = merge(baseWebpackConfig, {
// ...
mode: 'production',
// webpack4 内置了 optimization.splitChunks、optimization.runtimeChunk 用来抽取共公代码,优化了缓存策略
optimization: {
splitChunks: {
cacheGroups: {
vendors: {
test: /[///]node_modules[///]/,
chunks: 'initial',
name: 'vendors',
},
'async-vendors': {
test: /[///]node_modules[///]/,
minChunks: 2,
chunks: 'async',
name: 'async-vendors'
}
}
},
runtimeChunk: { name: 'runtime' }
},
// ...
}
经过上面三步, vue-cli
项目升级 webpack4.x
就完成了
需要注意的是当前项目一定要是较新的 webpack
模板生成的项目,是不是新模板,可以查看 package.json
中 scripts.dev
是否是使用 webpack-dev-server
启动的,如果是,则为新的模板
HappyPack就能让Webpack把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程
npm i happypack@5.0.0-beta.3 --save-dev
const HappyPack = require('happypack')
const os = require('os')
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length })
{
test: //.js$/,
// loader: 'babel-loader',
loader: 'happypack/loader?id=happy-babel-js', // 增加新的HappyPack构建loader
include: [resolve('src')],
exclude: /node_modules/,
}
plugins: [
new HappyPack({
id: 'happy-babel-js',
loaders: ['babel-loader?cacheDirectory=true'],
threadPool: happyThreadPool
})
]
忽略对已知文件的解析: 一个模块中没有其它新的依赖 就可以配置这项,webpack 将不再扫描这个文件中的依赖
resolve: {
alias: {
moment: "moment/min/moment-with-locales.min.js"
}
},
module: {
noParse: [/moment-with-locales/]
}
webpack
检查到 entry.js
文件对 moment
的请求 alias
重定向,转而请求 moment/min/moment-with-locales.min.js
noParse
规则中的 /moment-with-locales/
一条生效,所以 webpack
就直接把依赖打包进了 bundle.js
eval: 生成代码 每个模块都被eval执行,并且存在@sourceURL cheap-eval-source-map: 转换代码(行内) 每个模块被eval执行,并且sourcemap作为eval的一个dataurl cheap-module-eval-source-map: 原始代码(只有行内) 同样道理,但是更高的质量和更低的性能 eval-source-map: 原始代码 同样道理,但是最高的质量和最低的性能 cheap-source-map: 转换代码(行内) 生成的sourcemap没有列映射,从loaders生成的sourcemap没有被使用 cheap-module-source-map: 原始代码(只有行内) 与上面一样除了每行特点的从loader中进行映射 source-map: 原始代码 最好的sourcemap质量有完整的结果,但是会很慢
当我们不需要调试时,可以关掉 sourcemap
或降低 sourcemap
的级别来加快打包的速度
使用CDN
在 webpack.config.js
中配置模块变量为外部依赖
externals: {
moment: true
}
在 index.html
中添加资源引用
<script src="//apps.bdimg.com/libs/moment/2.8.3/moment-with-locales.min.js"></script>
使用静态资源
有时候,由于网络限制,不允许使用CDN资源,又不想经过Webpack打包,则可以将资源直接引入 index.html
,在 webpack build
配合 copy-webpack-plugin
插件,将资源复制到 dist
目录下,例 vue-cli 生成的项目根目录下的 static
目录就是用来放这类静态资源的
cacheDirectory
: 指定的目录将用来缓存 loader
的执行结果。之后的 webpack
构建,将会尝试读取缓存,来避免在每次执行时,可能产生的、高性能消耗的 Babel
重新编译过程
{
test: //.js$/,
loader: 'babel-loader?cacheDirectory',
exclude: /node_modules/,
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
官方文档中表示设置 cacheDirectory
可将 babel-loader
提速至少两倍
深入浅出Webpack
vue cli 平稳升级webapck4
Webpack4 那点儿东西
30分钟快速了解webpack