はじめに
普段はVanilla JSでWebGIS開発しているんですが、ここ1年くらいでWebpack5に取り組んでどうにかこうにか使い慣れてきたところでした。
しかし、「もう少しビルド(バンドル処理)が早くできないものか、それになにげに設定事も難しいし」と情報収集をして、一瞬だけesbuildも試したけどすぐWebpack5に戻り、今に至ります。
風の便りに、「Vite」ってのがいいらしいと知ります。
「なぜ Vite なのか | Vite」には、様々なJS開発現場での問題点が指摘され、「特徴 | Vite」では良さそうな感じがします。 よし、ちょっとやってみようか、ちょうど別のプロジェクトが立ち上がるし、と。
【追記】昨今は、もうこのViteが手放せなくなりつつあります。Node.jsのバージョン管理はVoltaを使って、npmからviteを入れて簡単にバンドルしてます。
構築環境
- Windows 10 Pro
- WSL2+Ubuntu-22.04を補助的に使っているけれど、ビルドなどはあくまでWindows上で完結させる
- IntelliJ PhpStorm(ビルドなどコマンドを実行するときはPhpStormの「ターミナル」から行っている)
- Vite v4.0系
- Node.js v18.16系、npm v9.8系とか
ここに紹介する設定で実現すること
- src/ と dist/ でディレクトリ管理できる。(webpack v5っぽく)
- 相対パス指定でバンドルされるので、サーバーのサブディレクトリ上に配置するのも簡単。
- 自作コードとnode_modules管理下のコードがチャンク別けできる。
- 開発版 development と本番版 production とでなるべく設定を共通ににして、違うところだけ定義を変更できる。
目指すディレクトリ構造
projectディレクトリトップ
│
├─src ディレクトリ(ビルド前のソース一式)
│ ├─index.html(コンテンツ入り口にあたるhtml)
│ ├─main.js(index.htmlから読み込まれる自作jsコード)
│ ├─style.scss(index.htmlから読み込まれる自作scssコード、バンドルによってcssに変換される)
│ │
│ ├─js ディレクトリ(自作モジュールjs置き場、main.jsでimportされる)
│ ├─css ディレクトリ(自作スタイルシート置き場style.scssでimportされる)
│ │
│ └─public ディレクトリ(配布物と一緒に置かれる静的コンテンツ類)
│ │
│ ├─img ディレクトリ
│ ├─json ディレクトリ
│ └─pdf ディレクトリ とか
│
├─dist ディレクトリ(ビルド後の配布物)
│ │
│ ├─assets ディレクトリ
│ │ │
│ │ ├─index.js(ビルド後のindex.htmlから読み込まれる)
│ │ ├─vender_a.js(node_modules由来のパッケージがひと塊)
│ │ ├─vender_b.js(node_modules由来のパッケージがひと塊)
│ │ └─index.css(ビルド後のindex.htmlから読み込まれる)
│ │
│ ├─public ディレクトリ(src/publicからコピーされる)
│ │
│ └─index.html(ビルド後のhtml)
│
├─node_modules ディレクトリ(パッケージ類の置き場所)
│
├─package.json
├─package-lock.json
└─vite.config.js(viteの設定ファイル)
vite.config.js の今
// vite.config.js
//import { splitVendorChunkPlugin } from 'vite' // 結局やめた
import { defineConfig } from 'vite'
export default defineConfig(({ command, mode, ssrBuild }) => {
// 設定オプション
var config = {
root: "src",
base: "./", // 相対パスでpublicなど参照できるように
publicDir: "public",
build: {
outDir: '../dist',
// emptyOutDir: true, // 絶対空にしないこと!
sourcemap: true,
rollupOptions: {
output: { // entry chunk assets それぞれの書き出し名の指定、ハッシュ値を使われると毎回変わって困るので
entryFileNames: `assets/[name].js`,
chunkFileNames: `assets/[name].js`,
assetFileNames: `assets/[name].[ext]`,
manualChunks: (id) => {
if (id.includes('node_modules')) {
if (id.includes('node_modules/ol/') || id.includes('node_modules/proj4/')) {
return 'vendor_ol';
} else if (
id.includes('node_modules/bootstrap/') ||
id.includes('node_modules/@popperjs/')
) {
return 'vendor_bs';
}
return 'vendor'; // all other package goes here
}
},
},
},
},
// plugins: [splitVendorChunkPlugin()],
}
if (mode === "development") {
return config;
}
else {
config.build.sourcemap = false; // ソースマップの出力抑止
return config;
}
})
いろいろ総合して、こうなった。
scssを使う上での設定や定義がいらないのが素敵。
古いブラウザ向けの互換性確保をするなら、「@vitejs/plugin-legacy」というプラグインを使えばいいらしいけれど、モダンブラウザだけ相手なので気にしない。
妥協点とか
publicDirについて
publicDirで指定したディレクトリは、ビルド時にdistディレクトリにコピーされるということだけど、たまたま今回Googleマップ互換のラスタータイル画像を大量に用意してあり、当初は publicDir で指定する public ディレクトリの下に全部置いていた。
そうしたら、数KB~十数KBの大量のファイルをディレクトリ構造ごとビルドのたびにコピーしているようで(HDD上ではあまりに時間がかかって)大変都合が悪かった。
ファイル数やファイルサイズが、たかが知れているファイルであればいいけれど、さすがに時間が無駄なので、最近は dist にはじめから置いといて、その代わり dist から src にシンボリックリンクを張って開発サーバー(npm run dev)の動作に支障がないようにしている。
mklink /d にてWindows上でシンボリックリンクを作成
ちなみに、Windows 10/11でシンボリックリンクを張るためには、例えばコマンドプロンプトを管理者権限で起動し、srcディレクトリ上でmklink /d terrain ..\dist\terrain
などとしている。 エクスプローラ上でAltキーを押しながらドラッグすればショートカットが作れるのだけど、その場合実態は「terrain.lnk」などという拡張子がついてしまって具合が悪い。 なので、dist
にあるterrain
を開発サーバーから参照できるようにするためには、srcディレクトリ上にてmklink /d リンク ターゲット
となるようにしておくと、npm run dev
にて開発サーバー実行中でも問題なく参照できるようになる。 WSL2ならln -s
なんだろうけれど。
そのため、config.build.emptyOutDir は false にしておくべき、定義がなければ false になるのでコメントアウトしている。
チャンクの分割(これもお試し中→自動化をやめて手動で対応)
プラグインsplitVendorChunkPlugin()
によって、venderのチャンクを分離できる。
これを使って dist/assets/vender.js として分離しても、パッケージ類がこってりとひと塊になっているので、500KBなんかはるかに超えちゃってる。
こういう場面でも、Dynamic Importとか活きてくるんだろうけど、まだ理解が追い付いていないので、追々。
手動でチャンク分割をやるようになった
500KBを越えないように分割せよってことなので、なんとなく近い機能まとまった機能ごとに分けようと思いつき、例えばBootstrap 5とそこで使ってる@popper.jsをひとまとめにしてみたり、OpenLayersと一緒に使ってるproj4jsをひとまとめにしてみたりして、括りだしていたりする。