TypeScriptのモジュール実装をES形式で出力したときに実行できるスマートな方法
Q&A
Closed
現在、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