Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

TypeScriptのモジュール実装をES形式で出力したときに実行できるスマートな方法

現在、TypeScriptのモジュール実装で気になることがあります。
例えば、以下のようなモジュールの実装があるとします。

実行環境は Node.js(Windows x64) v12.18.4 です。

ファイル構成は単純に以下のようにしております。

-+-App.ts
 +-Main.ts
 +-tsconfig.json

App.tsとMain.tsの中身を共有いたします。

App.ts
export namespace MyApp {
    interface AppInterface {
        name: string;
        value: any;
    };

    export class App{
        name?: string;
        value?: any;

        constructor(init: Partial<AppInterface> = {}){
            Object.assign(this, init);
        }

        get val(): any{
            return this.value;
        }
        set val(value: any){
            this.value = value;
        }

        out(): string {
            return `name: ${this.name} / value: ${this.value}`;
        }
    }
}
Main.ts
import { MyApp } from './App';

let o = {name: "hoge", value: 1 };
let x:MyApp.App = new MyApp.App(o);

x.val = 100;

console.log(x.out());

(注)あくまでもモジュール実装の動作確認用ですので、実装のクオリティについてはまた別の話です…

tsconfig.jsonの"module"を"commonjs"のままにすると特に問題なくビルド・実行できます

tsconfig.json
{
  "compilerOptions": {
   :
    "target": "ES2019",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
   :

その後、以下の方法でECMAScript形式にするため、他のドキュメントを参考にしながら以下の方法を取りました。

1. "module"を"es2015"にする

tsconfig.json
{
  "compilerOptions": {
   :
    "module": "es2015",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
   :

2. package.jsonを追加する

package.json
{
    "type": "module"
}

3. ビルド後、 --experimental-modulesを付けて実行

PS ***> tsc
PS ***> node Main.js --experimental-modules

結果、エラーが発生

Main.jsからApp.jsが見えないエラーが発生しました。

(node:16720) ExperimentalWarning: The ESM module loader is experimental.
internal/modules/run_main.js:54
    internalBinding('errors').triggerUncaughtException(
                              ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '***\App' imported from ***\Main.js
Did you mean to import ../App.js?
    at finalizeResolution (internal/modules/esm/resolve.js:259:11)
    at moduleResolve (internal/modules/esm/resolve.js:636:10)
    at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:726:11)
    at Loader.resolve (internal/modules/esm/loader.js:97:40)
    at Loader.getModuleJob (internal/modules/esm/loader.js:243:28)
    at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:47:40)
    at link (internal/modules/esm/module_job.js:46:36) {
  code: 'ERR_MODULE_NOT_FOUND'
}

出力された Main.js の2行目を修正すると問題なく動くのですが、

Main.js
import { MyApp } from './App';
 
import { MyApp } from './App.js';
(node:17900) ExperimentalWarning: The ESM module loader is experimental.
name: hoge / value: 100

…ここまでやってきて、出力されたjsファイルをいちいち弄るのはスマートじゃないという認識です。jsファイルを修正せずに実行する方法はございますでしょうか?

[追記]解決しました

uttkさんからご回答を頂いたので、さっさとオプションを付けて実行してみたところ同じエラーが発生しました。

jsファイルの指定を最初に
node Main.js --experimental-modules --es-module-specifier-resolution=node

変だなと思ってリンク先の記事を読むと、もしかしたらと思い、jsファイルの指定を最後にしたところ、エラーにならず想定の動きとなりました…書式が結構シビアですね…。

jsファイルの指定を最後に
PS ***> node --experimental-modules --es-module-specifier-resolution=node .\Main.js
(node:23616) ExperimentalWarning: The ESM module loader is experimental.
name: hoge / value: 100

とりあえず、問題が解決いたしました。ありがとうございました。

0

No Answers yet.

Your answer might help someone💌