Closed4

ts-node や nestjs で絶対パスと ESM を同時に使う

sun-yryrsun-yryr

両方を使うように設定するとこんなエラーが出る
CustomError: Cannot find package '@/xxx' imported from yyy

問題は2つあって、「ts-node/esm が paths を読まない」「tsconfig-paths は ESM 標準の書き方 (拡張子付きの import) を変換しない」

これを解決するカスタムローダーを作らないといけない。

issue とか pull request などもある。
https://github.com/TypeStrong/ts-node/pull/1585
https://kimuson.dev/blog/typescript/ts_node_esm_paths/

sun-yryrsun-yryr

結論としてはこれで動いた。ts-node/esm を使いつつ、matchPath には拡張子を除いたパスを渡して変換してもらう。

import { pathToFileURL } from 'url';

import {
    resolve as esmResolve,
    getFormat,
    transformSource,
    load,
} from 'ts-node/esm';
import { createMatchPath, loadConfig } from 'tsconfig-paths';

export { getFormat, transformSource, load };

const { absoluteBaseUrl, paths } = loadConfig();
const matchPath = createMatchPath(absoluteBaseUrl, paths);

export async function resolve(specifier, context, defaultResolve) {
    // *.js を matchPath が展開できないため、matchPath 前後で拡張子を付け直す
    if (specifier.endsWith('.js')) {
        const trimmed = specifier.substring(0, specifier.length - 3);
        const matchedSpecifier = matchPath(trimmed);
        if (matchedSpecifier) {
            return esmResolve(
                pathToFileURL(`${matchedSpecifier}.js`).toString(),
                context,
                defaultResolve,
            );
        }
    }

    return esmResolve(specifier, context, defaultResolve);
}
sun-yryrsun-yryr

nestjs はビルド時に paths を変換してくれる機能があるみたいですが、拡張する方法が見当たらなかったので実行時に解決させるようにした。パワー💪

package.json を抜粋

"scripts": {
    "build": "nest build",
    "start": "node --loader ./custom-loader.js dist/main.js",
    "dev": "node --loader ./custom-loader.js ./node_modules/.bin/ts-node src/main.ts"
}
このスクラップは6ヶ月前にクローズされました