涨薪面技:如何写 webpack 路径解析插件(2)

一、前文回顾

上文详细讲述了 webpack 中的 resolver 的由来及作用:

  1. webpack resolver 用于解析webpack 构建过程中的 request 对应的 模块及模块要对应的 loader 的资源路径用的,分为 normal resolver 和 loader resolver 两种类型;

  2. NMF.prototype.getResolver 负责获取 resolver,核心是通过 ResolverFactory.prototype.get 方法实现;

  3. 接着我们讨论了 ResolverFactory 类型的构造函数,重点在于声明钩子:

    • 3.1 resolveOptions: 用于修改定制 resolver 行为的配置对象;
    • 3.2 resolver:用于修改 resolver 默认行为;
  4. 详细讨论了 ResolverFactory.prototype.get 方法,内部会优先取用 typedCaches.direct/stringify 缓存,有则返回,没有则调用它 ResolverFactory.prototype._create 方法创建;

  5. ResolverFactory.prototype._create 方法内部主要是触发在 WebpackOptionsApply 中配置的 对应 type 的 resolver 选项对象,然后调用 ehanced-resolve 库提供的 Factory.create 方法创建 resolver;接着触发 resolverFactory.hooks.resolver 修改 resolver 的行为并且举例 ResolverCachePlugin;

以上是有关 webpack 中的 Resolver 相关的基础知识, resolve 是 webpack 中相当重要的一个组成部分,后面的几篇文章我们重点研究这个对象。今天这篇我们要研究 webpack 有关 resolver 的配置部分。

二、resolve 配置项和 resolver

在 webpack 中,我们通过 webpack.config.js.resolve、resolverLoader 两个配置对象,其中 resolve 属性用于配置常规的模块的解析器行为,resolveLoader 用于设置 loader 的解析器行为。

二者的配置子项相同,这里我们以 resolve 的配置为例!

2.1 resolve.alias

这个配置大家很常用,一般在开发中用于简化模块的导入路径,比如我们 src/components/ 目录,为了简化我们把他设置为 @:

ini 复制代码
const path = require('path');

module.exports = {
  //...
  resolve: {
    alias: {
      @: path.resolve(__dirname, 'src/components/')
    },
  },
};

经过这个后,我们可以用如下的方式进行导入:

js 复制代码
import someText from '@/someText.vue'

该特性由 enhanced-resolve 库中的 AliasPlugin 实现!

2.2resolve.aliasFields

译为"别名字段",也就是用着个指定某个构建目标对应的入口。当然这个特性也是由 AlisPlugin 实现的。

ini 复制代码
module.exports = {
  //...
  resolve: {
    aliasFields: ['browser'],
  },
};

指定一个字段,例如 browser,根据 此规范进行解析。

我从这个规范中摘抄了一段原文:

The browser field is provided by a module author as a hint to javascript bundlers or component tools when packaging modules for client side use.

啥意思嘞?我翻译一波:

browser 字段是由模块的作者提供的,用作指示打包工具(js bundler)或者组件工具所构建产物为客户端使用时,使用该字段指向的模块;(该模块是用在浏览器环境的)

有点拗口是不是,具体的我们后面再介绍 AliasPlugin 时还会再行展开!

2.3 resolve.conditionNames

这个有点意思,但是对于没怎么写过 npm 包或者 SDK 的同学来说有点陌生,这个配置相当于给大家实现了一个条件,最常见的就是区分 ESModule 和 CommonJS;

exports 配置项 (定义一个库的入口)的 conditionName。

我从 node 文档上摘抄了一段:

Conditional exports provide a way to map to different paths depending on certain conditions. They are supported for both CommonJS and ES module imports.

翻译一下就是:conditionalExports 提供了一种根据不同条件映射到不同路径的方式。支持 CommonJS 和 ESM 规范;

比如说,我们有一个包想提供一个给 ESModule 的导出,这个时候我们的 package.json 中要加入这段声明:

json 复制代码
// package.json
{
  "exports": {
    "import": "./index-module.js",
    "require": "./index-require.cjs"
  }
}

注意,以上是 Node.js 原生提供的能力,那对于 webpack 而言,也是需要拥有这个能力的,这个工作当然就需要 enhanced-resolve 来完成,因此有了这个配置:

java 复制代码
module.exports = {
  //...
  resolve: {
    conditionNames: ['require', 'import'],
  },
};

当然,要注意,webpack 这个是有优先级的,如 requrire 写在前面,则优先匹配 exports.require;

2.4 resolve.descriptionFiles

这个不新鲜,描述文件,这个一般都是 package.json ,一般也不会去制定它。如果你有这方面的诉求,比如你写了一个 .someDescFile 这种,需要 enhanced-resolve 识别可以设置一下;

2.5 resolve.enforceExtension

如果设置为 true,强制必须写扩展名,不允许写这种:

js 复制代码
import a from 'a';

2.6resolve.extensionAlias

一个将拓展名与拓展名别名映射的对象。

js 复制代码
module.exports = {
  //...
  resolve: {
    extensionAlias: {
      '.js': ['.ts', '.js'],
      '.mjs': ['.mts', '.mjs'],
    },
  },
};

把 .ts 和 .js 都当 .js 解析;该特性由 ehanced-resolve 内部的 ExtensionAliasPlugin.js 实现。

三、总结

从今天这篇小作文开始我们系统的学习 webpack 内部有关 resolve 的有关配置项目,本文包含以下配置:

  1. alias: 设置路径别名;
  2. aliasFields:设置别名字段;
  3. conditionalName:条件名;
  4. descriptionFiles:描述文件列表;
  5. enforceExtension:强制拓展名;
  6. extensionAlias:扩展名别名;
相关推荐
ggdpzhk1 小时前
VUE:基于MVVN的前端js框架
前端·javascript·vue.js
小曲曲2 小时前
接口上传视频和oss直传视频到阿里云组件
javascript·阿里云·音视频
学不会•3 小时前
css数据不固定情况下,循环加不同背景颜色
前端·javascript·html
EasyNTS4 小时前
H.264/H.265播放器EasyPlayer.js视频流媒体播放器关于websocket1006的异常断连
javascript·h.265·h.264
活宝小娜6 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点6 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow6 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o6 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app
刚刚好ā7 小时前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
yqcoder8 小时前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript