码农之家

如何在 js 文件中直接调用 ts

背景是这样的,如下图,右边是 vscode 插件打开的一个 webview 界面,已经实现了在页面选择了一个方法,填入参数后,可以加载左边的 materials/blocks/表单/script/index.js 代码并执行里面对应的方法,返回执行结果。

materials/blocks/表单/script/index.js 内容如下:

module.exports = {
  beforeCompile: context => {
    context.outputChannel.appendLine('compile 表单 start')
  },
  afterCompile: context => {
    context.outputChannel.appendLine('compile 表单 end')
  },
  IntFromOcrText: context => {
    context.outputChannel.appendLine(Object.keys(context))
    context.outputChannel.appendLine(JSON.stringify(context.model))
    context.outputChannel.appendLine(context.params)
    return { ...context.model, name: '测试一下' }
  }
}

ts 写多了,写 js 真的效率低下。就想着能不能把方法里的逻辑单独放到 ts 文件里,这样还能给 context 写上类型声明。

直接问 ChatGPT 怎么在 js 文件直接调用 ts,它告诉我要先用 tsc 编译。

明显不是我想要的答案。

还好我知识储备丰富😆,想到了这个库 TypeStrong/ts-node: TypeScript execution and REPL for node.js (github.com)。认真看了一遍文档,发现都是命令行的用法,我之前也只是在命令行里面用过。拿着 require 关键字去搜(在 js 里调用肯定是用 require),终于发现有用的信息。

跟着链接跳过去

再跳

就这,怎么用嘛,换个姿势问 ChatGPT

被它坑过一次,给我一个完全不存在的调用方法,不太相信它,让它给我相关的文章

只能去翻翻 issues,还真找到了

realappie/tsnode-example: This is repository is an example of how to use ts-node programmatically (github.com) 弄到本地成功运行,看起来之前 ChatGPT 没骗我。

其实到这里问题已经解决了,但是我手贱,改了默认参数,想看看生成结果,index.js 代码如下

require('ts-node').register({
  transpileOnly: false,
  emit: true,
  compilerHost: true
})
const path = require('path')
const handle = require('./handle.ts')
console.log(handle.getTitle('lowcode'))
module.exports = {
  beforeCompile: context => {
    context.outputChannel.appendLine('compile 表单 start')
  },
  afterCompile: context => {
    context.outputChannel.appendLine('compile 表单 end')
  },
  IntFromOcrText: context => {
    context.outputChannel.appendLine(Object.keys(context))
    context.outputChannel.appendLine(JSON.stringify(context.model))
    context.outputChannel.appendLine(context.params)
    context.outputChannel.appendLine(handle.getTitle('lowcode'))
    return { ...context.model, name: '测试一下' }
  }
}

先用 node.js 直接运行

还生成了编译后文件,没问题,插件里调用看看

Error: EPERM: operation not permitted, mkdir ‘H:/Microsoft VS Code/.ts-node’,mac 上也是这个错。那就是 ts-node 的锅了,又去翻 issues,搜到了有个参数cwd 貌似有用

调整下参数

require('ts-node').register({
  transpileOnly: false,
  emit: true,
  compilerHost: true,
  cwd: __dirname
})

还是一样的报错,然后全部恢复默认参数,依旧报错。

经过漫长的网上冲浪找答案,最终关了 vscode 重新打开居然就好了。

然后又发现改了 ts 文件,执行的并不是最新的代码,要重新打开 vscode 才行

这个问题我熟啊,插件里动态加载 index.js 文件的时候就遇到过,是 node.js 缓存的机制,加一行代码就解决了

delete require.cache[require.resolve(path.join(__dirname, 'handle.ts'))]

最终代码

require('ts-node').register({
  transpileOnly: false,
  emit: false,
  compilerHost: false, // 和 emit 一起设置为 true,会在 .ts-node 文件夹输出编译后的代码
  cwd: __dirname // 要输出编译后代码必须配置,否则会报错 EROFS: read-only file system, mkdir '/.ts-node'。不输出也要配置不然会出现各种奇奇怪怪的报错
})
const path = require('path')
// 清除缓存,保证每次修改代码后实时生效
delete require.cache[require.resolve(path.join(__dirname, 'handle.ts'))]
const title = require('./handle.ts')
module.exports = {
  beforeCompile: context => {
    context.outputChannel.appendLine('compile 表单 start')
  },
  afterCompile: context => {
    context.outputChannel.appendLine('compile 表单 end')
  },
  IntFromOcrText: context => {
    context.outputChannel.appendLine(Object.keys(context))
    context.outputChannel.appendLine(JSON.stringify(context.model))
    context.outputChannel.appendLine(context.params)
    context.outputChannel.appendLine(title.getTitle('lowcode'))
    return { ...context.model, name: '测试一下' }
  }
}

如果你看到了这里,你可以直接问 ChatGPT

  • 使用 ts-node 在 js 文件中直接调用 ts
  • 使用 babel 在 js 文件中直接调用 ts
  • 使用 swc 在 js 文件中直接调用 ts
  • 使用 esbuild 在 js 文件中直接调用 ts

原文链接:https://juejin.cn/post/7248995705292111929 作者:若邪