背景
webpack
静态模块化打包工具。无论是前端工程化,还是高级前端岗位都是绕不开的话题之一,面试经常问到构建优化的的方案,自定义loader
,自定义plugin
等。无论是进阶,还是面试高级岗位,在这里你都可以找到答案。webpack
简单来说就是各种令人眼花缭乱的配置,笔者也是感同身受,学了很快就会忘记,所以才有了这篇文章。采用费曼学习法
,用简洁的思想和简单的语言向大家表达出来,帮助大家也是帮助自己,本文的学习资料大部分来自于官方文档。本文将持续迭代,收藏===
学会~
安装
shell
# 创建文件夹
mkdir learn-webpack
# 进入文件夹
cd learn-webpack
# 初始化
pnpm init
# 安装依赖
pnpm i webpack webpack-cli -D
结构划分
代码仓库:github.com/GetWebHB/le...
- 每一个小的章节,都会存放在对应的文件夹中(例:
0.start
),文件夹会存放对应的配置文件 ,源代码 ,产物 。打包命令如下所示,b-0
为build-step0
的简写,方便大家理解
js
// package.json
"scripts": {
"b-0": "webpack --config ./packages/0.start/webpack.config.js"
},
scripts
脚本,本质上就只在.bin
文件夹下寻找webpack, 即npm run b-1
等同于npx webpack
,--config
代表配置文件存在的目录。
因为每个章节都会有不一样的配置,给它们拆分开这样会更加清晰。如果是公司项目中不需要这样,一般只会有一个配置文件webpack.config.js
,存放在同package.json
目录,就不需要指定配置文件路径,执行npm run build
会自动去根目录查找webpack.config.js
配置文件
目录结构
css
├── README.MD
├── package.json
├── packages
│ └── 0.start
│ ├── build
│ │ └── bundle.js
│ ├── src
│ │ └── main.js
│ └── webpack.config.js
└── pnpm-lock.yaml
起手式
本节代码见:0.start
js
// main.js
function sayHi() {
console.log('hi ice 24')
}
sayHi()
export { sayHi }
// webpack.config.js
const path = require('path')
module.exports = {
entry: path.resolve(__dirname, "./src/main.js"),
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js'
},
}
- 简单走读一下,
cjs
的方式导出了一个对象
entry
代表入口,发现我们使用的是绝对路径,因为默认情况下相对路径为package.json
存在的目录output
代表出口,即产物打包后的位置,同样是绝对路径,打包到build
的文件夹下,文件名为bundle.js
npm run b-0
, 即打包产物,就会发现该目录下出现了产物
mode&devtool
本节代码见:1.mode_devtool
上一小节中,我们学习到了entry
,output
这两项配置,这一章节中,我们学习mode
和devtool
mode
概述:告诉webpack使用相应模式的内置优化
当我们执行npm run b-0
的时候,webpack
会有这一串警告,说我们没有设置mode
那什么是模式(即mode
),从提示看说我们可以设置为development
orproduction
传送门 :webpack.js.org/configurati...
mode也是最重要的优化,webpack
都会帮我们做好。接下来我们来一一了解对应模式展示的不同行为
mode
='none' | 'development' | 'production'(default)
js
// main.js
const mes = 'hi ice 24'
function sayHi() {
console.log(mes)
}
sayHi()
export { sayHi }
none
产物分析
- 我们大致扫一眼即可
development
我们平常使用的cli
, vue/cli
(维护阶段),create-react-app
等,反正所有底层使用webpack
的,npm run serve / npm run start
这种在本地开启服务的,采用的策略都是使用development
,主打的就是一个快,不需要通过一些plugin
,例如terser
(后面会讲)丑化压缩代码
产物分析 从注释中我们可以得知,它使用eval
函数可以在浏览器的开发工具中创建一个单独的源文件,在或者说devtool
:false
的时候就会移除(source map
),那么创建一个单独的文件可以干嘛呢?可以映射到代码报错的位置,这也是devtool
配置项的作用,我们后面会详细探讨。
production
就是那么朴实无华,甚至连函数
都帮你执行了,直接打印出结果
devtool
概述:是否生成,控制如何生成source map(源码映射),不同的值会明显影响到构建(build)和重新构建(rebuild)的速度。
默认值
dev: eval
prod: none
传送门 :webpack.docschina.org/configurati...- 在
mode
模式为development
中,我们看见了eval
函数,可以映射出代码的错误位置信息,即配置为mode: "eval"
,现在让我们来深入探讨一下devtool
就拿mode:prod
来说,我们发现代码是已经被丑化过,编译后的产物,如果在测试阶段,代码发生了错误压根不知道代码出错在哪里,那我们如何debug
呢?这正是source map
的作用,编译后的产物 ->(映射)源代码的位置
false
js
// main.js
const mes = 'hi ice 24'
function sayHi() {
console.log(mes)
}
console.log(age) // age is not defined
sayHi()
export { sayHi }
// bundle.js
(()=>{"use strict";console.log(age),console.log("hi ice 24")})();
跑到浏览器上(测试阶段),我们可以看到错误信息,但是却看不到代码详细出错在第几行,这在一个庞大的项目中,是非常致命的(即devtool: false
),不开启source map
eval
使用eval
函数可以在浏览器的开发工具中创建一个单独的source map
source-map
当我们配置改为它,我们先看下产物
会多出来一个.map的文件,即源码映射文件,最后一行代表着引用哪个.map文件,接下来我们在到浏览器下看下行为。
竟然神奇的映射出来了源代码的位置(第几行,甚至第几个字符),非常的神奇是吧
接下来,让我们继续深入探究,简单看下map
文件
- version:3,从之前1,2的版本构建出来的map文件有点大,随着不断的迭代构建出来的
.map
文件也越来小 - file:映射的源文件(转换后的源文件)
- mappings:记录位置信息的字符串(VLQ编码)
- sources:源的路径
- sourcesContent:源代码的内容
- names:转换前的所有变量名和属性名
- sourceRoot:映射目录的位置,为根目录
最佳实践
- prod:
none(默认) | false
- test:
source-map
- development:
source-map