需求来源
安装了一个自己写的test-package
,里面有一些可复用的代码,比如有个index.ts
的代码如下:
export const msg = 'msg'; 复制代码
想要在新项目里面import这些代码,
import {msg} from 'test-package/index' 复制代码
发现无法正常import,提示
定位问题
解析ts我这边使用的ts-node
,对配置也不是太熟悉,根据报错堆栈开始追代码,发现import会调用require,而require会调用module.load,Module._extensions[extension]()
这句代码会根据文件扩展名调用相应的
顺带看了下json的实现
原理就是读取字符串,然后JSONParse下,也不是太难
const {JSONParse} = primordials; 复制代码
ts文件的话,最终就会来到ts-node里面,这里有个非常重要的逻辑:
其中shouleIgnore
函数里面,有对node_modules
的排除,同时options也是可以干扰这个结果的,其实在ts-node的文档里面也有说明这个参数
那么我们应该如何传递这个参数呢?
解决问题
ts-node的文档上也有写,会读取当前工作目录的tsconfig.json
它会从ts-node
中读取需要的参数
tsconfig.json
示例
{ "ts-node":{ "skipIgnore": true } } 复制代码
这样就能完美的引入node_modules里面的代码了,至于有其他的什么问题,暂时没有多测试
优化实现
上述的这个解决方案能解决问题,但是我的需求是希望默认开始这个设置,不想要用户自己在tsconfig.json中手动增加这个配置。
我使用的是cli,所以可以通过代码控制这个参数,
require('ts-node') .register({ skipIgnore: true, }); 复制代码
但是我这里使用了一个第三方的库:rechoir
、interpret
,它可以根据不同的文件扩展名准备内置好的环境,对于ts文件,它内置了好几个环境,其中就有这个ts-node,最终也是会调用register函数, 这个库也是通过看vue-cli-server才知道的。
所以接下来,就看下怎么把register的参数传递进去
最终发现interpret的配置是写死的,也没有开放register的参数,看来通过api修改的路堵死了。
再读ts-node的源码,定义环境变量
发现options的数据有来自process.env
export const env = process.env as ProcessEnv; export const DEFAULTS: RegisterOptions = { cwd: env.TS_NODE_CWD ?? env.TS_NODE_DIR, emit: yn(env.TS_NODE_EMIT), scope: yn(env.TS_NODE_SCOPE), scopeDir: env.TS_NODE_SCOPE_DIR, files: yn(env.TS_NODE_FILES), pretty: yn(env.TS_NODE_PRETTY), compiler: env.TS_NODE_COMPILER, compilerOptions: parse(env.TS_NODE_COMPILER_OPTIONS), ignore: split(env.TS_NODE_IGNORE), project: env.TS_NODE_PROJECT, skipProject: yn(env.TS_NODE_SKIP_PROJECT), skipIgnore: yn(env.TS_NODE_SKIP_IGNORE), preferTsExts: yn(env.TS_NODE_PREFER_TS_EXTS), ignoreDiagnostics: split(env.TS_NODE_IGNORE_DIAGNOSTICS), transpileOnly: yn(env.TS_NODE_TRANSPILE_ONLY), typeCheck: yn(env.TS_NODE_TYPE_CHECK), compilerHost: yn(env.TS_NODE_COMPILER_HOST), logError: yn(env.TS_NODE_LOG_ERROR), experimentalReplAwait: yn(env.TS_NODE_EXPERIMENTAL_REPL_AWAIT) ?? undefined, }; 复制代码
其中yn
模块可以快速的将一些含义非常相似的数据转换为js可识别的值,比如:
- yn('y')=> true
- yn(true)=> true
而TS_NODE_SKIP_IGNORE
环境变量就是我们要找的目标。
只要我们在process.env上定义这个变量也可以达到同样的效果,通过dotenv
、dotenv-expand
来操作环境变量也可以达到预期的效果。
总结
一路看下来,还是学到了不少的新知识,遇到问题从源码入手解决问题,是有点浪费时间,但是能让你对细节更加的了解。