Webpack系列之构建Webpack知识体系

前言

1. 为什么学习 Webpack?

Webpack 是一种用于构建 JavaScript 应用程序的静态模块打包器,它能够以一种相对「一致且开放」的处理方式,加载应用中的所有资源文件(图片、CSS、视频、字体文件等),并将其合并打包成浏览器兼容的 Web 资源文件。

Webpack系列之构建Webpack知识体系
image.png
Webpack系列之构建Webpack知识体系
前端项目的构成

在旧时代,我们只能用原生 JavaScript(ES5)、CSS、HTML 方式编写页面代码,开发与生产环境代码基本一致,开发与运行效率都非常低;其次,页面的图片、代码、CSS 等资源都能且只能通过 imgscriptlink 等标签插入到页面中,我们需要非常精细地管理、设计各个标签出现的位置、顺序,这也会占用我们非常多的精力与注意力;并且,开发环境和生产环境一致,难以接入 TS 或 JS 新特性,以及CSS预处理工具。如下图代码片段:

<!DOCTYPE html>
<html lang="en">
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
   <link rel="shortcut icon" type="image/x-icon" href="./images/log.ico" media="screen">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>嗨.音乐</title>
   <link rel="stylesheet" type="text/css" href="./fonts/font-awesome-4.7.0/css/font-awesome.min.css">
   <link rel="stylesheet" type="text/css" href="./plugins/swiper/swiper-bundle.min.css">
   <link rel="stylesheet" type="text/css" href="./css/base.css">
   <link rel="stylesheet" type="text/css" href="./css/index.css">
   <link rel="stylesheet" type="text/css" href="./css/header.css">
   <link rel="stylesheet" type="text/css" href="./css/login.css">
   <link rel="stylesheet" type="text/css" href="./css/main_show.css">
   <script src="./plugins/swiper/swiper-bundle.min.js"></script>
   <script src="./js/flexible.js"></script>
   <script src="./js/jquery.min.js"></script>
   <script src="./js/index.js"></script>
</head>
<body>
   <!--网页logo 介绍 首行-->
   <div class="head">
       <div class="head_nav">
           <a href="index.html">发现音乐</a>
           <a href="index.html">我的音乐</a>
           <a href="sub/shop.html" target="_blank">商城</a>
       </div>
       <!--导航部分-->
       <div class="nav" id="nav">

2. 为什么是Webpack?

Webpack系列之构建Webpack知识体系
image.png
  1. 深入学习 Webpack,不仅能帮助你更快解决具体的工程技术问题,还能形成属于你个人的,极具区分度的核心竞争力!
  2. Vite 一类 Unbundle 工具定位于解决特定问题,而 Webpack 则几乎无所不能,功能覆盖小程序、桌面应用、微前端、WASM 等诸多场景,许多情况下 Webpack 依然是最优解。
  3. 同类工具或多或少都有借鉴 Webpack 之处,虽然具体实现差异很大,但解决工程化问题的思路基本一致,所谓一通百通,深入理解 Webpack 底层逻辑,以及处理具体问题的方式方法后,相同的知识必然也能套用到同类工具中。
  4. Webpack 还在持续迭代发展,V5 之后推出的持久化缓存、lazyCompilation 等特性极大强化了构建性能,未来虽不大可能超越 Unbundle 方案的性能优势,但相信会逐渐缩小差距,直至可被用户接受。

3. Webpack 的优点

  • 所有资源都是 Module,所以可以用同一套代码实现诸多特性,包括:代码压缩、Hot Module Replacement、缓存等;
  • 打包时,资源与资源之间非常容易实现信息互换,例如可以轻易在 HTML 插入 Base64 格式的图片;
  • 借助 Loader,Webpack 几乎可以用任意方式处理任意类型的资源,例如可以用 Less、Stylus、Sass 等预编译 CSS 代码。
  • Webpack 具有极强的开放性,也让它得以成为前端工程化环境的 「基座」,我们可以围绕 Webpack 轻易接入一系列工程化工具,例如 TypeScript、CoffeScript、Babel 一类的 JavaScript 编译工具;或者 Less、Sass、Stylus、PostCSS 等 CSS 预处理器;或者 Jest、Karma 等测试框架,等等。
  • 自 2012 年首次发布至今,Webpack 还处于快速迭代成长阶段,社区依然保持极大活力;Webpack 已经发布了最新的 5.73.0 版本,经过 5 个大版本迭代以及社区的不断努力,现如今的 Webpack 已经非常非常成熟。

4. 如何学习 Webpack?

Webpack系列之构建Webpack知识体系
img

「1. 入门应用」

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

「2. 进阶」

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

「3. 大师级」

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

1、使用 Webpack

1. 第一个 Webpack项目

首先新建文件夹 wepack-test, 通过编辑器打开,文件结构:

├── src
|   └── index.js
└── webpack.config.js

填写内容: webpack.config.js

const path = require('path');
module.exports = {
 entry: './src/index.js', //项目入口文件
 mode: 'development', //环境
 devtool: false,
 output: { //输出目录
   filename: '[name].js',
   path: path.join(__dirname, './dist')
}
}

index.js

document.write("hello Webpack!");

进行项目初始化,安装 Webpack:在项目根目录下,打开终端,执行命令:

npm init # 一路回车
npm i -D webpack webpack-cli
Webpack系列之构建Webpack知识体系
image.png

在项目根目录下,打开终端,执行编译命令,构建项目:

npx webpack

执行成功输出生产文件:

Webpack系列之构建Webpack知识体系
image.png
Webpack系列之构建Webpack知识体系
image.png

2. 理解 Webpack配置项

「核心流程 — 极度简化版」

Webpack 原生提供了上百种配置项,这些配置最终都会作用于 Webpack 打包过程的不同阶段,因此我们可以从Webpack 编译流程来了解各项配置的作用。

Webpack系列之构建Webpack知识体系
image.png
  1. 入口处理:从 entry 配置项开始,启动编译流程
  2. entry 配置项所指定的入口文件开始,根据 requireimport 等语句找到依赖资源
  3. 根据 moudle 配置项,调用资源转移器,将 png、css 等非标准 JS 资源转译为 JS 内容
  4. 递归调用 1 2,指定所有引用的文件和非标准 JS 资源处理完毕
  5. 将转译后的资源内容合并打包为可直接在浏览器运行的 JS 文件

「webpack 特点 模块化 + 一致性」

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

「那么,怎么使用 Webpack?」

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

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

流程类配置项综述

与打包流程强相关的配置项有:

  • 输入输出:

    • entry:用于定义项目入口文件,Webpack 会从这些入口文件开始按图索骥找出所有项目文件;
    • context:项目执行上下文路径;
    • output:配置产物输出路径、名称等;
  • 模块处理:

    • resolve:用于配置模块路径解析规则,可用于帮助 Webpack 更精确、高效地找到指定模块
    • module:用于配置模块加载规则,例如针对什么类型的资源需要使用哪些 Loader 进行处理
    • externals:用于声明外部资源,Webpack 会直接忽略这部分资源,跳过这些资源的解析、打包操作
  • 后处理:

    • optimization:用于控制如何优化产物包体积,内置 Dead Code Elimination、Scope Hoisting、代码混淆、代码压缩等功能
    • target:用于配置编译产物的目标运行环境,支持 web、node、electron 等值,不同值最终产物会有所差异
    • mode:编译模式短语,支持 developmentproduction 等值,可以理解为一种声明环境的短语

这里的重点是,Webpack 「首先」需要根据输入配置(entry/context) 找到项目入口文件;「之后」根据按模块处理(module/resolve/externals 等) 所配置的规则逐一处理模块文件,处理过程包括转译、依赖分析等;模块处理完毕后,最后「再根据」后处理相关配置项(optimization/target 等)合并模块资源、注入运行时依赖、优化产物结构等。

这些配置项与打包流程强相关,建议学习时多关注它们对主流程的影响,例如 entry 决定了项目入口,而 output 则决定产物最终往哪里输出;resolve 决定了怎么找到模块,而 module 决定了如何解读模块内容,等等。

工具类配置项综述

除了核心的打包功能之外,Webpack 还提供了一系列用于提升研发效率的工具,大体上可划分为:

  • 开发效率类:

    • watch:用于配置持续监听文件变化,持续构建
    • devtool:用于配置产物 Sourcemap 生成规则
    • devServer:用于配置与 HMR 强相关的开发服务器功能
  • 性能优化类:

    • cache:Webpack 5 之后,该项用于控制如何缓存编译过程信息与编译结果
    • performance:用于配置当产物大小超过阈值时,如何通知开发者
  • 日志类:

    • stats:用于精确地控制编译过程的日志内容,在做比较细致的性能调试时非常有用
    • infrastructureLogging:用于控制日志输出方式,例如可以通过该配置将日志输出到磁盘文件

逻辑上,每一个工具类配置都在主流程之外提供额外的工程化能力,例如 devtool 用于配置产物 Sourcemap 生成规则,与 Sourcemap 强相关;devServer 用于配置与 HMR 相关的开发服务器功能;watch 用于实现持续监听、构建。

工具类配置内聚性较强,通常一个配置项专注于解决一类工程问题,学习时建议先对配置项按其功能做个简单分类,例如上述开发效率类、性能优化类等,之后再展开研究其可选值与效果。

Webpack系列之构建Webpack知识体系
img

3. 通过例子了解 Webpack 配置过程

「引入CSS预处理器,处理CSS资源」

首先搭建项目,示例文件结构:

.
├── src
|   ├── index.js
|   └── index.css
└── webpack.config.js

填写内容

index.js

import styles from './index.css' 

index.css

.box{
   width: 100px;
   height: 100px;
}

初始化项目,安装 Webpack

npm init # 一路回车
npm i -D webpack webpack-cli

安装 CSS 处理器 loader

npm add -D css-loader style-loader

配置 webpack.config.js

const path = require('path');
module.exports = {
 entry: './src/index.js',
 mode: 'development',
 devtool: false,
 output: {
   filename: '[name].js',
   path: path.join(__dirname, './dist')
},
 module: {
   //CSS处理器
   rules: [{
     test: /.css/i,
     use: [
       'style-loader',
       'css-loader'
    ]
  }]
}
}

在项目根目录下,打开终端,执行编译命令,构建项目:

npx wabpack
Webpack系列之构建Webpack知识体系
image.png

问题

  1. Loader 有什么作用?为什么这里需要用到 css-loader、style-loader?
  2. 与旧时代 —- 在 HTML 文件中维护 css 相比,这种方式会有什么优劣处?
  3. 有没有接触过 Less、Sass、Stylus 这一类 CSS 预编译框架?如何在 Webpack 接入这些工具?

回答

Loader有什么作用?

Webpack Loader 最核心的只能是实现内容转换器 —— 将各式各样的资源转化为标准 JavaScript 内容格式,例如:

  • css-loader 将 css 转换为 __WEBPACK_DEFAULT_EXPORT__ = ".a{ xxx }" 格式
  • html-loader 将 html 转换为 __WEBPACK_DEFAULT_EXPORT__ = "<!DOCTYPE xxx" 格式
  • vue-loader 更复杂一些,会将 .vue 文件转化为多个 JavaScript 函数,分别对应 template、js、css、custom block

为什么这里需要用到 css-loader、style-loader ?

  • 本质上是因为 Webpack 只认识符合 JavaScript 规范的文本(Webpack 5之后增加了其它 parser):在构建(make)阶段,解析模块内容时会调用 acorn 将文本转换为 AST 对象,进而分析代码结构,分析模块依赖;这一套逻辑对图片、json、Vue SFC等场景就不工作了,就需要 Loader 介入将资源转化成 Webpack 可以理解的内容形态。

与旧时代 —- 在 HTML 文件中维护 css 相比,这种方式会有什么优劣处?

  • 优点:统一管理
  • 缺点:耦合度高

有没有接触过 Less、Sass、Stylus 这一类 CSS 预编译框架?如何在 Webpack 接入这些工具?

  • 有,接入 less 示例,在理解loader章节叙述

「引入 Babel 处理 JS 兼容性问题」

Webpack系列之构建Webpack知识体系
图解

Babel 的作用: 用于将 JS 语法降级, 处理兼容性, 如将 ES6 规范,转换为 ES5 规范

为什么这样做:

  • JavaScript 语法标准繁多, 浏览器支持程度不一
  • 开发者需要用到高级语法

安装 babel 依赖

npm i -D @babel/core @babel/preset-env babel-loader

配置 webpack.config.js

const path = require('path');
module.exports = {
 entry: './src/index.js',
 mode: 'development',
 devtool: false,
 output: {
   filename: '[name].js',
   path: path.join(__dirname, './dist')
},
 module: {
   rules: [{ //less处理
     test: /.less$/i,
     use: [
       'style-loader',
       'css-loader',
       'less-loader'
    ]
  },{ //js处理 babel
     test: /.js?$/,
     use:[{
         loader: 'babel-loader',
         options:{
           presets:[
            ['@babel/preset-env']
          ]
        }
      }]
  }]
}
}

执行 npx webpack

Webpack系列之构建Webpack知识体系
image.png

问题

  1. Babel 具体有什么功能?
  2. Babel 与 Webpack 分别解决了什么问题? 为何能协作到一起?

回答

Babel 具体有什么功能 ?

  • Babel 插件大致分为两种:语法插件和转换插件。语法插件作用于 @babel/parser,负责将代码解析为抽象语法树(AST)(官方的语法插件以 babel-plugin-syntax 开头);转换插件作用于 @babel/core,负责转换 AST 的形态。

Babel 与 Webpack 分别解决了什么问题? 为何能协作到一起?

  • Babel 解决了项目的兼容性问题
  • Webpack 使项目模块化, 解决依赖问题
  • Webpack 主要是将非标准 JS 资源转译为 JS 内容,进行统一资源管理,而 JS 可能在不同浏览器上存在兼容问题,所以需要 Babel 来进行协作

「引入HTMLWebPackPlugin 生成 HTML」

安装 HTMLWebPackPlugin 插件

npm i -D html-webpack-plugin

配置 webpack.config.js

const path = require('path');
//引入 依赖
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
mode: 'development',
devtool: false,
output: {
  filename: '[name].js',
  path: path.join(__dirname, './dist')
},
module: {
  rules: [{ //less处理
    test: /.less$/i,
    use: [
       'style-loader',
       'css-loader',
       'less-loader'
    ]
  },{ //js处理
    test: /.js?$/,
    use:[{
        loader: 'babel-loader',
        options:{
          presets:[
            ['@babel/preset-env']
          ]
        }
      }]
  }]
},
//插件
plugins:[new HtmlWebpackPlugin()]
}

执行 npx webpack

Webpack系列之构建Webpack知识体系

问题

  1. 相比于手工维护 HTML 内容,这种自动生成的方式有什么优缺点?

回答

相比于手工维护 HTML 内容,这种自动生成的方式有什么优缺点?

  • 优点:简化了HTML文件的创建,无需手工维护 HTML 文件
  • 缺点:配置繁琐

「开启模块热替换工具,进行项目的实时预览」

HMR Hot Moudle Replacement — 模块热替换工具:热更新代码,当你修改代码保存后,会自动更新,实时显示

Webpack系列之构建Webpack知识体系

安装 devserver

npm install -D webpack-dev-server

配置 webpack.config.js

const path = require('path');
//引入 依赖
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
 entry: './src/index.js',
 mode: 'development',
 devtool: false,
 devServer:{
   hot: true, //开启热加载
   open:true
},
 watch:true, //持续监听代码改变生成新版本
 output: {
   filename: '[name].js',
   path: path.join(__dirname, './dist')
},
 module: {
   rules: [{ //less处理
     test: /.less$/i,
     use: [
       'style-loader',
       'css-loader',
       'less-loader'
    ]
  },{ //js处理
     test: /.js?$/,
     use:[{
         loader: 'babel-loader',
         options:{
           presets:[
            ['@babel/preset-env']
          ]
        }
      }]
  }]
},
 //插件
 plugins:[new HtmlWebpackPlugin()]
}

执行命令,运行项目至浏览器

npx webpack serve

「使用 Tree-Shaking 删除没有使用的代码」

Webpack系列之构建Webpack知识体系
形象解释-摇一摇树,清除落叶

Tree-Shaking 树摇 工具

把定义的代码,但没有进行使用,进行删掉

使用 Tree-Shaking, 配置 webpack.config.js

const path = require('path');
//引入 依赖
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
 entry: './src/index.js',
 mode: 'production', //使用树摇,注意把 模式改为 生产环境
 devtool: false,
 devServer:{
   hot: true, //开启热加载
   open:true
},
 optimization:{
   usedExports:true //开启 树摇
},
 watch:true, //持续监听代码改变生成新版本
 output: {
   filename: '[name].js',
   path: path.join(__dirname, './dist')
},
 module: {
   rules: [{ //less处理
     test: /.less$/i,
     use: [
       'style-loader',
       'css-loader',
       'less-loader'
    ]
  },{ //js处理
     test: /.js?$/,
     use:[{
         loader: 'babel-loader',
         options:{
           presets:[
            ['@babel/preset-env']
          ]
        }
      }]
  }]
},
 //插件
 plugins:[new HtmlWebpackPlugin()]
}

验证: 编写 index.js bar.js

//bar.js
let bar1 = '1';
let bar2 = '2';

export {
   bar1,
   bar2
}

//index.js
import {
   bar,
   bar2
} from './bar'

console.log(bar);

注意此时是生产环境,执行 npx webpack

Webpack系列之构建Webpack知识体系

以下效果是开发环境和生产环境的对比

Webpack系列之构建Webpack知识体系

其他工具

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

3、进阶篇:理解 Loader

1. 概述

问题:Webpack 只认识JS

Webpack系列之构建Webpack知识体系

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

2. 使用Loader

文件结构

├── src
|   ├── a.less
|   ├── b.less
|   └── index.js
└── webpack.config.js

引入 less

 npm install less less-loader -D 

配置 webpack.config.js

const path = require('path');
module.exports = {
 entry: './src/index.js',
 mode: 'development',
 devtool: false,
 output: {
   filename: '[name].js',
   path: path.join(__dirname, './dist')
},
 module: {
   //less处理器
   rules: [{
     test: /.less$/i,
     use: [
       'style-loader',
       'css-loader',
       'less-loader'
    ]
  }]
}
}

index.js

import styles from './a.less'

认识Loader — 链式调用

使用上,可以为某种资源文件配置多个 Loader,Loader 之间按照配置的顺序「从前到后(pitch),再从后到前依次执行」,从而形成一套内容转译工作流,例如对于下面的配置:

module.exports = {
 module: {
   rules: [
    {
       test: /.less$/i,
       use: [
         "style-loader",
         "css-loader",
         "less-loader",
      ],
    },
  ],
},
};
Webpack系列之构建Webpack知识体系
loader 执行流程

上述示例中,三个 Loader 分别起如下作用:

  • less-loader:实现 less => css 的转换,输出 css 内容,无法被直接应用在 Webpack 体系下
  • css-loader:将 css 内容包装成类似 module.exports = "${css}" 的内容,包装后的内容符合 JavaScript 语法
  • style-loader:做的事情非常简单,就是将 css 模块包进 require 语句,并在运行时调用 injectStyle 等函数将内容注入到页面的 style 标签

认识Loader :其它特性

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

参考:Webpack 原理系列七:如何编写loader

2. 编写loader

Webpack系列之构建Webpack知识体系Webpack系列之构建Webpack知识体系

3. 常见 Loader

站在使用角度,建议掌握这些常见的 Loader 的功能、配置方法

Webpack系列之构建Webpack知识体系
image.png

4、进阶篇:理解插件

1. 概述

插件是什么?

  • 插件是为了给程序提供一种扩展能力
  • 比如 Vs Code、Vue

甚至、Webpack 本身的很多功能都是插件来实现的,我们可以通过下图看出:

Webpack系列之构建Webpack知识体系
Webpack 编译流程

2. 使用插件

  1. 安装插件依赖 npm
  2. 在 webpack 配置,引入插件
  3. 创建插件实例
Webpack系列之构建Webpack知识体系
image.png

3. 写webpack插件

首先:插件围绕 “钩子“ 展开

Webpack系列之构建Webpack知识体系
image.png

钩子的核心信息:

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

时机: compier.hooks.compliation

参数:compliation

交互:dependencyFactories.set

Webpack系列之构建Webpack知识体系
image.png

5、总结

我们前面学了:

  • Webpack 的作用
  • 理解 Webpack 配置结构,学习关键配置项
  • Loader 的作用与常用 Loader
  • 插件基本形态与作用

推荐学习网址:

Webpack 官方文档[1]

Babel 官网[2]

Webpack 原理系列七:如何编写loader

Webpack 原理系列十:HMR 原理全解析

深入浅出 Webpack · 深入浅出[3]

Webpack 5 知识体系 – GitMind[4]

Reference

[1]

Webpack 官方文档: https://webpack.js.org/configuration/

[2]

Babel 官网: https://babeljs.io/

[3]

深入浅出 Webpack · 深入浅出: https://webpack.wuhaolin.cn/

[4]

Webpack 5 知识体系 – GitMind: https://gitmind.cn/app/doc/fac1c196e29b8f9052239f16cff7d4c7


原文始发于微信公众号(yanghi):Webpack系列之构建Webpack知识体系

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/226965.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!