# Webpack5 开发环境 与 生产环境优化

TIP

本章节我们主要学习开发环境下可以做那些优化,给开发人员提供一个更好的体验。在生产环境下打包需要做那些优化,可以减少打包的时间,项目上线的体积等。

开发环境下,我们主要讲解以下几个方面的优化

  • 文件监听功能
  • webpack-dev-server 工具
  • 模块热替换
  • source-map

生产环境下,我们主要讲解以下几个方面的优化

  • 摇树优化 Tree Shaking
  • 资源压缩
  • 缩小查找范围

# 一、Webpack5 开发环境配置

TIP

学习开发环境的配置主要目的是为了给开发人员在开发项目时有一个更好的体验。

本章节我们讲解的开发环境配置有:文件监听与 webpack-dev-server 工具、模块热替换、source map。

每一项配置的具体功能如下表:

配置项 描述
文件监听 Webpack提供了开启文件监听模式的功能后,当我们修改保存项目代码时,会自动进行重新构建,而不需要再次执行npx webpack命令
webpack-dev-server 工具 当安装并启用 webpack-dev-server 后,它会自动帮我们执行npx webpack打包命令完成打包工作,同时还会开启 Webpack 的文件监听模式。最终通过开启一个本地服务器来加载构建完成的资源文件,它还有代理请求等功能。
模块热替换 可以在不刷新浏览器页面情况下,做到局部刷新,只刷新修改过的模块部分的内容,实现实时预览。
source map 通过 Webpack 打包后生成的代码与我们的源码完全不一致,可读性很差。当我们需要对这些代码进行调试时,就很麻烦。而 source map 可以帮我们把打包后的代码与源码作一一映射,快速找到问题。

# 1、文件监听

TIP

Webpack提供了开启文件监听模式的功能后,当我们修改保存项目代码时,会自动进行重新构建,而不需要再次执行npx webpack命令

开启文件监听模式最简单的方法就是在执行npx webpack打包的时候,在后面带上--watch这个参数。

npx webpack --watch

接下来,我们通过一个案例了解监听模式的具体功能

  • 项目目录结构
icod
├─ node_modules
├─ package-lock.json
├─ package.json
├─ src
│  └─ index.js
└─ webpack.config.js
  • index.js文件内容
const username = "icoding";
console.log(username);
  • package.jsondevDependencies字段信息如下:
"devDependencies": {
    "webpack": "^5.76.3",
    "webpack-cli": "^5.0.1"
  }
  • webpack.config.js文件内容如下
const path = require("path");
module.exports = {
  mode: "none",
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "bundle.js",
  },
};

# 1.1 在命令行开启文件监听模式

TIP

项目创建好后,我们在当前目录下执行以下命令开始打包

npx webpack --watch

以上命令就相当于开启了 Webpack 的文件监听模式,同时完成了打包工作。在 dist 目录下生成了bundle.js文件,仔细观察命令行窗口。

如下图:

image-20230327174621941

会发现 Webpack 的构建信息与以往不同。该命令行构建程序并没有自动退出,而且这个时候不能再执行其它命令。

接下来,我们把index.js文件里username变量的值由icoding改成艾编程,然后保存进行观察。观察命令行,发现 Webpack 自动进行了重新构建,命令行窗口提示了新的构建信息,如下:

image-20230327175115904

这时候我们再查看bundle.js文件,发现里面变量username的值也变成了艾编程

# 1.2 在 Wepack 配置文件中开启文件监听模式

TIP

Webpack 开启文件监听模式的方式,除了上面的命令行模式外,还可以在 Webpack 的配置文件里开启。具体设置如下:

点击 查阅官方文档 (opens new window)

const path = require("path");
module.exports = {
  mode: "none",
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "bundle.js",
  },
  // 开启文件监听模式
  watch: true,
};

注:

不过我们很少在配置文件里配置,因为在实际的开发中,我们并不会选择这种方式来开启文件监听模式,而是会采用接下来进的webpack-dev-server工具

# 2、DevServer 工具

TIP

webpack-dev-server是 Webpack 官方提供的一个 Webpack 服务工具,一般也称它为 DevServer。

当安装并启用webpack-dev-server后,它会自动帮我们执行npx webpack打包命令完成打包工作,同时还会开启Webpack的文件监听模式。最终通过开启一个本地服务器来加载构建完成的资源文件,它还有代理请求等功能。

具体的安装和使用(配置)教程 可查阅官方文档 (opens new window)

# 2.1、DevServer 的使用

首先我们需要执行以下命令,安装webpack-dev-server

npm install --save-dev webpack-dev-server

接下来,我们在前一个项目的基础上,在src文件夹下面新建index.html页面,页面内容如下:

<body>
  网站首页
</body>

然后修改webpack.config.js配置文件内容如下:

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
  mode: "none",
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "bundle.js",
  },
  // watch:true
  plugins: [
    new HtmlWebpackPlugin({
      template: "./src/index.html",
      filename: "index.html",
    }),
  ],
};

记得还要安装html-webpack-plugin插件。

然后,我们在当前目录下执行以下命令

npm install --save-dev webpack-dev-server

以上命令执行后,它会自动帮我们执行npx webpack打包,同时开启了 Webpack 的文件监听模式。同时开启一个本地服务器来加载构建完成的资源文件。

观察命令行终端信息,提示信息如下:(截取了部分内容)

image-20230327184911388

我们在浏览器中打开http://localhost:8080/地址,可以正确的访问到index.html页面,具体如下截图:

image-20230327185138768

注意事项

我们并没有在根目录下看见dist目录,是因为webpack-dev-server在编译之后不会写入到任何输出文件。

而是将 bundle 文件保留在内存中,然后将它们 serve 到 server 中,就好像它们是挂载在 server 根路径上的真实文件一样。

当我们访问http://localhost:8080/地址,默认访问的是output.path指定目录下的index.html文件

接下来我们修改index.html页面的内容为如下:

<body>
  网站首页内容更新
</body>

保存后,发现浏览器中访问的index.html页面内容并没有变化。当我们把index.jsusername变量的

值由icoding改为艾编程后并保存,这时bundle.jsusername变量的值变为了艾编程,同时浏览器中访问的index.html页面内容也更新为最新内容了。

只有打包入口文件相关的依赖文件中的内容被更改后,才会自动开启重新打包。

# 2.2、DevServer 的常用参数

TIP

DevServer 除了上述默认行为,它还支持自定义参数,通过配置相关参数,可以改改变其行为。

常用的参数有以下:

参数 说明
open 是否自动在浏览器中打开服务,true 为自动打开
port 指定 Web 服务运行的端口号
compress 可设定是否为静态资源开启 Gzip 压缩。
static 用于设置静态文件的目录
hot 开启模块热替换功能,后面单独来讲

接下来,我们通过代码来演示下。我们在上面项目的基础上,在当前目录下新public文件夹,然后在public文件夹下新建index.html页面。

最后项目的目录结构如下:

icoding
├─ node_modules
├─ package-lock.json
├─ package.json
├─ public
│  └─ index.html
├─ src
│  ├─ index.html
│  └─ index.js
└─ webpack.config.js

接下来,我们更改webpack.config.js文件中的配置如下:

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
  mode: "none",
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "bundle.js",
  },
  // watch:true
  plugins: [
    new HtmlWebpackPlugin({
      template: "./src/index.html",
      filename: "index.html",
    }),
  ],
  devServer: {
    // 自动打开浏览器
    open: true,
    // 服务的端口号
    port: 8809,
    // 为静态资源开启Gzip压缩
    compress: true,
    // 静态资源访问路径,必需在当前磁盘上存在对应的目录
    static: {
      // 告诉服务器从哪里提供内容,只有在你希望提供静态文件时才需要这样做
      directory: path.resolve(__dirname, "public"),
      // 告诉服务器在哪个 URL 上提供 static.directory 的内容
      // 比如:通过http://localhost:8809/assets/可以访问当前目录下public文件夹中内容
      publicPath: "/assets",
    },
  },
};

最后在当前目录下执行npx webpack serve命令,会新开一个浏览器窗口打开output.path目录下的index.html文件,访问地址是:http://localhost:8809

如果想要访问当前目录下的public文件夹中的内容,可以能过 http://localhost:8809/assets/ 地址访问,该地址默认访问的是public下面的index.html文件,如果需要访问该目录下其它资源,手动修改访问题到该资源就好。

温馨提示:

  • 只有在你希望提供静态文件时才需要配置 static 配置。
  • 如果我们只想访问打包后生成的资源,不用做任何路径相关配置,因为这些打包的资源在内存中,并且访问地址会默认映射到该内存地址访问打包后的资源。

# 2.3、模块热替换

TIP

在上面我们使用webpack-dev-server实现了当内容更新后,会自动刷新整个页面的功能,从而做到了实时预览代码修改后的效果。

Webpack 还有一种更高级的方式来做到实时预览,那就是模块热替换。这种技术不需要重新刷新整个页面,而只是通过重新加载修改过的模块来实现实时预览。该技术称为模块热更新,英文名称是Hot Module Replacement,简称 HMR。

在 Webpack5 中,我们只需要在devServer配置中,添加hot选项,将他的值设为 true,就可以开启模块热更新功能。

具体如下:

devServer: {
  // ....
  // 开启模块热更新
  hot: true;
}

不过,在前端项目里,开启模块热替换功能后,我们还需要在使用模块热替换功能的模块中,添加以下代码来触发模块的自更新。

// module.hot 为HotModuleReplacementPlugin插件暴露的接口,是一个对象
// 在webpack5之前,需要安装HotModuleReplacementPlugin插件,在webpack5中只要开启模块热替换,就会自动加载这个插件
// 以下代码表示,只有在开启了模块热替换,才执行accept方法,否则不执行
if (module.hot) {
  module.hot.accept(); // 触发自身更新
}

注:

关于模块热替换相关的配置 查阅官方文档 (opens new window)

# 2.3.1 、使用模块热替换

接下来,我们通过一个案例来演示。

我们在上一个项目的基础上,更新index.js文件的内容如下:

import { password } from "./login.js";
const username = "icoding";
console.log(username);
console.log(password);

同时在src目录下新建login.js文件,内容如下:

export const password = 123456;
console.log(password);
// 只有在启用了模块热替换更能,再执行下面方法触发热替换
if (module.hot) {
  module.hot.accept(); // 触发当前模块自身热更新
}

最后,当前项目的目录结构如下

icoding
├─ node_modules
├─ package-lock.json
├─ package.json
├─ public
│  └─ index.html
├─ src
│  ├─ index.html
│  ├─ index.js
│  └─ login.js
└─ webpack.config.js

最后,我们在当前目录执行npx webpack serve命令后,会在浏览器窗口自动打开index.html页面。查看当前页的控制台,可以看到输出的内容如下:

image-20230328221120330

接下来,我更新login.js内容如下

export const password = 12345678;
console.log("更新", password);
// 只有在启用了模块热替换更能,再执行下面方法触发热替换
if (module.hot) {
  module.hot.accept(); // 触发当前模块自身热更新
}

image-20230328221336215

接下来,我把index.js文件的内容更新如下:

import { password } from "./login.js";
const username = "艾编程";
console.log(username);
console.log(password);

image-20230328221439185

# 3、source map

TIP

利用 Webpack 编译打包后的代码,会添加很多与原始代码无关的代码。如果我们的原始代码一旦有错,在调试的时候就很难找到错误,因为我们是在打包后的代码上进行调试的。

要想在浏览器里能直接看到打包前的原始代码,在原始代码上进行调试,这就需要用到source map

我们在上面代码的基础上,修改index.js中的代码如下:

import { password } from "./login.js";
const username = "艾编程";
debugger; // 设置断点
console.log(s);
console.log(username);
console.log(password);

注:

接下来,我们在当前目录执行npx webpack打包,打包后,我们在浏览器中打开index.html页面,发现控制台抛出错误。假设我们现在不清楚为什么出现这个错误,我们就需要通过打断点来调试错误。

接下来,我们切换到Sources面板,然后点击bundle.js,我们发现当前的代码有 4000 多行,我们根本不知道从哪里打断点来调试我们的代码。

还好我们刚才在代码中手动设置了断点,我们重新刷新下页,就能看到代码中打断点的位置,但这还是很难调试。

# 3.1 、使用 source map

TIP

要使用 source map 只需要Webpack的配置文件中。

添加以下配置即可:

module.exports = {
  // ....
  devtool: "source-map",
};

接下来,在当前根目录下,执行npx webpack命令再重新打包,打包成功后,刷新 index.html 页面,观察Sources面板,如下图:

image-20230328233043555

注:

观察上图,我们发现多了一个index.js文件,也就是打包前的原始代码。

并且在调试时,可以直接在index.js文件上打断点调试,非常方便。

# 3.2、devtool 的值

TIP

因为 devtool 后面的值非常多,所以我们在实际开发中,具体应该选择使用那个值,建议大家参考官方给推荐的,每一种值为什么被推荐,官方给出了明确说明。 详细 查阅官方文档 (opens new window)

以下是我从官网简单摘录,关于第一种环境下的推荐的 devtool 值。

推荐
开发环境下使用的值 evaleval-source-mapeval-cheap-source-mapeval-cheap-module-source-map
生产环境下使用的值 nonesource-maphidden-source-mapnosources-source-map(注意看每一种值后面对应的禁告信息,一定不要让用户能访问到 source-map 文件,会暴露源码,很不安全)
针对一些特定场景使用的值 inline-source-mapcheap-source-mapcheap-module-source-mapinline-cheap-module-source-map

生产环境下,一般是不会选择source-map的,所以更推荐大家使用 none

# 二、Webpack 生产环境优化

TIP

深入浅出 Webpack 生产环境的优化 和 实践

# 1、摇树优化 Tree Shaking

TIP

在实际开发中,我们通常会用到一些第三方的工具函数,如果没有经过任何特殊处理的话,打包时会引入整个包。但实际开发中我们可能只用到了里面极小部分的功能(API),这样将整个工具函数的代码都打包进来,体积就太大了。

有没有什么办法,只帮我们引入在我们的代码中用到的那部分代码呢 ?有,那就是我们接下来讲到的Tree Shaking

Tree Sharking可以帮我们检测模块中没有用到的那块代码,并在 Webpack 打包时将没有使用到的代码块移除,减小打包后的资源体积。它的名字也非常形象,通过摇晃树,把树上干枯无用的叶子摇掉。

Webpack5 中内置了这个功能,在生产环境打包时,Webpack 会自动开启Tree Shaking功能,将没有用到的那部分代码给删除。

我们创建一个简单的项目来演示下

  • 当前项目目录结构如下
icoding
├─ node_modules
├─ package-lock.json
├─ package.json
├─ src
│  └─ index.js
└─ webpack.config.js
  • index.js文件的代码如下
function max(a, b) {
  return a > b ? a : b;
}
function min(a, b) {
  return a > b ? b : a;
}
console.log(1);
  • package.json文件内容如下:
 "devDependencies": {
    "webpack": "^5.76.3",
    "webpack-cli": "^5.0.1",
  }
  • webpack.config.js文件内容如下:
const path = require("path");
module.exports = {
  mode: "production",
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "bundle.js",
  },
};

接下来,在当前根目录下执行npx webpack打包,打包后生成的bundle.js文件内容如下:

console.log(1);

观察以上代码,我们可以得出,没有用到的minmax函数,都被删除了。

# 2、资源压缩

TIP

资源压缩的主要目的是减小文件体积,以提升页面加载速度或降低带宽消耗等。资源压缩通常发生在生产环境打包的最后一个环节,开发环境打包是不需要进行资源压缩处理的。

资源压缩主要是对 HTML、JS、CSS 文件、图片进行压缩,通常的做法就是整个文件或大段的代码压缩成一行,比如:去掉空格,空行,删除注释,把较长的变量名替换成较短的变量名等。

图片这类静态资源,一般在项目上线后会交由服务端来处理,不需要我们处理。

接下来,我们创建一个简单的项目来演示下

项目结构如下:

icoding
├─ node_modules
├─ package-lock.json
├─ package.json
├─ src
│  ├─ basic.css
│  ├─ index.html
│  └─ index.js
└─ webpack.config.js
  • index.html文件核心内容如下:
<body>
  网站首页
</body>
  • index.js文件内容如下:
import "./basic.css";

const username = "icoding";
const password = 123456;
function login(username, password) {
  if (username === "icoding" && password === 123456) {
    console.log("登录成功");
  } else {
    console.log("登录失败");
  }
}
login(username, password);
  • basic.css文件内容如下:
.box1 {
  width: 100px;
  height: 100px;
  background-color: skyblue;
  border: 20px solid khaki;
  font-size: 20px;
  padding: 20px;
  margin: 20px;
}

.box2 {
  width: 100px;
  height: 100px;
  background-color: skyblue;
  border: 20px solid khaki;
  font-size: 20px;
  padding: 20px;
}
  • package.json 文件的核心内容如下:
 "devDependencies": {
    "css-loader": "^6.7.3",
    "html-webpack-plugin": "^5.5.0",
    "mini-css-extract-plugin": "^2.7.5",
    "webpack": "^5.76.3",
    "webpack-cli": "^5.0.1",
    "webpack-dev-server": "^4.13.1"
  }
  • webpack.config.js文件内容如下:
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
  mode: "none",
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "bundle.js",
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./src/index.html",
      filename: "index.html",
    }),
    new MiniCssExtractPlugin(),
  ],
};

# 2.1、JS 压缩

TIP

在 Webpack5 中,当我们开启生产环境打包时,JS 代码会自动做压缩处理,并不需要做任何配置。是因为,在安装 Webpack5 时,会自动安装terser-webpack-plugin插件,同时在生产环境下打包时,Webpack5 会自动使用这个插件来对 JS 做压缩处理。

如果我们不想在生产环境打包时,对 JS 做压缩处理,我们只需要webpack.config.js文件中添加如下配置,就可以。

module.exports = {
  // 相关的优化配置,在这里配置
  optimization: {
    // 不使用插件压缩代码
    // 默认值为true,表示使用terser-webpack-plugin 插件来对JS代码压缩。
    minimize: false,
  },
};

# 2.2、CSS 压缩

TIP

默认配置下,Webpack5 在生产环境打包下,并不会对 CSS 做压缩处理。

我们需要借助第三方插件:css-minimizer-webpack-plugin来帮我们对 CSS 做压缩处理。

首先,我们需要执行以下命令,安装css-minimizer-webpack-plugin插件需要的包

npm install css-minimizer-webpack-plugin --save-dev

接下来,我只按以下步骤修改webpack.config.js文件,来完成相关插件配置就可以

  • 使用require方法,来加载插件
  • optimization选项中通过minimizeminimizer属性,告诉 Webpack 需要使用minimizer中的插件来压缩代码。
module.exports = {
  // ....
  optimization: {
    // 使用插件压缩代码
    minimize: true,
    // 提供一个或多个压缩插件,来对打包后的文件作相关压缩,不过会覆盖默认的插件
    // 也就是,这样设置后,CSS代码确实压缩,但是JS代码确没有被压缩了
    minimizer: [new CssMinimizerPlugin()],
  },
};

当我们在当前目录执行npx webpack来打包时,打包后的 css 代码确实压缩,压缩后代码如下:

/* css压缩后 */
.box1 {
  margin: 20px;
}
.box1,
.box2 {
  background-color: skyblue;
  border: 20px solid khaki;
  font-size: 20px;
  height: 100px;
  padding: 20px;
  width: 100px;
}

但是 JS 代码确没有被压缩了。是因为minimizer:[new CssMinimizerPlugin()]设置,覆盖了默认的 JS 压缩插件。

如果想要 JS 和 CSS 都能被压缩,则需要在minimizer对应数组中添加 JS 压缩插件。官方说明文档中提到,可以在 optimization.minimizer 中可以使用 '...' 来访问默认值(JS 压缩插件)。

接下来我们把webpack.config.js配置文件中optimization项的内容,修改如下:

module.exports = {
  optimization: {
    minimize: true,
    // ...表示,webpack5自带的JS压缩插件
    minimizer: [new CssMinimizerPlugin(), "..."],
  },
};

最后,我们再在当前目录下执行npx webpack打包,打包后的 JS 与 CSS 都做了压缩处理。

# 2.3、HTML 压缩

TIP

还记得,在前面学习html-webpack-plugin插件时,在这个插件中通过配置minify参数,就可以控制打包后的 HTML 代码是否需要做压缩处理。

如果minify的值为false表示不对打包后的 HTML 压缩,true表示做压缩处理。他的默认值就是 true,所以如果要做压缩处理,也可以不用写这个配置。

plugins:[new HtmlWebpackPlugin({
        template:"./src/index.html",
        filename:"index.html",
        // minify的值为false表示不对打包后的HTML压缩,true表示压缩
    	// 默认值就是true,所以如果要做压缩处理,也可以不用写这个配置
        minify:true
    }),new MiniCssExtractPlugin() ],

# 3、缩小查找范围

TIP

在 Webpack 打包时,我们可以通过以下几个方面来减少打包所需要的时间

  • 排除那些不需要被预处理器解析的模块
  • 帮助 Webpack 快速找到需要的模块
  • 帮助 Webpack 识别不带后缀名的文件

接下来,我们就从上面三个方向来讲解一些常见的缩小查找范围的方法

# 3.1 配置预处理器的 exclude 与 include

TIP

在使用预处理器解析模块的时候,可以通过配置 exclude 和 include 来减少需要预除理的模块。

  • exclude: 排除不需要使用当前预处理器来处理的文件夹目录
  • include:指定当前预处理器只对哪些目录中匹配的文件做预处理

当 exclude 与 include 同时指定时,以 exclude 的设置为主

module.exports = {
  // ....{
  module: {
    rules: [
      // 预处理器
      {
        test: /\.js$/,
        exclude: /node_modules/,
        include: /src/,
        use: {
          loader: "babel-loader",
        },
      },
    ],
  },
};

# 3.2、module.noParse

TIP

在实际开发中,我们有可能用到第三方模块,这些模块本身没有依赖任何的第三方模块(内部使用 import 或 require 关键字),所以不需要再用相关的预处理器来解析。

module.noParse:可以让 webpack 忽略对部分没有采用模块化的文件的递归解析和处理,以提高构建性能

modlue.noParse 的值可以是字符串,正则表式和数组。具体设置如下:

module.exports = {
  // ....
  module: {
    noParse: /login/, // login.js文件不需要解析,其内部内有使用第三方模块
  },
};

我们来看下面这个例子

  • 项目目录结构

icod
├─ node_modules
├─ babel.config.json
├─ package-lock.json
├─ package.json
├─ src
│  ├─ index.js
│  ├─ login.js
│  └─ search.js
└─ webpack.config.js
  • index.js 文件
import "./login";
const a = 1;
const b = 2;
console.log(a, b);
  • login.js文件
import "./search";

const username = "icoding";
const password = 123456;
console.log(username, password);
  • search.js文件
const n = 1;
const m = 2;
console.log(1, 2);
  • package.json文件内容
 "devDependencies": {
    "@babel/core": "^7.21.3",
    "@babel/preset-env": "^7.20.2",
    "babel-loader": "^9.1.2",
    "webpack": "^5.76.3",
    "webpack-cli": "^5.0.1"
  }
  • webpack.config.js文件内容
const path = require("path");

module.exports = {
  mode: "none",
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "[name].js",
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env"],
          },
        },
      },
    ],
    // login文件中,不需要再递归解析
    noParse: /login/,
  },
};

注:

最后执行在当前目录执行npx webpack命令打包,发现在打包后的main.js文件中,还保留了import './search'语句,说明打包时,并没有对login.js文件进行递归解析。

当然,这样打包后的内容肯定是有问题的,所以我们要指定某个文件不需要被解析的前提是,这些问呢件内部没有使用importrequire这样的语句。

# 3.3、resolve.modules

TIP

  • resolve.modules 用来配置 Webpack 如何搜寻第三方模块的路径。
  • resolve.modules 的值可以是相对路径,也可以是绝对路径,他的默认值是['node_modules']这是一个相对路径。

当我们使用 import 等语句来加载第三方模块时,如下:

import axios from 'axios'

上面代码表示,Webpack 在打包时,默认会在当前目录的./node_modules下搜索 axios 模块,如果没有找到,则会到上一级目录../node_modules下找,如果还没找到,则会再去../../node_modules下找,以此类推,直到找到为止。如果找不到,最后就会抛出错误。

我们的第三方模块都是保存在项目根目录的node_modules下,因此没有必要一级一级向上找。主要考虑的时,当我们的地址写错时,一层一层向上找,最后找不到再抛出错误,浪费了大量的时间。所以,我们可以指定第三方模块的搜索地址为绝对地址,就是我们当前项目目录下的node_modules文件夹中找,找不到就直接抛错,

以下是resolve.modules的配置

module.exports = {
  // ...
  resolve: {
    modules: [path.resolve(__dirname, "node_modules")],
  },
};

# 3.4、resolve.extensions

TIP

在我们引入(导入)自定义模块时,我们通常会采用以下简写形式

import { username } from "./login";

以上代码并没有指定 login 文件的后缀名是以.js还是.json等其它格式。那 Webpack 是如何知道这个文件最后是以.js结尾的后缀名呢?

resolve.extensions就是 Webpack 识别不带后缀名文件的关键。他的默认值是:['.js', '.json', '.wasm']

Webpack 在解析到这些不带后缀名的文件后,会按数组['.js', '.json', '.wasm']中的元素从头到尾的顺序尝试找到对应的文件,如果找到了,后面的格式就不匹配了,如果没找到一直往后匹配,直到找到为止。如果都匹配完还没找到就会抛出错误。

如果resolve.extensions指定的数组中的项越多,那 Webpack 尝试搜寻的次数就越多,这会影响 Webpack 的解析速度。所以我们可以根据我们的实际项目来合理的配置resolve.extensions的值。

配置的规则:

  • 出现频率高的放在最前,以免能最快找到对应文件
  • 没有用到的后缀名,不要出现,这样在找不到对应文件后,会尽快抛出错误。

如果很在乎这些解析时间,那最好是在导入语句中带上后缀名。

配置代码如下:

module.exports = {
  //...
  resolve: {
    extensions: [".js", ".css", ".json"],
  },
};
上次更新时间: 6/8/2023, 9:23:17 PM

大厂最新技术学习分享群

大厂最新技术学习分享群

微信扫一扫进群,获取资料

X