ssr.js 3.28 KB
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 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 isCacheable = () => {
    return false;
};

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 = (req, res, next) => {
    const cacheable = isCacheable(req);

    if (cacheable) {
        const html = microCache.get(req.url);

        if (html) {
            return res.send(html);
        }
    }
    let context = getContext(req);

    renderer.renderToString(context, (err, html) => {
        if (err) {
            // TODO 处理错误类型
            return next(err);
        }
        if (cacheable) {
            microCache.set(req.url, html);
        }
        return res.send(html);
    });
};

if (!isDev) {
    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]
        });
    });

    // 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 = isDev ? (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);
} : render;

const routes = [
    /product\/\d+/,
    '/channel',
    '/channel/search',
    '/channel/men',
    '/channel/women',
    '/about'
];

module.exports = app => {
    _.each(routes, r => app.get(r, ssrRender));
};