GoテンプレートとVueを共存させる構成のすべて
🎯 はじめに
Vue 3 + Vite で構築した SPA と、サーバーサイドテンプレート(ここでは Go の *.tmpl
ファイル)を 共存させたい!
例えば:
-
✅
/index.html
では Vue Router を用いた SPA として動作 -
✅
/signTmp.tmpl
のような外部テンプレートでは<script src="/assets/myApp.js">
のように Vue の一部モジュールや関数だけを使いたい -
✅ でも出力された JS がバッティングせず、重複読み込みがなく、構成が汚くならないようにしたい!
⚠️ 以前の問題点・困っていたこと
問題 | 詳細 |
---|---|
🔁 Vite のビルド結果で app-[hash].js も myApp.js も preload されてしまう |
同じ内容のJSが2つ読み込まれていた(無駄) |
❌ Viteのデフォルト設定だと、外部テンプレート向けのJSを単体で出力するのが難しい | index.html が強く結びついている構成になる |
❌ <script type="module" src="/src/main.js"> が動作しない |
開発中のViteサーバなら可能だが、本番では MIMEエラーになる |
❌ myApp.js ビルド時に .vue ファイルがパースできずエラー |
vite.config.tmpl.js に Vueプラグインが未定義だった |
🔧 試したアプローチたち
❌ 方法1:main.js
を直接読み込む
<script type="module" src="/src/main.js"></script>
-
→ 本番環境で失敗(
text/html
のMIMEエラー)
❌ 方法2:vite.config.js
で rollupOptions.input
に main.js
を追加
input: {
app: 'index.html',
myApp: 'src/main.js'
}
-
→ 成功はするが、
index.html
にmyApp.js
がpreload
されてしまい JS重複読込の無駄が発生
✅ 方法3(採用!):設定ファイルを2つに分ける構成
🎯 方針:
-
vite.config.js
→ Vue SPA用(Vue Router、Piniaなど) -
vite.config.tmpl.js
→ 外部テンプレート向け最小構成(必要なモジュールだけ、グローバルにexport)
✅ 最終構成(採用した構成)
vite.config.js
(SPA専用)
import { fileURLToPath, URL } from 'node:url'
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
build: {
outDir: 'dist',
rollupOptions: {
input: 'index.html',
output: {
entryFileNames: 'assets/app-[hash].js'
}
}
}
})
vite.config.tmpl.js
(Goテンプレート等で使うJSだけをビルド)
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'node:url'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
build: {
outDir: 'dist',
emptyOutDir: false, // SPAの出力を消さない
rollupOptions: {
input: {
myApp: fileURLToPath(new URL('./src/myApp.js', import.meta.url))
},
output: {
entryFileNames: 'assets/myApp.js'
}
}
}
})
src/myApp.js
の中身例
import { pushReceive } from '@/pushReceive/pushReceive.js'
// 👇 Goテンプレートなどでこの関数を使えるように
window.pushReceive = pushReceive
console.log('✅ myApp.js loaded!')
package.json の scripts
"scripts": {
"dev": "vite",
"build": "vite build",
"build:tmpl": "vite build --config vite.config.tmpl.js",
"build:all": "npm run build && npm run build:tmpl"
}
Goテンプレート側(例:signTmp.tmpl
)
<script type="module" src="/assets/myApp.js"></script>
<script>
window.pushReceive({ action: 'thread', data: 'Hello' });
</script>
🧩 メリット・デメリット比較
項目 | 分離構成(採用) | 一体構成 |
---|---|---|
Vue SPA の最適化 | ✅ 完全保持 | ✅ 可能 |
Goテンプレート用JSの独立性 | ✅ 完全独立 | ❌ preloadされて混入 |
JSファイルの重複 | ❌(回避済) | ❌(出る) |
保守性・構成の明瞭さ | ✅ 高い | 🟡 やや不明瞭 |
ビルド管理 | 🟡 コマンド分け必要 | ✅ 単純に1回だけ |
✅ 結論:今の構成が最適な理由
-
重複読み込み(
myApp.js
が SPAに preload される)を完全に防止 -
vite.config.js
はそのまま使える(既存環境に影響しない) -
Goテンプレートや外部HTMLから Vue モジュールを安全に利用可能
-
メンテナンス性が高く、プロジェクト分離にも発展できる
🔚 まとめ
Vue SPA と Goテンプレートの共存は意外と繊細。
Viteのビルド戦略を分けることで、理想的な共存構成が実現できます!
-
SPA は SPA として最適にビルド
-
外部テンプレートは必要最小限の JS だけを export
-
preloadの無駄ゼロ、コンフリクトゼロ
🎉 これが Vue + Vite における 共存構成のベストプラクティス です!
登録日:
更新日: