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