Webpack 知识体系 | 青训营笔记

52 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 7 天

Webpack 知识体系

什么是 Webpack

前端项目由 PNG、JPG、GIF、WEBP、JS、TS、css、Less、Vue、JSX、Sass... 等资源构成。我们可以对这些资源进行手动管理,但会存在以下问题:

  • 依赖手工,比如有 50 个 JS 文件... 操作,过程繁锁
  • 当代码文件之间有依赖的时候,就得严格按依赖顺序书写
  • 开发与生产环境一致,难以接入 TS 或 JS 新特性
  • 比较难接入 Less、Sass 等工具
  • JS、图片、CSS 资源管理模型不一致

这些都是旧时代非常突出的问题,对开发效率影响非常大,直到出现了很多工程化道具,例如 gulp、webpack、vite 等。

webpack 本质上是一种前端资源编译、打包工具,它拥有以下功能:

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

使用 Webpack

1.安装

npm i -D webpack webpack-cli

2.编辑配置文件

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 打包核心流程

Webpack 打包核心简化版流程:

Entry => Dependencies Lookup => Transform => Bundle => Output

  1. 入口处理(entry)

    • entry 文件开始,启动编译流程
  2. 依赖解析(require import

    • entry 文件开始,根据 require or import 等语句找到依赖资源
  3. 资源解析(moudle output)

    • 根据 moudle 配置,调用资源转移器,将 png、css 等非标准 JS 资源转译为 JS 内容
  4. 资源合并打包(output

    • 将转译后的资源内容合并打包为可直接在浏览器运行的 JS 文件

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

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

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

示例:

const path = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin')
const {
    HotModuleReplacementPlugin
} = require('webpack' )
​
module.exports = {
    entry: "./src/index", 
    mode: "development",
    devtool: false,
    output: {
        filename: "[name].js",
        path: path.join(__dirname, "./dist"),
        clean: true,
    },
    devServer:{
        hot: true,
        open: true,
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './public/index.html',
            title: 'Hot Module Replacement!',
        }),
    ]
};

配置总览

config.png

按使用频率排序:

  1. entry/ouput

    module.export = {
        entry: "./src/index",
        output: {
            filename: "[name].js",
            path: path.join(__dirname, "./dist"),
        }
    }
    
  2. moudle/plugins

  3. mode

  4. watch/devServer/devtool

处理 css

项目文件结构:

css.png

  1. 安装 Loader

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

    module.export = {
      entry: './src/index',
      output: {
        filename: '[name].js',
        path: path.join(__dirname, './dist')
      },
      module: {
        // css 处理器
        rules: [
          {
            test: /.css/i,
            use: ['style-loader', 'css-loader']
          }
        ]
      }
    }
    
  3. 引入 css 模块

    const style = require('./index.css');
    // or 
    import style from './index.css'
    

接入 Babel

  1. 安装依赖

    npm i -D @babel/core @babel/preset-env babel-loader
    
  2. 声明产物出口 output

    module.export = {
      entry: './src/index',
      output: {
        filename: '[name].js',
        path: path.join(__dirname, './dist')
      },
      module: {
        rules: [
          {
            test: /.js?$/,
            use: [
              {
                loader: 'babel-loader',
                options: {
                  presets: [['@babel/preset-env']]
                }
              }
            ]
          }
        ]
      }
    }
    
  3. 使用 ES6 语法

    class Person {
      constructor () {
        this.name = 'Tecvan'
      }
    }
    console.log(new Person().name)
    const say = () => {}
    
  4. 执行 npx webpack

生成 HTML

  1. 安装依赖

    npm i -D html-webpack-plugin
    
  2. 声明产物出口 entry

    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

初始目录结构:

html1.png

打包后的目录结构:

html2.png

生成的 index.html

!DOCTYPE html>
<html><head>
    <meta charset="utf-8">
    <title>Webpack App</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script defer src="main.js"></script>
</head><body>
</body></html>

HMR

Hot Module Replacement(HMR),模块热替换,用于提高开发效率。

HMR.png

使用方法:

  1. 开启 HMR

    module.exports = {
      // ...
      devServer: {
        hot: true
      }
    }
    
  2. 启动 Webpack

    npx webpack serve
    

Tree-Shaking

Tree-Shaking,摇树,顾名思义,用于删除 Dead Code。

Dead Code 特征:

  • 代码没有被用到,不可到达
  • 代码的执行结果不会被用到
  • 代码只读不写
  • 模块导出了,但未被其他模块使用
  • ...

开启 Tree-shaking:

module.exports = {
  entry: './src/index',
  mode: 'production',
  devtool: false,
  optimization: { usedExports: true }
}

进阶篇:理解 Loader

为了处理非标准 JS 资源,设计出资源翻译模块 —— Loader,用于将资源翻译为标准的 JS。

使用 Loader

  1. 安装 Loader

    npm add -D css-loader style-loader less-loader
    
  2. 添加 modoule 处理 css 文件

    module.exports = {
      module: {
        rules: [
          {
            test: /.less$/i,
            use: ['style-loader', 'css-loader', 'less-loader']
          }
        ]
      }
    }
    
  3. 使用 css / less / sass

    import styles from './a.less';
    

Loader 的链式调用

loader1.png

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

loader2.png

特点:

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

常见 Loader

loader3.png

进阶篇:理解插件

许多知名的工具,如:VS Code、Web Storm、Chrome、Firefox、Babel、Webpack、Rollup、Eslint、Vue、Redux、Quill、Axios 等等,都设计了”插件“架构。

Webpack 编译过程:

webpack-compile.png

Webpack 编译是一个特别复杂的过程,具有上手成本、功能迭代成本高和功能僵化等缺陷,而插件架构的精髓是对外扩展开放,对修改封闭。Webpack 本身的很多功能都是基于插件实现的。

Webpack 插件是围绕着“钩子”展开的,钩子的核心信息如下:

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

学习路线

入门应用

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

进阶

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

大师级

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