ViteでWebGL、Three.jsを練習するための環境構築をしてみた(TypeScript)
はじめに
以下の点でViteがThree.jsやwebglを練習する際の環境構築に便利そうだったのでやってみました。
- マルチページアプリに対応
- glslのインポートに対応
Viteでマルチページのやり方
マルチページのやり方については以前書いたのでそちらを見ていただければと思います。
glslファイルのインポート
Viteはglslインポートに対応しています。
例えば以下のようなglslで書いたファイルがあります。
#version 300 es
precision mediump float;
in vec3 vPosition;
void main(void) {
gl_Position = vec4(vPosition, 1.0);
}
#version 300 es
precision mediump float;
out vec4 fragColor;
uniform vec2 resolution;
void main(){
vec2 pos = gl_FragCoord.xy / resolution.xy;
fragColor = vec4(pos, 1.0, 1.0);
}
?raw
のサフィックスをつけて以下のようにインポートして使用できます。
import vertexSource from './shader/vertex.glsl?raw'
import fragmentSource from './shader/fragment.glsl?raw'
const shaderMaterial = new THREE.RawShaderMaterial({
~ 中略 ~
vertexShader: vertexSource,
fragmentShader: fragmentSource,
})
トップページに各画面のリンクを自動で生成して表示させる
ViteにはtransformIndexHtml
というフックが用意されています。これはindex.htmlなどのエントリーポイントファイルを変換するためのフックです。
これを使ってトップページのHTMLに自動で各ページのリンクを出力するようにvite.config.js
を修正してみます。ディレクトリ構成は以下のようになってます。pages
ディレクトリ以下が画面単位のディレクトリになっています。
src
┣ 📂common
┃ ┣ 📜stage.ts
┃ ┗ 📜webgl.ts
┣ 📂pages
┃ ┣ 📂threejs-sample1
┃ ┃ ┣ 📂shader
┃ ┃ ┃ ┣ 📜fragment.glsl
┃ ┃ ┃ ┗ 📜vertex.glsl
┃ ┃ ┣ 📜index.html
┃ ┃ ┣ 📜main.ts
┃ ┃ ┗ 📜style.css
┃ ┣ 📂threejs-sample2
┃ ┃ ┗ 中略
┃ ┗ 📂webgl-sample1
┃ ┃ ┗ 中略
┣ 📜index.html
┣ 📜main.ts
┣ 📜style.css
┣ 📜typescript.svg
┣ 📜vite-env.d.ts
┗ 📜vite.svg
トップページのHTMLは以下のようになっています。
<ul id="pageIndex"></ul>
の部分が空ですが、これをビルドまたは起動時に各画面のリンクに差し替えるように修正します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sample</title>
</head>
<body>
<ul id="pageIndex"></ul>
<script type="module" src="/main.ts"></script>
</body>
</html>
vite.config.js内の処理
vite.config.js
の内容は以下になります。
import * as fs from 'fs'
import { resolve } from 'path'
import { defineConfig } from 'vite'
const root = resolve(__dirname, 'src')
const pages = resolve(__dirname, 'src', 'pages')
const outDir = resolve(__dirname, 'dist')
// 各ページのディレクトリ名のリストを取得
const pageDirNameList = fs.readdirSync(pages)
// rollupOptions用のコンフィグを作成
const pageConfig = pageDirNameList.reduce((arr, pageName) => {
arr[pageName] = resolve(root, 'pages', pageName, 'index.html')
return arr
}, {})
// 各ページ遷移用リストのHTMLを作成
const paheListHtml = pageDirNameList
.map((pageName) => `<li><a href="./pages/${pageName}/index.html">${pageName}</a></li>`)
.join('')
// rollupのプラグインを定義
// index.htmlを書き換えて各ページへ遷移するリンク用HTMLを差し込む
const htmlPlugin = () => {
return {
name: 'html-transform',
transformIndexHtml(html) {
return html.replace(/<ul id="pageIndex"><\/ul>/, `<ul id="pageIndex">${paheListHtml}</ul>`)
},
}
}
// Viteのコンフィグを定義
export default defineConfig({
root,
build: {
outDir,
rollupOptions: {
input: {
main: resolve(root, 'index.html'),
...pageConfig,
},
},
},
plugins: [htmlPlugin()],
})
まずpages以下のディレクトリ名のリストを取得します。
// 各ページのディレクトリ名のリストを取得
const pageDirNameList = fs.readdirSync(pages)
取得したディレクトリ名を使ってリンク用のHTMLを作成します。transformIndexHtmlでHTMLを書き換える処理をhtmlPluginとしてまとめます。
// 各ページ遷移用リストのHTMLを作成
const paheListHtml = pageDirNameList
.map((pageName) => `<li><a href="./pages/${pageName}/index.html">${pageName}</a></li>`)
.join('')
// rollupのプラグインを定義
// index.htmlを書き換えて各ページへ遷移するリンク用HTMLを差し込む
const htmlPlugin = () => {
return {
name: 'html-transform',
transformIndexHtml(html) {
return html.replace(/<ul id="pageIndex"><\/ul>/, `<ul id="pageIndex">${paheListHtml}</ul>`)
},
}
}
defineConfig
のpluginsオプションにこのhtmlPluginを追加してやります。
// Viteのコンフィグを定義
export default defineConfig({
中略,
plugins: [htmlPlugin()],
})
npm run dev
で起動したページを確認すると以下のように画面のリンクに置き換わっています。
最後に
Viteは何かさくっと環境を用意したい場合に便利だなと思いました。Rollupが使われているので、Viteのドキュメントだけでは理解できない場合や情報が不足してると感じた場合はRollupのドキュメントを読みに行くといいかなと思いました。
参照
Discussion