const fs = require('fs'); const path = require('path'); const rp = require('request-promise'); const LRU = require('lru-cache'); const _ = require('lodash'); const pkg = require('../../package.json'); const logger = global.yoho.logger; const {createBundleRenderer} = require('vue-server-renderer'); const routes = [ { route: /product\/\d+/, cache: true, // disable: true }, { route: '/channel', cache: true }, { route: '/channel/search', cache: true }, { route: '/channel/men', cache: true }, { route: '/channel/women', cache: true }, { route: '/about', cache: true }, ]; const isDev = process.env.NODE_ENV === 'development' || !process.env.NODE_ENV; let renderer; let template = fs.readFileSync(path.join(__dirname, '../../src/index.html'), 'utf-8'); const microCache = LRU({ // eslint-disable-line max: 10000, maxAge: 2000 }); const getContext = (req) => { return { url: req.url, title: 'BLK!', user: req.user, env: { isApp: req.yoho.isApp, isiOS: req.yoho.isiOS, isAndroid: req.yoho.isAndroid, isYohoBuy: req.yoho.isYohoBuy, channel: req.yoho.channel } }; }; const render = (options) => { return (req, res, next) => { if (options.cache) { const html = microCache.get(req.url); if (html) { console.log('cache', req.url); return res.send(html); } } let context = getContext(req); renderer.renderToString(context, (err, html) => { if (err) { // TODO 处理错误类型 return next(err); } if (options.cache) { microCache.set(req.url, html); } return res.send(html); }); }; }; const devRender = () => { return (req, res, next) => { let context = getContext(req); process.send({action: 'ssr_request', context}); let event = msg => { process.removeListener('message', event); if (msg.action === 'ssr_request') { if (msg.err) { try { const err = JSON.parse(msg.err); if (err.code === 404) { return next(); } return next(err); } catch (e) { return next({ code: 500, message: msg.err }); } } return res.end(msg.html); } }; process.on('message', event); }; }; const loadBundle = async (errorCount = 0) => { if (!isDev) { if (errorCount > 5) { throw { code: 9999, message: 'ssr bundle download faild 5!' }; } await Promise.all([ rp(`http://cdn.yoho.cn/yohoblk-wap/bundle/yoho-ssr-server-${pkg.version}.json`, {json: true}), rp(`http://cdn.yoho.cn/yohoblk-wap/bundle/yoho-ssr-client-${pkg.version}.json`, {json: true}), ]).then(results => { logger.warn('ssr file is loaded'); renderer = createBundleRenderer(results[0], { runInNewContext: false, template, clientManifest: results[1] }); }).catch(() => { return loadBundle(errorCount + 1); }); // const serverBundle = require(`../../public/dist/yohoblk-wap/bundle/yoho-ssr-server-${pkg.version}.json`); // const clientManifest = require(`../../public/dist/yohoblk-wap/bundle/yoho-ssr-client-${pkg.version}.json`); // renderer = createBundleRenderer(serverBundle, { // runInNewContext: false, // template, // clientManifest // }); } }; const ssrRender = options => isDev ? devRender(options) : render(options); module.exports = async (app) => { await loadBundle(); _.each(routes, r => { if (!r.disable) { app.get(r.route, ssrRender({ cache: r.cache })); } }); };