const Koa = require('koa');
const path = require('path');
const Router = require('koa-router');
const {
createBundleRenderer
} = require('vue-server-renderer');
const {
LRUCache
} = require('lru-cache'); // 引入 lru-cache
// --- 1. 初始化所有缓存实1例 ---
// a. 用于组件级缓存
const componentCache = new LRUCache({
max: 1000,
ttl: 1000 * 60 * 5, // 缓存5分钟
});
// b. 用于页面级缓存
const pageCache = new LRUCache({
max: 100,
ttl: 1000 * 60, // 缓存1分钟
});
// ... (devConfig, PORT, app, router 等初始化) ...
const devConfig = require('./build/dev.config.js');
const PORT = 3003;
let renderer;
const app = new Koa();
const router = new Router();
// --- 2. 注入组件级缓存 ---
const createRenderer = (bundle, options) => {
renderer = createBundleRenderer(
bundle,
Object.assign(options, {
runInNewContext: false,
cache: componentCache, // 注入组件缓存
})
);
};
if (process.env.NODE_ENV === 'production') {
const template = require('fs').readFileSync('./src/index.template.html', 'utf-8');
const serverBundle = require('./dist/vue-ssr-server-bundle.json');
const clientManifest = require('./dist/vue-ssr-client-manifest.json');
createRenderer(serverBundle, {
template,
clientManifest,
});
} else {
const template = path.resolve(__dirname, './src/index.template.html');
devConfig(app, template, (bundle, options) => {
createRenderer(bundle, options);
});
}
// --- 3. 实现页面缓存和HTTP缓存头的中间件 ---
const render = async (ctx, next) => {
const url = ctx.url;
// 设置HTTP缓存头,对所有请求生效
// public: 响应可以被CDN等中间缓存存储
// max-age=300: 缓存有效期5分钟
ctx.set('Cache-Control', 'public, max-age=300');
// 检查页面缓存
const cachedPage = pageCache.get(url);
if (cachedPage) {
console.log(`[Page Cache HIT] for ${url}`);
ctx.set('Content-Type', 'text/html');
ctx.body = cachedPage;
return next();
}
console.log(`[Page Cache MISS] for ${url}`);
// 页面缓存未命中,执行渲染
ctx.set('Content-Type', 'text/html');
const context = {
url: url,
title: '服务端渲染',
meta: `
`,
};
try {
// 调用 renderToString 时,组件级缓存会自动生效
const html = await renderer.renderToString(context);
ctx.body = html;
// 将新渲染的页面存入缓存
pageCache.set(url, html);
} catch (err) {
console.log(err);
ctx.status = 500;
ctx.body = 'Internal Server Error';
}
next();
};
router.get('*', render);
app.use(router.routes()).use(router.allowedMethods());
app.listen(PORT, () => {
console.log(`server started at http://localhost:${PORT}`);
});©2026 Hejian
陕 ICP 备 2025072452 号-1