UNPKG

generator-wxnode-boilerplate

Version:

Yeoman generator for wxnode boilerplate

132 lines (116 loc) 4.44 kB
import {BundleRenderer, createBundleRenderer} from 'vue-server-renderer'; import fs from 'fs'; import {infoL} from '../@core/log/log'; import path from 'path'; import * as Cached from '../@core/cache'; import to from 'await-to-js'; import {getIp} from '../util'; import {ICustomRouterContext} from '../@types/types'; import {errL} from '../@core/log/log'; import {IdKey} from '../config/idKey'; import {reportIdKey} from '../@core/report/idkey'; import {clientRender} from './render-client'; const isProd = process.env.NODE_ENV === 'production'; const isDebugServer = process.env.DEBUG === 'server'; const resolve = file => path.resolve(process.cwd(), file); export function createRenderer(bundle, options) { // https://github.com/vuejs/vue/blob/dev/packages/vue-server-renderer/README.md#why-use-bundlerenderer return createBundleRenderer(bundle, Object.assign(options, { // this is only needed when vue-server-renderer is npm-linked basedir: resolve('./dist'), // recommended for performance runInNewContext: false, })); } let renderer: BundleRenderer; let readyPromise: Promise<any>; let htmlTpl: string; const templatePath = resolve('./public/index.template.html'); export function initServerRender(app) { if (isProd || isDebugServer) { // In production: create server renderer using template and built server bundle. // The server bundle is generated by vue-ssr-webpack-plugin. const template = fs.readFileSync(templatePath, 'utf-8'); const bundle = require(resolve('./dist/vue-ssr-server-bundle.json')); // The client manifests are optional, but it allows the renderer // to automatically infer preload/prefetch links and directly add <script> // tags for any async chunks used during render, avoiding waterfall requests. const clientManifest = require(resolve('./dist/vue-ssr-client-manifest.json')); renderer = createRenderer(bundle, { template, clientManifest, }); } else { // In development: setup the dev server with watch and hot-reload, // and create a new renderer on bundle / index template update. readyPromise = require(resolve('./build/setup-dev-server'))( app, templatePath, (bundle, options) => { htmlTpl = options.htmlTpl; renderer = createRenderer(bundle, options); }, ); } } export async function render(ctx: ICustomRouterContext) { ctx.set('Content-Type', 'text/html'); const isHit = await Cached.getCacheAndResponse(ctx.url, ctx, Cached.CacheType.HTML); if (isHit) { infoL(`直出页面缓存命中: ${ctx.url}`); ctx.fromCached = true; return; } // 无缓存,服务端渲染 const ip = getIp(ctx); const context = { url: ctx.url, cookie: ctx.request.header.cookie, ua: ctx.request.headers['user-agent'], ip, }; const [err, html] = await to(renderer.renderToString(context)); if (err) throw err; ctx.body = html; // 缓存 Cached.set(ctx.url, html, Cached.emCACHE.Cache_Template); } export function getReadyPromise(): Promise<any> { return readyPromise; } export function getStaticHtml(): string { return htmlTpl; } // Server render出错时可以回退到 Client render const serverRenderReadyPromise = getReadyPromise(); export async function serverRender(ctx){ if(isProd){ try { await render(ctx); } catch (e) { // 同构出错,使用客户端渲染 errL('同构直出失败, 降级为前端渲染:', e); reportIdKey(IdKey.server_render_fail); if (e && e.code === 404) { // 404的情况直接返回404页面 throw e; } return clientRender(ctx); } }else{ try { await serverRenderReadyPromise; await render(ctx); } catch (e) { // 同构出错,使用客户端渲染 if (e && e.code === 404) { // 404的情况直接返回404页面 throw e; } else { errL('同构直出失败, 降级为前端渲染:', e); reportIdKey(IdKey.server_render_fail); } return clientRender(ctx); } } }