这是我参与「第四届青训营 」笔记创作活动的第12天
一、什么是Webpack?
定义: 本质上是一种前端资源编译、打包工具
基本使用:
文件结构
.
|——src
| ﹂index.js
|——webpack.config.js
1.安装依赖
npm i -D webpack webpack-cli
2.编辑配置文件
module.exports={
//声明入口:要打包的文件
entry:'index.js',
//声明产物出口
output:{
filename:"[name].js",
//项目打包后的存放位置
path:path.join(__diename,"./dist"),
},
module:{
rules:[{
test:/.less$/i,
use:['style-loader','css-loader','less-loader']
}]
}
}
3.执行编译命令
npx webpack
打包后的文件
核心流程
总结:webpack实际上主要做了两件事情——模块化+一致性
- 多个文件资源合并成一个,减少http请求数
- 支持模块化开发(
import
、export
对不同类型资源的管理) - 支持高级js特性
- 支持Typescript、CoffeeScript方言
- 统一图片、css、字体等其他资源的处理模型
- Etc···
二、使用Webpack
1.使用Webpack——接入Babel
babel作用:把高版本的代码转换成低版本的代码,已达到兼容目的。
文件结构:
.
|——src
| ﹂index.js
|——webpack.config.js
1.安装依赖
npm i -D @babel/core @babel/preset-env babel-loader
2.声明产物出口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']
]
}
}]
}]
}
}
3.执行npx webpack
2.使用Webpack——生成HTML
文件结构:
.
|——src
| ﹂index.js
|——webpack.config.js
1.安装依赖
npm i -D html-webpack-pligin
2.声明产物出口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()]
}
3.执行npx webpack
运行结果:
文件结构:
.
|——dist
| ﹂index.html
| ﹂main.js
|——src
| ﹂index.js
|——webpack.config.js
3.使用Webpack——HMR (模块热替换)
可以使我们写的代码不用刷新,就能立刻把最新结果更新到浏览器中
1.开启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()],
}
2.启动Webpack
npx webpack serve
参考资料:HMR 原理全解析mp.weixin.qq.com/s/cbYMpuc4h…
4.使用Webpack——Tree-Shaking
Tree-Shaking作用:删掉没有用到的代码,对工具类库如Lodash有奇效。
1.开启tree-shaking:
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,//必要
}
}
2.执行npx webpack
5.webpack工具线
其他工具:
- 缓存
- Sourcemap
- 性能监控
- 日志
- 代码压缩
- 分包
- ···
三、理解Loader
作用:
- 为了处理非标准JS资源,设计出资源翻译模块
- 用于将非js资源翻译为标准的js资源
认识:下面这3个loader 主要干了些什么
以链式调用的方式加载——前一个loader的输出作为后一个loader的输入
- less-loader: 实现了 less ~> css 的转换
- css-loader: 将 CSS 包装成类似 module.exports = "${css}" 的内容,包装后的内容符合 JavaScript 语法
- style-loader: 将 CSS 模块包进 require 语句,并在运行时调用 injectStyle 等函数将内容注入到页面的 style 标签
特性:
- 链式执行
- 支持异步执行
- 分 normal、pitch 两种模式
参考资料:如何编写loadermp.weixin.qq.com/s/TPWcB4MfV…
实现eslint-loader:
import getOptions from './ get0ptions ' ;
import Linter from './Linter' ;
import cacheLoader from './cacheLoader ';
export default function loader( content, map){
const options = getOptions ( this );
//创建lint实例
const linter = new Linter( this, options ) ;
this.cacheable( );
//return early if cached
if(options.cache){
cacheLoader( linter, content,map );
return;
}
//检查输入代码,并返回结果content
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'),
})
]
};
如何写插件
写一个插件最需要关注以三个参数:
- 时机:
compier.hooks.compilation
——钩子在何时触发 - 参数:
compilation
等 - 交互:
dependencyFactories.set
——在钩子回调中如何和webpack其他上下文内容进行交互
插件围绕钩子展开
钩子的核心信息:
- 时机: 编译过程的特定节点,Webpack 会以钩子形式通知插件此刻正在发生什么事情
- 上下文: 通过 tapable 提供的回调机制,以参数方式传递上下文信息
- 交互: 在上下文参数对象中附带了很多存在 side effect 的交互接口,插件可以通过这些接口改变
参考资料:
五、学习方法
知识点总结: