- API 路由统一: 移除 /api/h5/,统一 /api/pms/ 入口 - 二进制改名: api-server -> pms-api(与服务名一致) - nginx: 合并 /api/ + /pms/api/ 为 /api/pms/ - 新增 docs/API.md 接口文档 - 后端: CabinetDetail 增加 rssi/pow_fail/address/soc 等字段 - Redis 管道批量读取仓体实时数据(SOC/电压/电流/功率) - DB: 所有 TIMESTAMP 列改为 DATETIME(修复类型不匹配) - 用户管理: 新增创建时间/修改时间列,状态改用 Switch - 角色管理/用户管理: 操作按钮改为图标 - PC 设备详情: 基本信息补全 RSSI/ICCID/电源/地址 - PC 卡片: 通道统计改用 Lucide 图标,颜色统一 - PC 二维码: canvas 渲染,含编号文字,支持右键下载 - H5: 按 uni-app 规范修正导航(navigateTo 替代 reLaunch) - H5: 详情页加返回导航条 - H5: 扫码支持摄像头(jsQR)+ ?id= 参数 - H5: 底部 tabBar 在所有页面常显 - H5: 首页统计改为 6 项(设备/通道/空闲/充电/充满/故障) - H5: 下拉刷新 / 上拉加载 - 产品首页: 添加业务联系 - 文档: 清理过时文件,补充缺失规范章节
3.5 KiB
3.5 KiB
name, description
| name | description |
|---|---|
| build-ssr | Server-side rendering setup and configuration with Vite |
Server-Side Rendering (SSR)
Low-level API for framework authors. For applications, use higher-level tools from Awesome Vite SSR.
Project Structure
├── index.html
├── server.js # Express/Node server
└── src/
├── main.js # Universal app code
├── entry-client.js # Mounts app to DOM
└── entry-server.js # Renders app with SSR API
index.html
<!DOCTYPE html>
<html>
<body>
<div id="app"><!--ssr-outlet--></div>
<script type="module" src="/src/entry-client.js"></script>
</body>
</html>
Development Server
// server.js
import express from 'express'
import { createServer as createViteServer } from 'vite'
async function createServer() {
const app = express()
const vite = await createViteServer({
server: { middlewareMode: true },
appType: 'custom'
})
app.use(vite.middlewares)
app.use('*all', async (req, res, next) => {
const url = req.originalUrl
try {
// 1. Read index.html
let template = fs.readFileSync(
path.resolve(__dirname, 'index.html'),
'utf-8'
)
// 2. Apply Vite transforms
template = await vite.transformIndexHtml(url, template)
// 3. Load server entry
const { render } = await vite.ssrLoadModule('/src/entry-server.js')
// 4. Render app HTML
const appHtml = await render(url)
// 5. Inject into template
const html = template.replace('<!--ssr-outlet-->', appHtml)
res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
} catch (e) {
vite.ssrFixStacktrace(e)
next(e)
}
})
app.listen(5173)
}
createServer()
Conditional Logic
if (import.meta.env.SSR) {
// Server-only code (tree-shaken on client)
}
Production Build
{
"scripts": {
"build:client": "vite build --outDir dist/client",
"build:server": "vite build --outDir dist/server --ssr src/entry-server.js"
}
}
Production Server
// Differences from dev:
// 1. Use dist/client/index.html as template
// 2. Use import('./dist/server/entry-server.js') instead of ssrLoadModule
// 3. Serve static files from dist/client
SSR Manifest
For preload directives:
vite build --outDir dist/client --ssrManifest
Generates dist/client/.vite/ssr-manifest.json with module-to-chunk mappings.
SSR Externals
Dependencies are externalized by default. To transform with Vite:
export default defineConfig({
ssr: {
noExternal: ['package-that-needs-transform'],
external: ['package-to-externalize']
}
})
SSR-specific Plugin Logic
export function mySSRPlugin() {
return {
name: 'my-ssr',
transform(code, id, options) {
if (options?.ssr) {
// SSR-specific transform
}
}
}
}
SSR Target
export default defineConfig({
ssr: {
target: 'node', // Default
// target: 'webworker' // For edge runtimes
}
})
SSR Bundle
Bundle all dependencies (for workers):
export default defineConfig({
ssr: {
noExternal: true // Bundle everything
}
})
Resolve Conditions
export default defineConfig({
ssr: {
resolve: {
conditions: ['node'],
externalConditions: ['node']
}
}
})
Pre-Rendering / SSG
Pre-render routes with known data into static HTML at build time.