🚅
Viteをexpressにぶちこむ
ExpressサーバーとViteを組み合わせたら楽だなとか思ったのでやってみました。
Viteのアプリを作成
今回はModuleA
という名前でViteアプリを作成します。
npm init vite
または
yarn create vite
現在のディレクトリ構成
.
├── root
├── package.json
├── yarn.lock
└── modules
└── ModuleA
├── src
├── .gitignore
├── index.html
├── package.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
Expressアプリを作成
まずはモジュールのインストール。
mkdir modules/ModuleB
cd modules/ModuleB
yarn init
yarn add express vite
yarn add -D typescript @types/node @types/express
次にコードを書いていきます。
src/index.ts
import express from 'express'
const app = express()
app.listen(3000, () => {
console.log('listening on port 3000')
})
書いてあるそのまんまです。
expressをインポートして3000
番でサーバーを起動しています。
次にviteのサーバー用のコードを
src/viteServer.ts
import express from 'express'
import fs from 'fs-extra'
import path from 'path'
import { createServer } from 'vite'
export const createViteDevServer = async (cwd = path.resolve('../', 'bacon-front-vite')) => {
if (!fs.existsSync(cwd)) throw new Error(`No such directory: ${cwd}`)
const app = express.Router()
const vite = await createServer({
root: cwd,
logLevel: 'info',
server: {
middlewareMode: true,
watch: {
usePolling: true,
interval: 100,
},
},
})
app.use(vite.middlewares)
app.use('*', async (req, res) => {
try {
const url = req.originalUrl
const html = fs.readFileSync(path.resolve(cwd, 'index.html'), 'utf-8')
res.status(200)
.set({ 'Content-Type': 'text/html' })
.end(await vite.transformIndexHtml(url, html))
} catch (e) {
if (e instanceof Error) {
vite && vite.ssrFixStacktrace(e)
console.log(e.stack)
res.status(500).end(e.stack)
}
}
})
return { app, vite }
}
上から順番に
cwd
にはviteプロジェクトのディレクトリを指定します。
次にルーターとviteのサーバーを作成して、
viteのミドルウェアをルーターにバインドします。
src/viteServer.ts
export const createViteDevServer = async (cwd) => {
if (!fs.existsSync(cwd)) throw new Error(`No such directory: ${cwd}`)
const app = express.Router()
const vite = await createServer({
root: cwd,
logLevel: 'info',
server: {
middlewareMode: true,
watch: {
usePolling: true,
interval: 100,
},
},
})
app.use(vite.middlewares)
...
}
まずviteプロジェクトのディレクトリからindex.html
を読み込みます。
つぎにvite.transformIndexHtml
にURLとHTMLを渡してビルドし、htmlを返します。
src/viteServer.ts
export const createViteDevServer = async (cwd) => {
...
app.use('*', async (req, res) => {
try {
const url = req.originalUrl
const html = fs.readFileSync(path.resolve(cwd, 'index.html'), 'utf-8')
res.status(200)
.set({ 'Content-Type': 'text/html' })
.end(await vite.transformIndexHtml(url, html))
} catch (e) {
if (e instanceof Error) {
res.status(500).end(e.stack)
}
}
})
return { app, vite }
}
最後にはじめのindex.ts
を少し書き換えます。
src/index.ts
import express from 'express'
import { createViteDevServer } from './viteServer'
const app = express()
app.listen(3000, () => {
console.log('listening on port 3000')
})
+ createViteDevServer('../../ModuleA').then(({app}) => {
+ app.use(app)
+ })
現在のディレクトリ構成
.
├── root
├── package.json
├── yarn.lock
└── modules
├── ModuleA
│ ├── src
│ ├── .gitignore
│ ├── index.html
│ ├── package.json
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
└── ModuleB
├── src
│ ├── index.ts
│ └── viteServer.ts
├── package.json
└── tsconfig.json
起動する
ModuleB
内でsrc/index.ts
を起動します。
今回はts-nodeで起動します。
yarn ts-node src/index.ts
しばらくすると以下のようなログが表示されます。
Pre-bundling dependencies:
react
react-dom
baseui
chart.js
styletron-engine-atomic
(...and 26 more)
(this will be run only when your dependencies or config have changed)
この状態で指定し他ポート(今回は3030
)にアクセスすると...
無事表示されました。
ファイルを書き換えると自動で更新されます。
まとめ
vite強い!!
Discussion