module-alias的原理及应用是什么,常见问题有哪些
Admin 2022-07-29 群英技术资讯 702 次浏览
首先有必要介绍一下module-alias
是什么,这里有其官网链接(官网地址 https://github.com/ilearnio/module-alias)。
简单点说,module-alias
提供了在node
环境下的路径别名功能。一般前端开发可能会比较熟悉webpack
的alias
配置、typescript
的paths
配置等,这些都是提供了陆军别名的功能。路径别名在代码开发过程中是yyds,不然你看到这种../../../../xx
路径时,是肯定会抓狂的。
使用webpack
打包的项目webpack
本身会处理源代码中路径别名的配置到打包后代码的转换过程,但是如果单纯使用typescript
进行编译的项目,虽然typescript
在编译过程中可以正常处理paths
中路径别名的配置,但是并不会改变打包后的代码,造成在打包后的代码中仍然存在路径别名配置,看一个经过typescript
编译后的代码:
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); require("./module-alias-register"); var commands_1 = require("@/commands"); var package_json_1 = require("../package.json"); (0, commands_1.run)(package_json_1.version);
这里是tsconfig.json
的配置内容
"paths": { "@/*": [ "src/*" ] }
可以看到在经过typescript
编译后的代码中,仍然存在@符号,然而当代码运行的过程中,比如允许在node
中,require
并不能正常识别路径里的这个符号,导致找不到相应模块而抛出异常。
这也是module-alias
这个库存在的目的。
从官网上看,这个库使用方法只需要两步,真的已经是极简状态了。
1、路径别名配置:module-alias
支持两种路径别名配置方式
在package.json
中增加_moduleAliases
属性进行配置
"_moduleAliases": { "@": "./src" }
通过提供的API接口addAlias
、addAliases
、addPath
,增加配置
moduleAlias.addAliases({ '@' : __dirname + './src', });
2、在项目启动时首先导入该库:require(module-alias/register)
即可,当然选择使用API方式的需要导入对应的函数进行处理
一般我们都是使用package.json
中配置路径别名 + 项目入口处require(module-alias/register)
来使用这个库。
module-alias
通过覆写了全局对象Module
上的方法_resolveFilename
来实现路径别名的转换,简单来说就是通过拦截原生的_resolveFilename
方法调用,进行路径别名的转换,当获取到文件的真实路径后,再调用原声的_resolveFilename
方法。
下面是其源代码,基本上分为两部分:路径别名转换+原生_resolveFilename
调用
var oldResolveFilename = Module._resolveFilename Module._resolveFilename = function (request, parentModule, isMain, options) { for (var i = moduleAliasNames.length; i-- > 0;) { var alias = moduleAliasNames[i] if (isPathMatchesAlias(request, alias)) { var aliasTarget = moduleAliases[alias] // Custom function handler if (typeof moduleAliases[alias] === 'function') { var fromPath = parentModule.filename aliasTarget = moduleAliases[alias](fromPath, request, alias) if (!aliasTarget || typeof aliasTarget !== 'string') { throw new Error('[module-alias] Expecting custom handler function to return path.') } } request = nodePath.join(aliasTarget, request.substr(alias.length)) // Only use the first match break } } return oldResolveFilename.call(this, request, parentModule, isMain, options) }
看似简单的背后,往往也会踩坑
一般我们会在node
项目中使用module-alias
库,因为node
项目一般会从typescript
转换成js
代码,但是往往并不会进行打包处理,因为node
项目中一般也确实不需要打包,显得有些冗余。这时候就需要module-alias
上场了。
但是这个项目有点不一般,我们在项目中使用了多层代码组织方式,最外层有全局的package.json
, 内层包有自己的package.json
, 简单说是使用了monorepo
的代码组织方式,问题也就是由此而来。
module-alias无法正常解析在package.json中配置的路径别名
刚开始确实没想到是多层项目组织方式的问题,官网对module-alias/register
使用有一段说明:
但是当时确实也是没有注意到这块说明,要不然也不会踩这个坑了,下次看使用说明要仔细了,不过这么长的使用说明,大概率还是不会看的这么仔细。。。毕竟看起来这么简单的使用方法,好像似乎是不会出什么问题的吧
既然踩坑了,就有必要了解一下踩坑的原因,避免反复踩坑才好。可以详细了解下module-alias
中init
方法的实现。为了节省篇幅,省略了部分细节
function init (options) { // 省略了部分内容 var candidatePackagePaths if (options.base) { candidatePackagePaths = [nodePath.resolve(options.base.replace(/\/package\.json$/, ''))] } else { // There is probably 99% chance that the project root directory in located // above the node_modules directory, // Or that package.json is in the node process' current working directory (when // running a package manager script, e.g. `yarn start` / `npm run start`) // 重点看这里!!! candidatePackagePaths = [nodePath.join(__dirname, '../..'), process.cwd()] } var npmPackage, base for (var i in candidatePackagePaths) { try { base = candidatePackagePaths[i] npmPackage = require(nodePath.join(base, 'package.json')) break } catch (e) { // noop } } // 省略了部分内容 var aliases = npmPackage._moduleAliases || {} for (var alias in aliases) { if (aliases[alias][0] !== '/') { aliases[alias] = nodePath.join(base, aliases[alias]) } } // 省略了部分内容 }
可以看重点部分,如果我们没有给base参数,module-alias
默认会从../../
目录和当前目录下找寻package.json
文件,而且../..
目录下的package.json
文件的优先级比当前目录下的优先级还要高,这里的优先级设置似乎和正常的优先级逻辑有点差别,一般都会让当前目录的优先级比较高才比较符合正常逻辑,所以会导致加载的不是当前目录下的package.json
文件,而导致找不到路径别名配置而出错。
关于这点似乎有不少人踩坑了,还有人提了issues,但是似乎暂时并没有人回应。
通过API方式注册路径别名,或者手动调用init
方法,传入base参数,指定package.json
文件.
似乎只有踩坑了,才会更深入的了解
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
这篇文章主要介绍了js删除对象中的某一个字段的方法实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
目录前言关于边框关于控制点本章小结前言在上一章中我们已经搞定了下层画布,也就是能够对物体进行绘制了,现在就可以开始搞搞上层交互了。不过在和画布产生交互之前,我们还要做一件事情,就是让物体支持边框和控制点的绘制,亦即物体被选中时的状态,就像下面这样:这样一来如果要对物体进行一些操作,那就变成了对上图中的红色和蓝色边框进行
本篇文章带大家深入聊聊Angular中的变化检测,介绍一下Angular 如何订阅异步事件执行变化检测,聊聊变化检测的策略,希望对大家有所帮助!
今天给大家分享的是关于vue图片裁剪组件的内容,下文对vue图片裁剪组件的使用有详细的介绍及示例代码,有需要的朋友可以参考。本文介绍的组件是基于vue-cropper二次封装,接下来我们一起了解看看。
这篇文章主要给大家介绍了关于JS中多层次排序算法的实现代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008