【问题标题】:How to load modules from dynamic typescript files如何从动态打字稿文件加载模块
【发布时间】:2022-11-20 18:41:58
【问题描述】:

许多流行的节点包都支持用 JS 或 TS 编写配置文件,如webpackvite。现在我也在尝试创建一个支持 JS 和 TS 配置文件的包,它将用作:my-package --config path/to/config.ts
我首先尝试直接使用require,但它对 TS 失败了(这是一个很明显的结果,因为没有指定 TS 的加载程序)。
所以我然后尝试使用typescript 包来转换配置文件并使用require-from-string 来加载模块,当指定的配置文件导入一些其他模块时,这也不起作用。
所以我现在的问题是:如何在当前上下文中解析配置模块.
请注意,此包旨在像 webpack-cli 一样工作,被其他包添加到 devDependencies 并用作开发工具。所以当前上下文指的是安装这个包的包。
这是我浏览并尝试过的一些相关帖子(所以不要对这些问题提出重复):

【问题讨论】:

  • 你的bin脚本是什么?有没有像node something.js
  • @Dimava 是的,bin 脚本在package.json 中定义为{ "bin": { "some-command": "dist/some-command.js" } }
  • 然后尝试安装tsx并将命令设置为tsc dist/some-command.js
  • 甚至tsx dist/some-command.ts
  • @Dimava 我猜你没有完全明白我的意思。我需要支持所有的配置格式,包括json、js和ts,而不仅仅是ts。

标签: node.js typescript configuration node-modules


【解决方案1】:

查了webpack-cli的出处,终于在rechoir的帮助下搞定了。这是代码:

import interpret from "interpret";
import rechoir from "rechoir";
import AsyncFs from "fs/promises";
import Path from "path";
import { pathToFileURL } from "URL";

// My package is build with `webpack`, so I need the following to bypass its dynamic require constraint.
declare var __non_webpack_require__: ((id: string) => any) | undefined;
const dynamicRequire = typeof __non_webpack_require__ === "function" ? __non_webpack_require__ : require;

async function tryRequireThenImport(module: string): Promise<any> {
    let result;
    try {
        result = dynamicRequire(module);
    } catch (error: any) {
        let importEsm: ((module: string) => Promise<{ default: any }>) | undefined;
        try {
            importEsm = new Function("id", "return import(id);") as any;
        } catch (e) {
            importEsm = undefined;
        }
        if (error.code === "ERR_REQUIRE_ESM" && importEsm) {
            const urlForConfig = pathToFileURL(module).href;
            result = (await importEsm(urlForConfig)).default;
            return result;
        }
        throw error;
    }
    // For babel/typescript
    if (result && typeof result === "object" && "default" in result)
        result = result.default || {};
    return result || {};
}

async function loadModule(path: string): Promise<any> {
    const ext = Path.extname(path);
    if (ext === ".json") {
        const content = await AsyncFs.readFile(path, "utf-8");
        return JSON.parse(content);
    }
    if (!Object.keys(interpret.jsVariants).includes(ext))
        throw new Error(`Unsupported file type: ${ext}`);
    // This is the key point that gets the configuration module loaded under current context
    rechoir.prepare(interpret.jsVariants, path);
    return await tryRequireThenImport(path);
}

实现主要是借鉴webpack-cli。以下是资料来源:

【讨论】:

    猜你喜欢
    • 2017-06-27
    • 2016-04-11
    • 2016-05-30
    • 1970-01-01
    • 1970-01-01
    • 2013-02-26
    • 2015-11-18
    • 2016-04-08
    • 2016-10-29
    相关资源
    最近更新 更多