概要
2022年2月22日時点の現象
こちらのDownloadからZipダウンロードしたファイル群を下のように展開
ディレクトリ構造
root
└ index.html
└ index.js
└ three.js-master/three.js-master
└ build/three.module.js
└ examples/jsm/loaders/GLTFLoader.js
GLTFLoader.jsをimport
import * as THREE from './three.js-master/three.js-master/build/three.module.js'
import {GLTFLoader} from './three.js-master/three.js-master/examples/jsm/loaders/GLTFLoader.js'
サーバー立ち上げ
npm start —force
localhost:8080
を確認するもエラー
Uncaught TypeError: Failed to resolve module specifier "three". Relative references must start with either "/", "./", or "../"
解決法
GLTFLoader.jsの64行目付近の from文
元々はこちら
//中略
VectorKeyframeTrack,
sRGBEncoding
} from 'three';
//中略
from 'three';
の部分をfrom '../../../build/three.module.js';
に変更
//中略
VectorKeyframeTrack,
sRGBEncoding
} from '../../../build/three.module.js';
//中略
これで解決しました。
追記 (おそらくこちらの方が正着?)
@o_obさんからTwitterでコメントをいただきました。(ありがとうございます!)
参考にした結果以下の書き方でも解決しました。
GLTFLoader.jsは元のまま
//中略
VectorKeyframeTrack,
sRGBEncoding
} from 'three';
//中略
エラー時のhtml
<html lang="ja">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Model Loader</title>
</head>
<body>
<canvas class="webgl" id="myCanvas"></canvas>
<script src="index.js" type="module"></script>
</body>
</html>
修正後のhtml
<html lang="ja">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Model Loader</title>
<!-- 追加 -->
<script type="importmap">
{
"imports": {
"three": "./three.js-master/three.js-master/build/three.module.js"
}
}
</script>
<!-- ここまで -->
</head>
<body>
<canvas class="webgl" id="myCanvas"></canvas>
<script src="index.js" type="module"></script>
</body>
</html>
importMapとは
気になったので調べました。
「JavaScript の実際のファイル名」と「そのファイルを import するときに指定する名前」を切り離すことができます(2つの対応情報はJSON形式で用意しておきます)。
これにより、ファイル名が後から変わっても(ファイル名にバージョン番号が含まれている場合など)、一度記述した import 文を変更する必要はなくなります。(JSON形式による対応情報側のみを変えます)
npm のパッケージ名のようなシンプルな名前でインポートできます。
静的インポート、動的インポートのどちらでも使えます。
とのこと。
これにより three
という名まえを使えるようになるということですね。
ちなみに、three.jsのサンプル実装では
<!-- Import maps polyfill 古いブラウザーでも動かすためのコード -->
<!-- Remove this when import maps will be widely supported この1行はimport mapが普及したら削除してよい -->
<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>
<script type="importmap">
{
"imports": {
"three": "../build/three.module.js"
}
}
</script>
とありました。こちら確認しておけば...!
補足議論
おそらく、three.js開発者はnode_modulesによるinstall想定だったため、今回のようなエラーが発生したのでは...?など予想しています。(詳しい人教えてください。)