构建 Webpack 知识体系 | 青训营笔记

116 阅读3分钟

什么是 Webpack?

本质上是一种前端资源编译、打包工具。

  • 多份资源文件打包成一个 Bundle
  • 支持 Babel、Eslint、TS、CoffeScript、Less、Sass
  • 支持模块化处理 css、图片等资源文件
  • 支持 HMT + 开发服务器
  • 支持持续监听、持续构建
  • 支持代码分离
  • 支持 Tree-shaking
  • 支持 Sourcemap
  • ...

使用 Webpack

  1. 安装

     npm i -D webpack webpack-cli
    
  2. 编辑配置文件

     // webpack.config.js
     ​
     module.exports = {
       entry: 'main.js', // 入口文件
       output: { // 输出目录
         filename: "[name].js",
         path: path.join(__dirname, "./dist"),
       },
       module: {
         rules: [{
           test: /.less$/i,
           use: ['style-loader', 'css-loader', 'less-loader']
         }]
       }
     }
    
  3. 执行编译命令

     npx webpack
    

关于 Webpack 的使用方法,基本都围绕 “配置” 展开,而这些配置大致可划分为两类:

  • 流程类:作用于流程中某个 or 若干个环节,直接影响打包效果的配置项
  • 工具类:主流程之外,提供更多工程化能力的配置项

配置总览

按使用频率:

  • entry / output
  • module / plugins
  • mode
  • watch / devServer / devtool

image-20230818113359852

流程类配置

  1. Get Start(entry)

    输入:

    • entry
    • context
  2. Dependencies Lookup(require、import)

    模块解析:

    • resolve
    • externals
  3. Transform(module)

    模块转译:

    • module
  4. Combine Assets(output)

    后处理:

    • optimization
    • mode
    • target

处理 CSS

  1. 安装 Loader

     npm add css-loader style-loader
    
  2. 添加 module 处理 css 文件

     // webpack.config.js
     ​
     module.exports = {
       module: {
         // css 处理器
         rules: [{
           test: /.css/i,
           use: [
             "style-loader",
             "css-loader"
           ],
         }],
       },
     }
    

接入 Babel

  1. 安装依赖

     npm i -D @babel/core @babel/preset0env babel-loader
    
  2. 添加 module 转译 js 文件

     // webpack.config.js
     ​
     module.exports = {
       module: {
         rules: [{
           test: /.js$/,
           use: [{
             loader: 'babel-loader',
             options: {
               presets: [
                 ['@babel/preset-env'],
               ],
             },
           }],
         }],
       },
     }
    

生成 HTML

  1. 安装依赖

     npm i -D html-webpack-plugin
    
  2. 配置 plugin

     // webpack.config.js
     ​
     module.exports = {
       plugins: [new HtmlWebpackPlugin()]
     }
    

工具类配置

HMR

Hot Module Replacement:模块热替换。

  1. 开启 HMR

     // webpack.config.js
     ​
     module.exports = {
       devServer: {
         hot: true
       }
     }
    
  2. 启动

     npx webpack serve
    

Tree-Shaking

Tree-Shaking:树摇,用于删除 Dead Code。

  • 模块导出了,但未被其他模块使用

Dead Code:

  • 代码没有被用到,不可到达
  • 代码的执行结果不会被用到
  • 代码只读不写
  • ...
  1. 修改 mode

     // webpack.config.js
     ​
     module.exports = {
       mode: 'production'
     }
    
  2. 配置 optimization

     // webpack.config.js
     ​
     module.exports = {
       optimization: {
         usedExports: true
       }
     }
    

PS:对工具类库如 Lodash 有奇效。

其他

  • 缓存
  • Sourcemap
  • 性能监控
  • 日志
  • 代码压缩
  • 分包
  • ...

Webpack 打包核心流程

  1. 入口处理(Get Start):从 entry 文件开始,启动编译流程
  2. 依赖解析(Dependencies Lookup):从 entry 文件开始,根据 require 或 import 等语句找到依赖资源
  3. 资源解析(Transform):根据 module 配置,调用资源转移器,将 png、css 等非标准 JS 资源转译为 JS 内容
  4. 资源合并打包(Combine Assets):将转译后的资源内容合并打包为可直接在浏览器运行的 JS 文件

递归调用 2、3,直到所有资源处理完毕。

模块化 + 一致性

  1. 多个文件资源合并成一个,减少 http 请求数
  2. 支持模块化开发
  3. 支持高级 JS 特性
  4. 支持 TypeScript、CoffeeScript 方言
  5. 统一图片、CSS、字体等其他资源的处理模型
  6. ...

Loader

由于 Webpack 只认识 JS,为了处理非标准 JS 资源,设计出资源翻译模块——Loader。

作用:用于将资源翻译为标准 JS。

  1. 安装 Loader

     npm add -D css-loader style-loader less-loader
    
  2. 配置 module

     // webpack.config.js
     ​
     module.exports = {
       module: {
         rules: [
           {
             test: /.less$/i,
             use: [
               "style-loader", // 将 CSS 模块包进 require 语句,并在运行时调用 injectStyle 等函数将内容注入到页面的 style 标签
               "css-loader", // 将 CSS 包装成类似 module.exports = "${css}" 的内容,包装后的内容符合 JavaScript 语法
               "less-loader", // 实现 less => css 的转换
             ],
           },
         ],
       },
     };
    

特性

image-20230818153703414.png

  • 链式执行
  • 支持异步执行
  • 分 normal、pitch 两种模式

编写 Loader

 // myLoader.js
 ​
 module.exports = function(source, sourceMap?, data?) {
   // source 为 loader 的输入
   // 可能是文件内容,也可能是上一个 loader 处理结果
   return source;
 }

在 Loader 中 debug

在 npx 前面加上 ndb。

 ndb npx webpack

常见 Loader

  • JavaScript

    • babel-loader
    • eslint-loader
    • ts-loader
    • buble-loader
    • vue-loader
    • angular2-template-loader
  • CSS

    • css-loader
    • style-loader
    • less-loader
    • sass-loader
    • stylus-loader
    • postcss-loader
  • HTML

    • html-loader
    • pug-loader
    • posthtml-loader
  • Assets

    • file-loader
    • val-loader
    • url-loader
    • json5-loader

Plugin

DashboardPlugin

作用:美化终端数据展示。

  1. 安装

     npm i -D webpack-dashboard
    
  2. 引入并配置 plugins

     // webpack.config.js
     ​
     const DashboardPlugin = require('webpack-dashboard/plugin');
     ​
     module.exports = {
       plugins: [new DashboardPlugin()]
     }
    

如何编写 Plugin

image-20230818160701193.png

钩子的核心信息:

  1. 时机:编译过程的特定节点,Webpack 会以钩子形式通知插件此刻正在发生什么事情
  2. 上下文:通过 tapable 提供的回调机制,以参数方式传递上下文信息
  3. 交互:在上下文参数对象中附带了很多存在 side effect 的交互接口,插件可以通过这些接口改变

总共有 239 个钩子。

 class EntryPlugin {
   apply(compiler) {
     // 时机
     compiler.hooks.compilation.tap(
       "EntryPlugin",
       // 参数
       (compilation, { normalModuleFactory }) => {
         // 交互
         compilation.dependencyFactories.set(
           EntryDependency,
           normalModuleFactory
         )
       }
     )
   }
 }

如何学习 Webpack

入门应用

  • 理解打包流程
  • 熟练掌握常用配置项、Loader、插件的使用方法,能够灵活搭建集成 Vue、React、Babel、Eslint、Less、Sass、图片处理等工具的 Webpack 环境
  • 掌握常见脚手架工具的用法,例如:Vue-cli、create-react-app、@angular/cli

image-20230818163057056.png

进阶

  • 理解 Loader、Plugin 机制,能够自行开发 Webpack 组件
  • 理解常见性能优化手段,并能用于解决实际问题
  • 理解前端工程化概念与生态现状

大师级

阅读源码,理解 Webpack 编译、打包原理,甚至能够参与共建。