From ae5ad185a06622c917153846654e5e6e83c2833b Mon Sep 17 00:00:00 2001 From: hubcarl Date: Thu, 31 May 2018 13:01:56 +0800 Subject: [PATCH] feat: support config.mergeLocals config and set runInNewContext default once --- README.md | 17 +++++++------ config/config.default.js | 13 ++++++---- lib/engine.js | 25 +++++++++++++++---- lib/view.js | 2 +- package.json | 2 +- .../view-vue-ssr-test/app/controller/view.js | 6 +++++ .../apps/view-vue-ssr-test/app/router.js | 1 + .../view-vue-ssr-test/config/config.test.js | 18 +++++++++++++ test/view-vue-ssr.test.js | 25 +++++++++++++++++++ 9 files changed, 89 insertions(+), 20 deletions(-) create mode 100644 test/fixtures/apps/view-vue-ssr-test/config/config.test.js diff --git a/README.md b/README.md index c8df4bf..47ae3d8 100644 --- a/README.md +++ b/README.md @@ -68,9 +68,9 @@ exports.vuessr = { // }, }; ``` -- **doctype**: html content will auto add ``, you can set `doctype: ''` -- **layout**: client render template, support renderString compile -- **manifest**: static resource dependence, the content such as: +- **doctype**: {String} html content will auto add ``, you can set `doctype: ''` +- **layout**: {String} client render template, support renderString compile +- **manifest**: {Object} static resource dependence, the content such as: ```json { @@ -90,14 +90,15 @@ exports.vuessr = { } } ``` -- **injectCss**: whether inject href css, default true -- **injectJs**: whether inject src script, default true -- **injectRes**: inline/inject css or js to file head or body. include location and src config +- **injectCss**: {Boolean} whether inject href css, default true +- **injectJs**: {Boolean} whether inject src script, default true +- **injectRes**: {Boolean} inline/inject css or js to file head or body. include location and src config inline {Boolean} true or false, default false location {String} headBefore, headAfter, bodyBefore, bodyAfter insert location, default headBefore url {String} inline file absolution path -- **crossorigin**: js cross domain support for cdn js error catch, default false -- **fallbackToClient**: fallback to client rendering if server render failed, default true +- **mergeLocals** {Boolean} whether merge ctx locals to data, default true +- **crossorigin**: {Boolean} js cross domain support for cdn js error catch, default false +- **fallbackToClient**: {Boolean} fallback to client rendering if server render failed, default true - **cache**: lru-cache options @see https://www.npmjs.com/package/lru-cache - **renderOptions**: @see https://ssr.vuejs.org/en/api.html#renderer-options - **afterRender**: afterRender hook html after render diff --git a/config/config.default.js b/config/config.default.js index df79568..2c4a383 100644 --- a/config/config.default.js +++ b/config/config.default.js @@ -18,11 +18,12 @@ module.exports = app => { * @property {String} [manifest=${baseDir}/config/manifest.json] - resource dependence(css, js) config * @property {Boolean} [injectCss] whether inject href css * @property {Boolean} [injectJs] whether inject src script - * @property {Boolean|String} [crossorigin] js cross domain support for cdn js error catch, default false * @property {Array} [injectRes] inline/inject css or js to file head or body. include location and src config * inline {Boolean} true or false, default false * location {String} headBefore, headAfter, bodyBefore, bodyAfter insert location, default headBefore * url {String} inline file absolution path + * @property {Boolean} [mergeLocals] whether merge ctx locals, default true + * @property {Boolean|String} [crossorigin] js cross domain support for cdn js error catch, default false * @property {Object} [cache] lru-cache options @see https://www.npmjs.com/package/lru-cache * @property {Object} [renderOptions] @see https://ssr.vuejs.org/en/api.html#renderer-options * renderOptions.template will override layout template @@ -38,16 +39,18 @@ module.exports = app => { injectBodyRegex: /(<\/body>)/i, injectCss: true, injectJs: true, - crossorigin: false, injectRes: [], + crossorigin: false, + mergeLocals: true, fallbackToClient: true, // fallback to client rendering if server render failed, cache: { max: 1000, maxAge: 1000 * 3600 * 24 * 7, }, - // renderOptions: { - // template: ``, - // }, + renderOptions: { + runInNewContext: 'once', + // template: ``, + }, afterRender: (html, context) => { /* eslint no-unused-vars:off */ return html; }, diff --git a/lib/engine.js b/lib/engine.js index b90083e..69a3fc5 100644 --- a/lib/engine.js +++ b/lib/engine.js @@ -43,12 +43,27 @@ class Engine { return this[VUE_RESOURCE]; } - normalizeLocals(ctx, locals = {}) { - [ 'ctx', 'request', 'helper' ].forEach(key => { - Object.defineProperty(locals, key, { enumerable: false }); - }); - return Object.assign({}, { csrf: ctx.csrf }, locals); + normalizeLocals(ctx, locals = {}, options = {}) { + // default locals and data merge; + if (this.config.mergeLocals) { + [ 'ctx', 'request', 'helper' ].forEach(key => { + Object.defineProperty(locals, key, { enumerable: false }); + }); + return this.setCSRFLocals(ctx, locals); + } + // only data + return this.setCSRFLocals(ctx, options && options.locals || {}); } + + setCSRFLocals(ctx, locals) { + // when csrf enable, set ctx csrf + const security = this.app.config.security; + if (security.csrf && security.csrf.enable) { + return Object.assign({}, { csrf: ctx.csrf }, locals); + } + return locals; + } + createBundleRenderer(name, renderOptions) { if (this.bundleCache) { const bundleRenderer = this.bundleCache.get(name); diff --git a/lib/view.js b/lib/view.js index 16b9f5a..e0ecb0e 100644 --- a/lib/view.js +++ b/lib/view.js @@ -16,7 +16,7 @@ class View { * @return {Object} Promise */ render(name, locals, options = {}) { - locals = this.app.vue.normalizeLocals(this.ctx, locals); + locals = this.app.vue.normalizeLocals(this.ctx, locals, options); const context = { state: locals }; return this.app.vue.render(name, context, options).then(html => { return this.app.vue.resource.inject(html, options.name, context, options); diff --git a/package.json b/package.json index 72400f4..797702c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-view-vue-ssr", - "version": "3.0.8", + "version": "3.1.0", "description": "vue server side render solution for egg", "eggPlugin": { "name": "vuessr" diff --git a/test/fixtures/apps/view-vue-ssr-test/app/controller/view.js b/test/fixtures/apps/view-vue-ssr-test/app/controller/view.js index c99ea9a..9e68e63 100755 --- a/test/fixtures/apps/view-vue-ssr-test/app/controller/view.js +++ b/test/fixtures/apps/view-vue-ssr-test/app/controller/view.js @@ -25,6 +25,12 @@ exports.render = function* (ctx) { yield ctx.render('test/test.js', { message: 'vue server side render!' }); }; +exports.renderLocals = function* (ctx) { + this.app.locals.title = 'app_locals_render_ssr'; + this.locals.description = 'app_context_locals_render_ssr'; + yield ctx.render('test/test.js', { message: 'vue server side render!' }); +}; + exports.renderServerError = function* (ctx) { yield ctx.render('error/error.js', { keywords: 'ssr', diff --git a/test/fixtures/apps/view-vue-ssr-test/app/router.js b/test/fixtures/apps/view-vue-ssr-test/app/router.js index 7c43e2b..1b7dabc 100644 --- a/test/fixtures/apps/view-vue-ssr-test/app/router.js +++ b/test/fixtures/apps/view-vue-ssr-test/app/router.js @@ -5,6 +5,7 @@ module.exports = app => { this.body = 'hi, vue ssr'; }); app.get('/render', app.controller.view.render); + app.get('/renderLocals', app.controller.view.renderLocals); app.get('/renderString', app.controller.view.renderString); app.get('/renderClient', app.controller.view.renderClient); app.get('/renderVueClient', app.controller.view.renderVueClient); diff --git a/test/fixtures/apps/view-vue-ssr-test/config/config.test.js b/test/fixtures/apps/view-vue-ssr-test/config/config.test.js new file mode 100644 index 0000000..e4161b9 --- /dev/null +++ b/test/fixtures/apps/view-vue-ssr-test/config/config.test.js @@ -0,0 +1,18 @@ +'use strict'; + +'use strict'; +module.exports = () => { + const config = {}; + + config.vuessr = { + mergeLocals: false, + }; + + config.security = { + csrf: { + enable: false + } + }; + + return config; +}; diff --git a/test/view-vue-ssr.test.js b/test/view-vue-ssr.test.js index ae97126..fc3da29 100644 --- a/test/view-vue-ssr.test.js +++ b/test/view-vue-ssr.test.js @@ -39,6 +39,7 @@ describe('test/view-vue-ssr.test.js', () => { assert(res.text.indexOf('"csrf"') > -1); assert(res.text.indexOf('data-server-rendered="true"') > -1); assert(res.text.indexOf('') > -1); + assert(res.text.indexOf('app_locals_render_ssr') > -1); assert(res.text.indexOf('vue server side render!') > -1); assert(res.text.indexOf('/public/css/test/test.css') > -1); assert(res.text.indexOf('/public/js/vendor.js"') > -1); @@ -111,4 +112,28 @@ describe('test/view-vue-ssr.test.js', () => { }); }); + describe('locals and crsf test', () => { + let app; + before(() => { + mm.env('test'); + app = mm.app({ + baseDir: 'apps/view-vue-ssr-test', + }); + return app.ready(); + }); + + after(() => app.close()); + afterEach(mm.restore); + + it('should GET /renderLocals', () => { + return request(app.callback()) + .get('/renderLocals') + .expect(200) + .expect(res => { + assert(res.text.indexOf('"csrf"') === -1); + assert(res.text.indexOf('app_locals_render_ssr') === -1); + assert(res.text.indexOf('data-server-rendered="true"') > -1); + }); + }); + }); });