这里写目录标题
webpack构建流程:
- 初始化参数,从配置文件和shell语句中读取和合并参数,得到最终的参数
- 开始编译,用上一步得到的参数初始化compiler这个对象,加载所有配置的插件,执行对象的run方法
- 确定入口,根据配置中的 entry 找出所有的入口文件
- 编译模块:从入口文件出发,调用所有配置的Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
- 完成模块编译:在经过第四步使上oader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会
- 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统,在以上过程中,webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用
基础配置
plugins:可以在webpack运行到某个阶段时帮我们做一些事情,可以监听事件并执行特定的功能,有点像vue的生命周期
webpack.config.js中
const path = requeire('path')
module.exports = {
mode:'development',
entry:path.join(__dirname,'src','index.js')//把哪个文件作为打包入口
output: {
publicPath:'http://cdn.xxx.com/',
path: path.join(__dirname,'dist')//把打包好的文件放在哪个路径,一般是dist
filename:'boundle.js'//也可以用占位符[name].js·
},
plugins:[
new HtmlWebpackPlugin({//打包完毕之后,帮忙自动生成html文件,再把打包后的结果注入到html之中
template:path.join()__dirname,'src','index.html'),//把src底下index.html作为模板文件来打包,把打包好的js自动放进html里
filename:'boundle.js'
})
new CleanWebpackPlugin()//自动删除dist文件夹
],
module:{//解析模块的规则
rules:[
{
test:/\.js$/,
loader:['babel-loader],//es6转化为es5
include:path.join(__dirname,'src'),//只处理哪些代码
exclude:/node_modules/, //排除哪些代码
}
]
},
devServer: {
port:8000,
static:path.join(__dirname,'dist)//把dist目录作为静态资源的文件夹
}
}
package.json文件中
'script':{
"build":"webpack"//输入npm run build,运行webpack打包
"dev":"webpack-dev-seerver"//实时编译代码,会把打包生成的文件放在内存里
},
.babelrc文件中
{//预设,
"presets":["@babel/preset-env"]
}
拆分配置,合并配置
项目中常常会遇到,生产环境,测试环境,开发环境配置不同的情况,我们可以提取这些环境中的公共部分,写进webpack.base.config.js
在webpack.dev.config.js和webpack.prod.config.js中引入webpack.base.config.js
const commonConfig = require('./webpack.base.config');
const {smart:merge} = require('webpack-merge');//用smart方法合并配置,改名为merge
const prodConfig = {
mode:'production'
}
module.exports = merge(commonConfig,prodConfig)
"scripts": {
"build:dev":"webpack --config ./build/webpack.dev.config.js",//开发
"build":"webpack --config ./build/webpack.prod.config.js",//生产
loader
Loader 是用于对模块的源代码进行转换的插件。
webpack本身是不认识图片,css,vue之类的东西的,只认识js,所以我们需要引入loader来处理各种模块
处理图片
webpack.dev.config.js
//开发环境
const devConfig = {
module:{//解析模块的规则
rules:[
{
test:/\.(png|jpg)$/,
loader:'file-loader ',//把图片移到dist目录下,直接访问url来拿图
}
]
},
}
//生产环境
const prodConfig = {
module:{//解析模块的规则
rules:[
{
test:/\.(png|jpg)$/,
use:{
loader:'url-loader ',//小图转化为base64,减少一次http请求
options:{//大图依然像file-loader一样,单独打包到img文件夹里,发请求,防止页面首次渲染时间太慢
limit: 5*1024
}
}
}
]
},
}
index.js
import axios from 'axios'
axios.get('api/Yixiantong/getHomeDatas')//把api/Yixiantong rewrite成...
.then(({data})=>{console.log(data)})
样式
webpack不能直接处理css
webpack.dev.config.js中
module.exports = {
module:{//解析模块的规则
rules:[
{
test:/\.css$/,
loader:[
'style-loader',//把样式插进style标签里
'css-loader',//处理css之间的依赖关系
'postcss-loader',//处理css3
'sass-loader',//处理预处理器sass
]
},
]
},
posts.config.js
moudle.exports = {
plugins:[
require('autoprefixer')
package.json
"browserslist": [//适配这些浏览器
"> 1%",//选择全球使用率超过 1% 的浏览器版本。
"last 2 versions"//选择每个浏览器的最近两个版本。
],
webpack-dev-server使用
webpack-dev-server可以用来转发请求
webpack.dev.config.js中
const devConfig = {
mode:'development',
devServer:{
port:8000,//服务器气筒的端口8080
contentBase:'./dist',//服务器静态资源文件夹
progress:true,//打包时显示进度条
open:true,//启动服务器后,自动打开浏览器
compress:true,//开启gzip压缩
proxy:{//请求转发
'/api/Yixiantong': {
target:'http://study.jsplus.com',
pathRewite:{
'^/api':''
},
changeOrigin:true
}
}
}
}
多入口
webpack.config.js中
module.exports = {
entry:{
index:'./src/index.js',
other:'./src.other/js'
},
output:{
filename:'[name].js',//打包后的文件名,[name] 示入口的名称,即 index 或 other。
path:path.resolve(__dirname,'../dist')
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html',
filename:'index.html',
chunks:['index'],//chunk:由模块组成的代码块
}),
new HtmlWebpackPlugin({
template:'./src/other',
filename:'other.html'.
chunks:['other'],
}),
],
抽离css
我们想在生产环境中,把样式抽离成css文件
webpack.prod.config.js中
const MiniCSSExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsWepackPlugin = require('optimize-css-assets-wepack-plugin');
module.exports = {
module:{
rules:[
{
test:/\.css$/,
loader:[
MiniCSSExtractPlugin.loader,//换成minicss
'css-loader',//处理css之间的依赖关系
'postcss-loader',//处理css3
'sass-loader',//处理预处理器sass
]
},
]
},
plugins:[
new MiniCSSExtractPlugin({//根据文件内容生成的哈希值,只使用哈希值的前8个字符。
filename:'css/main.[contentHash:8].css'
}),
],
optimization:{
minimizer:[
new TerserPlugin(),//压缩js
new OptimizeCssAssetsWepackPlugin(),//压缩css
这样做的结果就是,原本的css被压缩,比如注释掉的css都没有被打包进去,
css没有被插入进style标签,而是生成了css/main.abcd1234.css文件,并在link中引入
公共代码
- 公共模块
公共模块的代码不需要重复打包,单独抽离成一个公共模块的文件,然后饮用即可 - 第三方模块
第三方模块的代码一般不会轻易改变,不需要在业务代码改变之后再重新打包,单独抽离成一个第三方模块的文件,然后引用即可
一般在生产环境做这样的配置
webpack.prod.config.js中
module.exports = {
entry:{
index:'./src/index.js',
other:'./src.other/js'
},
output:{
filename:'[name].[conetntHash:8]js',
path:path.resolve(__dirname,'../dist')
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html',
filename:'index.html',
//html使用的js文件
chunks:['index','vendor','common'],//vendor是第三方模块,common是公共模块
}),
new HtmlWebpackPlugin({
template:'./src/other',
filename:'other.html'.
chunks:['other','common'],//common是公共模块
}),
],
optimization:{
splitChunks:{//代码分割
chunks:'all'
//all:对同步异步代码都做代码分割
//async:只对异步代码做代码分割
//initial:只对同步代码做代码分割
//同步代码,例如import lodash from 'lodash'
//异步代码,例如 import('lodash'),用import函数
cacheGroups:{
// 第三方模块
vendor: {
// 每个组的名字
name: 'vendor',
// 优先级,优先级越高,越先检测处理
// 第三方模块 可能也会被作为公共模块来检测处理,通过高优先级,达到先被当做 第三方模块 来检测处理
priority: 1,
// 检则方法,例如:检测模块是否来自 node_modules
test: /node_modules/,//来自npm安装
// 实际开发中,可以写 5*1024,也就是 5kb
// 但这里为了看到 代码分割 的效果,我们把值沒置到最小,也就是0
minSize: 0,
// 检测模块被引用了几次
// 对于 第三方模块而言,引用1次就应该单独打包
// 对于 公共模块 而言,引用2次以上就应该单独打包
minChunks: 1,
},
// 公共模块
common: {
// 每个组的名字
name: 'common'
// 优先级,优先级越高,越先检测处理
priority: 0,
// 实际开发中,可以写5*1024,也就是5kb
// 但这里为了看到 代码分割 的效果,我们把值设置到最小,也就是0
}
}
}
sourceMap
建立打包生成的代码与源代码之间的关系,方便改bug
module.exports={
devtool:'eval-source-map',//开启sourcemap,关闭设为false
//eval:打包速度最快,转化成eval()语法
//source-map:把映射关系写入bundle.js.map文件里
//inline-source-map:把映射关系写入bundle.js文件内最后一行,base64字符串
//cheap:只记录哪行出错,不记录那列出错,不记录loader第三方模块出啥错
HMR模块热更新
占坑
性能优化
webpack的性能优化主要包括两部分,一是打包体积减少,一是打包速度加快
因为webpack构建流程其中有个步骤是所有的模块进行编译处理,那么我们可以在以下几点上做优化处理
- 缩小查找文件的范围,用alias,extensions等配置缩小范围
- 减少需要解解析的文件,使用noparse配置告诉webpack排除忽略指定文件,不对他们进行解析,
- 避免去重复的编译第三方库,打包到单独文件中,不会跟着业务文件一起重新打包,
- webpack在对代码进行压缩打包时,如果有多个js文件需要被压缩,她会一个个进行压缩,可以使用thread loader插件来开启多个子进程,采用并行的方式对多个js文件进行压缩打包。
参考:https://www.bilibili.com/video/BV1By4y177gX/?p=7&share_source=copy_web&vd_source=64698271e543eb5149301ff926e69c40