把字节青训营的视频又翻出来学习力,并且补个简单的笔记

什么是Webpack

Webpack本质上是一种前端资源编译、打包工具,核心目标是模块化+一致性

  1. 可以将多份资源文件打包成一个Bundle,减少http请求数

  2. 支持模块化开发(Babel / Eslint / TS / CoffeScript / Less / Sass)统一了资源文件的管理模型,不需要为JS独立设立一套管理的规范

  3. 支持高级JS特性

  4. 支持TypeScript、CoffeeScript方言

  5. 统一图片、CSS、字体 等其他资源的处理模型

Webpack核心工作流程

  1. 入口处理

entry文件开始,启动编译流程

  1. 依赖解析

entry文件开始,根据require or import等语句找到依赖资源

  1. 资源解析

根据module配置,调用资源转移器,将png、css等非标准JS资源转译为JS内容

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

  1. 资源合并打包

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

Webpack的基本使用流程

  1. 安装
yarn add webpack webpack-cli
  1. 编辑配置文件
// webpack.config.js
const path = require('path')

module.exports = {
  entry: './src/index',
  mode:'development',
  devtool:false,
  output:{
    // 产物文件名
    filename:'[name].js',
    path:path.join(__dirname,'./dist')
  },
}
// src/index.js
const sum = (x, y) => x + y;
  1. 执行编译命令
npx webpack

如何使用Webpack

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

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

流程类配置总览

webpack

  1. 输入
  • entry:定义项目入口

  • context:Webpack运行时该从哪个文件夹开始找资源

  1. 模块解析
  • resolve

  • externals

  1. 模块转译
  • module
  1. 后处理
  • optimization

  • mode

  • target

处理CSS

  1. 安装loader

loader是Webpack中用于处理不同资源的组件

yarn add css-loader style-loader
  1. 添加module处理css文件
// webpack.config.js
const path = require('path');

module.exports = {
  entry:'./src/index',
  output:{
    filename:'[name].js',
    path:path.join(__dirname,'./dist'),
  },
  module:{
    // css处理器
    rules:[{
      // 匹配文件后缀
      test:/\.css/,
      // 使用这个loader
      use:[
        "style-loader",
        "css-loader"
      ]
    }]
  }
}
  1. 运行npx webpack,进行转译

可以看到编译产物中,我们之前在css内写的内容转为字符串push到了__CSS_LOADER_EXPORT__

除此之外,我们会发现编译产物的内容远远多于原始文件,充斥了大段的运行时代码

处理JS(接入Babel)

  1. 安装依赖
yarn add @babel/core @babel/preset-env babel-loader
  1. 声明产物出口output
// webpack.config.js
module.exports = {
  module:{
    rules:[{
      test:/\.js$/,
      use:[{
        // 用babel-loader处理JS文件
        loader:'babel-loader',
        // options最终会传入loader运行
        options:{
          // 规则集
          presets:[
            ['@babel/preset-env']
          ]
        }
      }]
    }]
  }
}
  1. 执行npx webpack

生成HTML

需要安装一个html-webpack-plugin的插件,该插件可以帮助我们自动生成HTML文件,不需要手动管理导入HTML的资源

  1. 安装依赖
yarn add html-webpack-plugin
  1. 声明产物出口output
const HTMLWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  plugins:[new HTMLWebpackPlugin()],
}
  1. 执行npx webpack

开启HMR(Hot Module Replacement 热更新)

保存代码时,页面会自动更新

  1. 开启HMR
// webpack.config.js
module.exports = {
  devServer: {
    hot: true,
    open: true
  }, 
  // 持续监听文件变化
  watch: true
}
  1. 启动Webpack
npx webpack serve

开启Tree-Shaking

DeadCode: 代码没有被用到 / 代码的执行结果不会被用到 / 代码只读不写 / …
Tree-Shaking: 模块导出了,但未被其他模块使用

// webpack.config.js
module.exports = {
  mode: 'production',
  optimization: {
    usedExports: true
  }
}

理解Loader

由于Webpack只认识JS,为了处理非标准JS资源,Loader作为一个资源翻译模块诞生,用于将资源翻译为标准JS

Loader有三个特性:1. 链式调用 2. 支持异步执行 3. 分normal、pitch两种模式

使用Loader主要有两个步骤:1. 安装相关的loader 2. 将loader添加到module处理

特性:链式调用

比如在处理less文件时,通常需要安装三个loader: style-loader / css-loader / less-loader

less-loader用于实现less到css的转换;

css-loader用于将CSS包装成类似module.exports = "${css}"的内容,包装后的内容符合JavaScript语法;

style-loader用于将CSS模块包进require语句,并在运行时调用injectStyle等函数,将内容注入到页面的style标签

三者是链式调用的关系,第一个loader的输出结果会成为第二个loader的输入

Loader

loader在pitch阶段根据loader数组定义的顺序,从前往后执行(style->css->less)。任意一个loader的pitch阶段如果有返回值,就会停止后续执行(适合做一些catch loader)

到了执行阶段,则先从源码中读取内容,按照loader数组定义顺序,从后往前执行(less->css->style)

如何编写自定义loader

一个基本的loader结构如下:

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

将其命名为loader.js,并在webpack.config.js中指定由loader.js处理js后缀的文件

// webpack.config.js
module.exports = {
  module:{
    rules:[{
      test:/\.js$/,
      use:[path.join(__dirname, './loader')]
    }]
  }
}

常见loader

loader

理解插件

插件架构的精髓:对扩展开放,对修改封闭

使用插件主要有3个步骤:1. 安装插件依赖 2. 在webpack.config.js中引入插件 3. 在plugins数组中添加插件实例

插件基本形态

插件用起来容易,编写时却较为复杂。

首先,插件围绕钩子展开。一个钩子具有以下核心信息:

  1. 时机(compier.hooks.complication):在编译过程的特定节点,Webpack会以钩子形式通知插件此刻正在发生什么事情
  2. 上下文(complication):通过tapable提供的回调机制,以参数方式传递上下文信息
  3. 交互(dependencyFactories.set):在上下文参数对象中附带了很多存在side effect的交互接口,插件可以通过这些接口改变
class SomePlugin{
  apply(compiler){
    compiler.hooks.thisCompilation.tap('SomePlugin',(complication)=>{
      // ...
    })
  }
}

学习Webpack的方法

关键知识点

入门应用

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

进阶

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

大师级

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

问答

面试要学到什么程度

主要围绕三种主题

  1. Loader有什么用 / 怎么写Loader / 常用Loader有哪些
    css-loader / style-loader / vue-loader / eslint-loader

  2. 插件有什么用 / 怎么写插件 / 插件原理

  3. Bundle / chunk / module 分别是什么含义

    上一页: 利用Github Pages部署React项目到自己的域名下一页: 用customize-cra+react-app-rewired配置less+css module的踩坑经历