这是我参与「第五届青训营 」伴学笔记创作活动的第25天,学习的是关于 Webpack 的知识体系。
为什么要学习webpack?
- 前端“工程化”的重要工具
- 使团队成员能力配置更全面
- 增强个人核心竞争力
- 高阶前端必经之路
什么是webpack?
前端项目由庞杂的资源构成,需要进行有效地管理
手工管理的问题:
- 过程繁琐
- 当代码文件之间有依赖时,必须严格按依赖顺序书写
- 比较难以接入Less、Sass等工具
- JS、图片、CSS资源管理模型不一致
工程化工具的出现:
Vite、rollup.is、webpack等
本质是一种前端资源编译、打包工具
- 多份资源文件打包成一个Bundle
- 支持Babel、Eslint、Ts、CoffeScript、Less、Sass
- 支持模块化处理CSS、图片等资源文件
- 支持HMR+开发服务器
- 支持持续监听、持续构建
- 支持代码分离
- 支持Tree-shaking
- 支持Sourcemap
- ……
怎么使用webpack?
安装 → 编辑配置文件 → 执行编译命令
核心流程
- 入口处理
- 依赖解析
- 资源解析
- 资源合并打包
递归调用2、3直到所有资源处理完毕
模块化 + 一致性
- 多个文件资源合并成一个,减少 http 请求数量
- 支持模块化开发
- 支持高级JS特性
- 支持TS等
- 支持图片CSS ,字体,其他资源的处理模型
- ...
关于Webpack的使用方法,基本都围绕“配置”展开,而这些配置大致可划分为两类:
- 流程类:作用于流程中的某个or若干个环节,直接影响打包效果的配置项
- 工具类:主流程之外,提供更多工程化能力的配置项
使用Webpack——处理css
- 安装
Loader
npm add -D css-loader style-loader
- 添加
module处理css文件
const paht =require("path");
module.exports={
entry:"./src/index",
output:{
filename:"[name].js",
path.join(__dirname,"./dist"),
},
moduel:{
rules:[{
test:/\.css/i,
use:[{
"style-loader",
"css-loader"
],
}],
}
};
使用Webpack——接入Babel
- 安装依赖
npm i -D @babel/core @babel/preset-env babel-loader
- 声明产物出口
output
const paht =require("path");
module.exports={
entry:"./src/index",
output:{
filename:"[name].js",
path.join(__dirname,"./dist"),
},
moduel:{
rules:[{
test::/.js?$/,
use:[{
loader:'babel-loader',
options:{
presets:[
['@babel/preset-env']
]
}
}]
}]
}
}
- 执行
npx webpack
使用Webpack——生成HTML
- 安装依赖
npm i -D html-Webpack-plugin
- 声明产物出口
output
const path = require('path')
const HTMLWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/index',
output: {
filename: '[name].js',
path: path.join(__dirname, './dist')
},
plugins: [new HTMLWebpackPlugin()]
}
- 执行
npx webpack
使用Webpack——HMR
- 开启
HMR
const path = require('path')
const HTMLWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/index',
mode: 'development',
devtool: false,
watch: true
devServer: {
hot: true,
open: true
},
output: {
filename: '[name].js',
path: path.join(__dirname, './dist')
},
module: {
rules: [{ test: /.css$/, use: ['style-loader', 'css-loader']
}]
},
plugins: [new HTMLWebpackPlugin()],
}
- 启动
Webpack
npx webpack serve
使用Webpack——Tree-Shaking
对工具类库如Lodash有奇效
- 开启
tree-shaking - 执行
npxwebpack
const path = require('path')
module.exports = {
entry: './src/index',
devtool: false,
output: {
filename: '[name].js',
path: path.join(__dirname, './dist')
},
mode: 'production',
optimization: {
usedExports: true,
}
}
怎么扩展webpack?
理解 Loader
Loader的功能:
- 为了处理非标准JS资源,设计出资源翻译模块
- 用于将非js资源翻译为标准的js资源
认识Loader ——链式调用
- less-loader: 实现了 less ~> css 的转换
- css-loader: 将 CSS 包装成类似 module.exports = "${css}" 的内容,包装后的内容符合 JavaScript 语法
- style-loader: 将 CSS 模块包进 require 语句,并在运行时调用 injectStyle 等函数将内容注入到页面的 style 标签
认识Loader ——其他特性
- 链式执行
- 支持异步执行
- 分 normal、pitch 两种模式
编写Loader
import getOptions from './ get0ptions ' ;
import Linter from './Linter' ;
import cacheLoader from './cacheLoader ';
export default function loader( content, map){
const options = getOptions ( this );
const linter = new Linter( this, options ) ;
this.cacheable( );
//return early if cached
if(options.cache){
cacheLoader( linter, content,map );
return;
}
linter.printOutput(linter.lint( content ));
this.callback( null, content,map );
}
常见Loader
理解插件
什么是插件?
很多的知名工具都是所谓“插件”架构的 eg:
- VScode、Webstorm、Chrome、Firefox
- Babel、Webpack、Rollup、Eslint
- Vue、Redux、Quill、Axios
为什么需要这么设计?
- 新人需要了解整个流程细节,上手成本高
- 功能迭代成本高,牵一发动全身
- 功能僵化,作为开源项目而言缺乏成长性
- Blaba
心智成本高 →可维护性低 →缺少生命力
插件架构精髓:对扩展开放,对修改封闭
使用插件
使用html-webpack-plugin
module.exports={
...
plugins:[
new HTMLWebpackPlugin()
]
...
}
使用html-webpack-plugin + DefinePlugin
const webpack = require('webpack')
const HtmlwebpackPlugin = require( 'html-webpack-plugin ')
module.exports = {
entry: "./ src/index" ,
output: {
filename: " [name].js ",
path: path.join( __dirname, " ./dist" )
},
plugins:[
new HtmlwebpackPlugin( ),new webpack. DefinePlugin({
PRODUCTION:JSON.stringify( true ),
VERSION: JSON.stringify( ' 5fa3b9'),
})
]
};
如何写插件
插件围绕“钩子”展开
“钩子”的核心信息:
时机: 编译过程的特定节点,Webpack 会以钩子形式通知插件此刻正在发生什么事情
上下文: 通过 tapable 提供的回调机制,以参数方式传递上下文信息
交互: 在上下文参数对象中附带了很多存在 side effect 的交互接口,插件可以通过这些接口改变
- 时机:compier.hooks.compilation——钩子在何时触发
- 参数:compilation等
- 交互:dependencyFactories.set——在钩子回调中如何和webpack其他上下文内容进行交互
如何学习webpack?
入门应用
- 理解打包流程
- 熟练掌握常用配置项、Loader、插件的使用方法,能够灵活搭建集成Vue、React、Babel、Eslint、Less、Sass、图片处理等工具的Webpack环境
- 掌握常见脚手架工具的用法,例如:
Vue-cli、create-react-app、@angular/cli
进阶
- 理解Loader、Plugin机制,能够自行开发Web组件
- 理解常见性能优化手段,并能用于解决实际问题
- 理解前端工程化概念与生态现状
大师级
阅读源码,理解webpack编译、打包原理,甚至能够参与共建