Vite v4での個人的お気に入り設定を公開（旧題：Viteお試し中、Webpack5からViteに移行し始めました）

# はじめに

　普段はVanilla JSでWebGIS開発しているんですが、ここ1年くらいでWebpack5に取り組んでどうにかこうにか使い慣れてきたところでした。
　しかし、「もう少しビルド(バンドル処理)が早くできないものか、それになにげに設定事も難しいし」と情報収集をして、一瞬だけesbuildも試したけどすぐWebpack5に戻り、今に至ります。
　風の便りに、「[Vite](https://ja.vitejs.dev)」ってのがいいらしいと知ります。
　「[なぜ Vite なのか \| Vite](https://ja.vitejs.dev/guide/why.html)」には、様々なJS開発現場での問題点が指摘され、「[特徴 \| Vite](https://ja.vitejs.dev/guide/features.html)」では良さそうな感じがします。　よし、ちょっとやってみようか、ちょうど別のプロジェクトが立ち上がるし、と。

　【追記】昨今は、もうこの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 の今

```javascript
// 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のチャンクを分離できる](https://ja.vitejs.dev/guide/build.html#%E3%83%81%E3%83%A3%E3%83%B3%E3%82%AF%E6%88%A6%E7%95%A5)。
　これを使って dist/assets/vender.js として分離しても、パッケージ類がこってりとひと塊になっているので、500KBなんかはるかに超えちゃってる。
　こういう場面でも、Dynamic Importとか活きてくるんだろうけど、まだ理解が追い付いていないので、追々。

### 手動でチャンク分割をやるようになった

　500KBを越えないように分割せよってことなので、なんとなく近い機能まとまった機能ごとに分けようと思いつき、例えばBootstrap 5とそこで使ってる@popper.jsをひとまとめにしてみたり、OpenLayersと一緒に使ってるproj4jsをひとまとめにしてみたりして、括りだしていたりする。

# 参考記事など

- [Vite index\.html を移動させて開発ディレクトリを作りたいときの Tips \- かもメモ](https://chaika.hatenablog.com/entry/2022/12/08/083000)
- [静的アセットの取り扱い \| Vite](https://ja.vitejs.dev/guide/assets.html)
- [vite でアセットを相対パスにする \- Qiita](https://qiita.com/d2cid-kimura/items/765f629dbdcfff1499bb)