Webpack学习笔记
webpack - 项目优化
webpack实现原理
webpack - loader
webpack - plugin
webpack - 项目优化2
在production模式下,使用import导入的模块会自动shaking-tree,自动作用域提升
node下使用chrome调试
> node --inspect-brk ../mywebpack/bin/main.js
ebugger listening on ws://127.0.0.1:9229/484e409c-5ae8-449a-b24a-9efb4db4f957
For help, see: https://nodejs.org/en/docs/inspector
在chrome中打开chrome://inspect/#devices
webpack-dev-server
一个基于express的静态服务器,对打包后的文件热更新,方便调试
可以webpack.config.js中添加配置
// webpack-dev-server配置
devServer: {
port: 7070,
contentBase: './dist'
}
webpack-dev-server
启动调试
eslint
npm i eslint eslint-loader -D
可以在 https://eslint.org/demo 配置配置文件(当然也可以自己写),下载下来的 eslintrc.config 重命名为.eslintrc.config
{
test: /\.js$/,
use: {
loader: 'eslint-loader',
options: {
enforce: 'pre' // 最先执行,post最后
}
}
}
入口文件中加一句let ttt = 9
。打包后会提示:
/Users/aliya/D/9200/08.02-mywebpack-test/index.js
21:5 error 'ttt' is assigned a value but never used no-unused-vars
多入口,多出口
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: {
home: './index.js',
a: './common/a.js'
},
output: {
// 会根据文件名打包出 home.js、a.js
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new HtmlWebpackPlugin({
filename: 'home.html',
template: './template/index.html',
chunks: ['home'] // 打包出引用了 home.js 的html
}),
new HtmlWebpackPlugin({
filename: 'a.html',
template: './template/index.html',
chunks: ['a'] // 打包出引用了 a.js 的html
})
],
}
source-map
代码经过babel转化和webpack打包后,错误位置指向不准确
在production下打包,所有代码都在一行。使用source-map可以方便调试
// webpack.config.js
...
devtool: 'source-map'
}
- source-map 指向错误代码位置(行列),生成.map文件,很大(6+1k)
- eval-source-map 同上,不单独生成文件,大(3k)
- cheap-module-source-map 不指向错误代码位置(行列),生成.map文件,小(1+1k)
- cheap-module-eval-source-map 你猜
watch (只打包,不会自己刷新浏览器)
// 监控代码改变,动态打包
watch: true,
watchOptions: {
poll: 1000, // 访问1000/s
aggregateTimeout: 500, // 防抖 123 1231234
ignored: /node_modules/, // 不监控的目标
}
webpack-dev-middleware 前后端使用一个端口、解决跨域
官方表示:development only,仅做为一种解决跨域的方法
const webpack = require('webpack');
const middleware = require('webpack-dev-middleware');
const compiler = webpack({
// webpack options
});
const express = require('express');
const app = express();
app.use(
middleware(compiler, {
// webpack-dev-middleware options
})
);
app.listen(3000, () => console.log('Example app listening on port 3000!'));
其它两种是
devServer: {
proxy: {
'/api': {
target: 'http://n.n.n.n:nnnn',
ws: false,
changeOrigin: true
},
},
// 模拟数据请求
before(app){
app.get('/some/path', function(req, res) {
res.json({ custom: 'response' });
});
}
},
按环境使用配置文件 webpack-merge
- webpack.base.js // 基础配置
- webpack.dev.js // 开发配置,如devServer中的source-map、代理等
- webpack.prod.js // 生产配置,如代码压缩、shake-tree等
var {smart} = require('webpack-merge');
var base = require('./webpack.base.js');
const OptimizeCssPlugin = require('optimize-css-assets-webpack-plugin')
const uglifyjsPlugin = require('uglifyjs-webpack-plugin')
module.exports = smart(base, {
mode: 'development',
optimization: { // 优化项
minimizer: [
new OptimizeCssPlugin(),
new uglifyjsPlugin()
]
},
})
多线程打包 happypack
在项目中添加vue和moment,并用babel解析
let Vue = require('vue')
let moment = require('moment')
moment.locale('zh-cn')
new Vue.default({
// el: '#app',
data: {
message: moment().format('lll')
},
render (h) {
return h('div', this.message)
}
}).$mount('#app')
module: {
rules: [
{ test: /\.js$/, use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
} } // 为了效果明显,这里故意不加exclude include
]
},
打包时间为2868ms。下面加入happypack
module: {
rules: [
{ test: /\.js$/, use: 'HappyPack/loader?id=js' }
]
},
plugins: [
new HappyPack({
id: 'js',
loaders: [{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}]
})
打包时间为2192ms,嗯...差别不大,分配线程也需要时间,小项目用了搞不好比不用还久
提取公共代码 optimization.splitChunks
写两个一样的文件
let Vue = require('./src/vue')
let moment = require('moment')
moment.locale('zh-cn')
new Vue({
data: {
message: moment().format('lll')
},
render (h) {
return h('div', this.message)
}
}).$mount('#app')
// webpack.config.js
entry: {
index: './index.js',
a: './src/a.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new HtmlWebpackPlugin({
template: './template.html',
filename: 'index.html'
})
]
打包出两个1M的js,下面开始分包
optimization: {
// 提取公共代码 分包
splitChunks: {
cacheGroups: { // 缓存组
common: {
chunks: 'initial',
minSize: 0,
minChunks: 2 // 引用>=2时分包
}
}
}
}
chunks的含义是拆分模块的范围
- async表示只从异步加载得模块(动态加载import())里面进行拆分
- initial表示只从入口模块进行拆分
- all表示以上两者都包括
打包后多出了 commonaindex.js 文件 997K,原本两个1M的js现在只有6.79k。除了common再抽离一个
common: {
chunks: 'initial',
minSize: 0,
minChunks: 2 // 引用>=2时分包
}
vendor: {
priority: 1, // 权重,不加会都到common里
test: /node_modules/,
chunks: 'initial',
minSize: 0,
minChunks: 1
}
commonaindex.js 363K,vendoraindex.js 634K
热更新
devServer: {
hot: true,
port: 7070,
contentBase: './dist'
},
plugins: [
// 热更新
new webpack.NamedModulesPlugin(), // 确保模块ID稳定
new webpack.HotModuleReplacementPlugin(),
// 入口文件
let b = require('./src/b')
console.log(b)
if (module.hot) {
module.hot.accept('./src/b', () => {
console.log('已变更')
b = require('./src/b')
console.log(b)
})
}
// ./src/b.js
module.exports = 'ggggg'
npx webpack-dev-server 启动后,修改./src/b.js页面会无刷新更新
不加两个plugin更新时会刷新页面