Webpack 知识体系 | 青训营笔记

74 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第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?

安装 → 编辑配置文件 → 执行编译命令

核心流程

  1. 入口处理
  2. 依赖解析
  3. 资源解析
  4. 资源合并打包

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

模块化 + 一致性

  • 多个文件资源合并成一个,减少 http 请求数量
  • 支持模块化开发
  • 支持高级JS特性
  • 支持TS等
  • 支持图片CSS ,字体,其他资源的处理模型
  • ...

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

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

image.png

使用Webpack——处理css

  1. 安装Loader
npm add -D css-loader  style-loader
  1. 添加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

  1. 安装依赖
npm i -D @babel/core @babel/preset-env babel-loader
  1. 声明产物出口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']
               ]
            }
          }]
       }]
   }
}
  1. 执行npx webpack

使用Webpack——生成HTML

  1. 安装依赖
npm i -D html-Webpack-plugin
  1. 声明产物出口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()]
}
  1. 执行npx webpack

使用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()], 
}
  1. 启动Webpack
npx webpack serve

使用Webpack——Tree-Shaking

对工具类库如Lodash有奇效

  1. 开启tree-shaking
  2. 执行npx webpack
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 两种模式

image.png

编写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

image.png

理解插件

什么是插件?

很多的知名工具都是所谓“插件”架构的 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 的交互接口,插件可以通过这些接口改变

  1. 时机:compier.hooks.compilation——钩子在何时触发
  2. 参数:compilation等
  3. 交互:dependencyFactories.set——在钩子回调中如何和webpack其他上下文内容进行交互

如何学习webpack?

入门应用

image.png

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

进阶

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

大师级

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