「青训营」Webpack 知识体系

170 阅读4分钟

什么是 Webpack

前端项目由各式各样的资源组成,包括 png,js,ts,jsx,vue,css,less 等等,早期项目需要手动通过 script,img 等标签来引入各种文件。外部资源特别多时,我们需要手动管理,要考虑文件顺序等问题,特别容易出错。这样做影响了开发效率,限制了项目的规模。

image.png

为了解决这些问题,出现了很多工程化工具。正是因为这些工具的出现,有了前端工程化的概念。

Webpack 是前端资源的编译和打包工具。编译是为了将图片、less、sass、ts 等非 JS 文件转变成标准的 JS 内容。之后将编译好的内容打包成一个文件 bundle。Webpack 刚出现的时候,浏览器不支持 ESM 模式,当时将资源放到浏览器运行需要逐个引入 script,使用 Webpack 打包好后只需要插入一个 script。

使用 Webpack

示例

使用 Webpack 主要分三步:安装、编辑配置文件、执行编译命令。

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

module.exports = {
  // 打包的入口
  entry: './src/index',
  // 打包模式 development 和 production,默认为 production
  mode: 'development',
  devtool: false,
  // 打包的出口
  output: {
    filename: '[name].js',
    path: path.join(__dirname, './dist')
  }
}
  1. 执行编译命令
npx webpack

待编译的文件:

// src/index.js
import bar from './bar'

console.log(`hello ${bar}`)
// src/bar.js
export default 'bar'

编译的结果:

// dist/main.js
// ...
__webpack_require__.r(__webpack_exports__);
// ...
const __WEBPACK_DEFAULT_EXPORT__ = ('bar')
// ...
console.log(`hello ${_bar__WEBPACK_IMPORTED_MODULE_0__["default"]}`)

打包后 import 语句会转为 __webpack_require__ 语句,两个文件被合并为一个。

核心流程

image.png

资源解析就是调用 loader 的过程。

Webpack 主要做两件事情:模块化、一致性。

模块化是指将不同类型的文件都用 import 和 require 来管理,一致性是指 Webpack 支持非 JS 语言,像 TypeScript,图片,CSS,字体等资源的合并打包。

配置总览

Webpack 的使用方法主要围绕配置展开,配置大致分为两类:

流程类:作用于流程中的某个环节,直接影响打包效果的配置项。

工具类:主流程之外,提供更多工程化能力的配置项。

image.png

image.png

1. 处理 CSS

  1. 安装 loader
npm add -D css-loader style-loader
  1. 添加 module 处理 CSS 文件
// webpack.config.js
const path = require('path')

module.exports = {
  // ...
  module: {
    rules: [{
      // 过滤条件,满足 test 规则的才使用 rule 处理
      test: /\.css$/,
      // 用什么 loader 去处理满足 test 的文件
      use: ["style-loader", "css-loader"]
    }]
  }
}
  1. 执行 npx webpack

待处理的文件:

// index.js
import styles from './index.css'

2. 接入 Babel

Babel 是代码转译工具,用于将 ES6 的代码编译成 ES5 的代码。

  1. 安装依赖
npm i -D @babel/core @babel/preset-env babel-loader
  1. 声明产物出口 output
const path = require("path");
module.exports = {
  entry: "./src/index",
  output: {
    filename: " [ name].js",
    path: path.join(__dirname, "./dist"),
  },
  module: {
    rules: [{
      test: /\.js?$/,
      use: [{
        loader: ' babel-loader',
        options: {
          presets: [
          // preset 是提前打包好的规则集
            ['@babel/preset-env']
          ]
        }
      }]
    }],
  },
};
  1. 执行 npx webpack

3. 生成 HTML

使用插件自动生成 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"),
  },
  // 生成 HTML
  plugins: [new HtmlwebpackPlugin()]
};
  1. 执行 npx webpack

4. HMR

HMR 是指 Hot Module Replacement 模块热替换,编写的代码可以立刻被更新到浏览器上,不需要刷新。

  1. 开启 HMR
module.exports = {
  // ...
  devServer: {
    // 开启 HMR
    hot: true
  }
  // webpack 持续监听文件的变化并持续构建
  watch: true
};
  1. 启动 Webpack
npx webpack serve

5. Tree-Shaking

用于删除 dead code,也就是没有用到的代码。

module.exports = {
  // ...
   mode: "production"
   optimization {
     usedExports: true
   }
 };

理解 Loader

Webpack 只认识 JS,Loader 的作用是做内容的转换,它将非标准的 JS 资源翻译为标准 JS。

使用 Loader:处理 less 文件

  1. 安装 Loader
npm add -D css-loader style-loader less-loader
  1. 添加 module 处理 less 文件
module.exports = {
  module: {
    rules: [{
      test: /\.less$/i,
      use: ["style-loader", "css-loader", "less-loader"],
    }],
  },
};

这三个 loader 符合链式调用的规则:

image.png

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

其他特性:

image.png

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

执行阶段从数组的最后一位向前进行。

编写 Loader:

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

理解插件

使用插件的目的是提升应用的可扩展性,体现了对拓展开放、对修改关闭的思维。插件是在 Webpack 的整个生命周期都会生效的组件。

使用插件:Dashboard

// npm i -D webpack-dashboard
// Import the plugin:
const DashboardPlugin = require("webpack-dashboard/plugin");
// Add it to your webpack configuration plugins.
module.exports = {
  // ...
  plugins: [new DashboardPlugin()]
  //...
};

编写插件的过程围绕钩子展开,包括钩子的时机、上下文、交互。

学习 Webpack

Webpack 入门的关键知识点:

image.png