JavaScriptの環境についてのエントリが続きます。
前回のエントリで複数フォルダの複数ファイルに跨がるscriptをimport, exportして実行できる様にできた。
その後も、プロゲート上で実行したscriptファイルを拡張子を付けるなど修正し、自分のMac上に保存して実行させていた。
そんな現在のフォルダ構成は下記の通り。
. ├── class │ ├── animal.js │ └── dog.js ├── data │ └── dogData.js ├── package-lock.json ├── package.json └── script.js 2 directories, 6 files
しばらく上手く行っていたが、外部のパッケージをimportするscriptファイルにおいて下記エラーが出た。
% node script.js node:internal/errors:464 ErrorCaptureStackTrace(err); ^ Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'readline-sync' imported from /Users/(ユーザー名以降のパス)/files/data/dogData.js at new NodeError (node:internal/errors:371:5) at packageResolve (node:internal/modules/esm/resolve:884:9) at moduleResolve (node:internal/modules/esm/resolve:929:18) at defaultResolve (node:internal/modules/esm/resolve:1044:11) at ESMLoader.resolve (node:internal/modules/esm/loader:422:30) at ESMLoader.getModuleJob (node:internal/modules/esm/loader:222:40) at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:76:40) at link (node:internal/modules/esm/module_job:75:36) { code: 'ERR_MODULE_NOT_FOUND' }
エラーメッセージによると、パッケージ “readline-sync”が見つからないとの事。
まずは”Error [ERR_MODULE_NOT_FOUND]: Cannot find package ‘readline-sync’ imported from”で検索、
Error: Cannot find module ‘readline-sync’ : Node.jsでアドバイスされている通り
“npm install –save readline-sync”
を実行。
パッケージ “readline-sync”が私のMac上にないからインストール、と言う事だろう。
Pythonでも必要なモジュールはインストールする必要があるのでこれは分かる。
% npm install --save readline-sync added 1 package, and audited 2 packages in 2s found 0 vulnerabilities
インストール後、ファイルを実行すると”Cannot find package ‘readline-sync”は無くなったが、script.jsを実行するとやはりエラーメッセージが出る。
% node script.js node:internal/errors:464 ErrorCaptureStackTrace(err); ^ Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/Users/ユーザー名/~/files/class/dog' imported from /Users/ユーザー名/~/files/data/dogData.js at new NodeError (node:internal/errors:371:5) at finalizeResolution (node:internal/modules/esm/resolve:416:11) at moduleResolve (node:internal/modules/esm/resolve:932:10) at defaultResolve (node:internal/modules/esm/resolve:1044:11) at ESMLoader.resolve (node:internal/modules/esm/loader:422:30) at ESMLoader.getModuleJob (node:internal/modules/esm/loader:222:40) at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:76:40) at link (node:internal/modules/esm/module_job:75:36) { code: 'ERR_MODULE_NOT_FOUND' }
npm installも実行してみるも、同じエラーが出た。
% npm install up to date, audited 2 packages in 762ms found 0 vulnerabilities
現在のツリーは下記の通り。
フォルダ”node_modules”が出来ているのが分かる。
% tree . ├── class │ ├── animal.js │ └── dog.js ├── data │ └── dogData.js ├── node_modules │ └── readline-sync │ ├── LICENSE │ ├── README-Deprecated.md │ ├── README.md │ ├── lib │ │ ├── encrypt.js │ │ ├── read.cs.js │ │ ├── read.ps1 │ │ ├── read.sh │ │ └── readline-sync.js │ └── package.json ├── package-lock.json ├── package.json └── script.js 5 directories, 15 files
色々見ていて、”dogData.js”ファイル内で下記の行を見つける。
import readlineSync from "readline-sync";
フォルダ内ファイルのimport, exportにおいては拡張子.jsを付けていたんだから、パッケージも同じだろう。
と言う事で”readline-sync”の部分に.jsの拡張子を付けて実行するとエラーメッセージが変わった。
% node script.js node:internal/errors:464 ErrorCaptureStackTrace(err); ^ Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'readline-sync.js' imported from /Users/ShujiKatoMBPro/Dropbox/0_Udacity/0_Full_Stack_Web_Developer/Playground/JS_Playground/Progate_sample/files/data/dogData.js at new NodeError (node:internal/errors:371:5) at packageResolve (node:internal/modules/esm/resolve:884:9) at moduleResolve (node:internal/modules/esm/resolve:929:18) at defaultResolve (node:internal/modules/esm/resolve:1044:11) at ESMLoader.resolve (node:internal/modules/esm/loader:422:30) at ESMLoader.getModuleJob (node:internal/modules/esm/loader:222:40) at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:76:40) at link (node:internal/modules/esm/module_job:75:36) { code: 'ERR_MODULE_NOT_FOUND' }
そうか、ただ拡張子を変えただけでは読み込めないよね。
と、インポートの一行を下記の相対パスに修正した上でscript.jsを実行したら実行出来た。
import readlineSync from "../node_modules/readline-sync/lib/readline-sync.js";
要は、”readline-sync”に限らず外部パッケージが無いよ、と言うエラーでした。
プロゲート上ではサーバ内にパッケージが保存されているから
ただ
“import readlineSync from “readline-sync”;
とするだけでインポートして使用出来たのだろう。
JavaScriptをnodeで実行し、外部のパッケージを利用する際には、そのパッケージを自分がscriptファイルを実行しているディレクトリにある”node_modules”フォルダ内にインストール、相対パスを設定する必要が有るのだろう。
多分JS/nodeをお使いの方には当たり前なのでしょうが、今理解しました。
で、そのパッケージを管理するのがpackage.jsonファイル。
現時点のpackage.jsonファイルは下記の通り。
今回インストールした”readline-sync”が有るのが分かる。
{ "name": "files", "version": "1.0.0", "description": "", "main": "script.js", "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { "readline-sync": "^1.4.10" } }
Pythonではpip等でインストールしたモジュールはパス無しのimport文でインポートできるが、JavaScriptにおいては都度パッケージの場所を指定する必要がある、と言うのが現在の理解。
コメント