Skip to content

Commit 2d50ac1

Browse files
committed
ssr inject: false option
1 parent 94d5e33 commit 2d50ac1

File tree

4 files changed

+142
-40
lines changed

4 files changed

+142
-40
lines changed

src/server/create-renderer.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export type RenderOptions = {
2323
isUnaryTag?: Function;
2424
cache?: RenderCache;
2525
template?: string;
26+
inject?: boolean;
2627
basedir?: string;
2728
shouldPreload?: Function;
2829
clientManifest?: ClientManifest;
@@ -34,13 +35,15 @@ export function createRenderer ({
3435
directives = {},
3536
isUnaryTag = (() => false),
3637
template,
38+
inject,
3739
cache,
3840
shouldPreload,
3941
clientManifest
4042
}: RenderOptions = {}): Renderer {
4143
const render = createRenderFunction(modules, directives, isUnaryTag, cache)
4244
const templateRenderer = new TemplateRenderer({
4345
template,
46+
inject,
4447
shouldPreload,
4548
clientManifest
4649
})

src/server/template-renderer/index.js

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export const isJS = (file: string): boolean => JS_RE.test(file)
1414

1515
type TemplateRendererOptions = {
1616
template: ?string;
17+
inject?: boolean;
1718
clientManifest?: ClientManifest;
1819
shouldPreload?: (file: string, type: string) => boolean;
1920
};
@@ -33,6 +34,7 @@ export type ClientManifest = {
3334

3435
export default class TemplateRenderer {
3536
options: TemplateRendererOptions;
37+
inject: boolean;
3638
parsedTemplate: ParsedTemplate | null;
3739
publicPath: string;
3840
clientManifest: ClientManifest;
@@ -42,6 +44,7 @@ export default class TemplateRenderer {
4244

4345
constructor (options: TemplateRendererOptions) {
4446
this.options = options
47+
this.inject = options.inject !== false
4548
// if no template option is provided, the renderer is created
4649
// as a utility object for rendering assets like preload links and scripts.
4750
this.parsedTemplate = options.template
@@ -74,17 +77,26 @@ export default class TemplateRenderer {
7477
throw new Error('renderSync cannot be called without a template.')
7578
}
7679
context = context || {}
77-
return (
78-
template.head(context) +
79-
(context.head || '') +
80-
this.renderLinks(context) +
81-
this.renderStyles(context) +
82-
template.neck(context) +
83-
content +
84-
this.renderState(context) +
85-
this.renderScripts(context) +
86-
template.tail(context)
87-
)
80+
if (this.inject) {
81+
return (
82+
template.head(context) +
83+
(context.head || '') +
84+
this.renderLinks(context) +
85+
this.renderStyles(context) +
86+
template.neck(context) +
87+
content +
88+
this.renderState(context) +
89+
this.renderScripts(context) +
90+
template.tail(context)
91+
)
92+
} else {
93+
return (
94+
template.head(context) +
95+
template.neck(context) +
96+
content +
97+
template.tail(context)
98+
)
99+
}
88100
}
89101

90102
renderStyles (context: Object): string {

src/server/template-renderer/template-stream.js

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export default class TemplateStream extends Transform {
99
renderer: TemplateRenderer;
1010
template: ParsedTemplate;
1111
context: Object;
12+
inject: boolean;
1213

1314
constructor (
1415
renderer: TemplateRenderer,
@@ -20,6 +21,7 @@ export default class TemplateStream extends Transform {
2021
this.renderer = renderer
2122
this.template = template
2223
this.context = context || {}
24+
this.inject = renderer.inject
2325
}
2426

2527
_transform (data: Buffer | string, encoding: string, done: Function) {
@@ -35,26 +37,22 @@ export default class TemplateStream extends Transform {
3537
this.started = true
3638
this.push(this.template.head(this.context))
3739

38-
// inline server-rendered head meta information
39-
if (this.context.head) {
40-
this.push(this.context.head)
41-
}
40+
if (this.inject) {
41+
// inline server-rendered head meta information
42+
if (this.context.head) {
43+
this.push(this.context.head)
44+
}
4245

43-
// inline preload directives for initial chunks
44-
const preloadLinks = this.renderer.renderPreloadLinks(this.context)
45-
if (preloadLinks) {
46-
this.push(preloadLinks)
47-
}
46+
// inline preload/prefetch directives for initial/async chunks
47+
const links = this.renderer.renderLinks(this.context)
48+
if (links) {
49+
this.push(links)
50+
}
4851

49-
// inline prefetch directives for async chunks not used during render
50-
const prefetchLinks = this.renderer.renderPrefetchLinks(this.context)
51-
if (prefetchLinks) {
52-
this.push(prefetchLinks)
53-
}
54-
55-
// inline server-rendered CSS collected by vue-style-loader
56-
if (this.context.styles) {
57-
this.push(this.context.styles)
52+
// inline server-rendered CSS collected by vue-style-loader
53+
if (this.context.styles) {
54+
this.push(this.context.styles)
55+
}
5856
}
5957

6058
this.push(this.template.neck(this.context))
@@ -63,16 +61,18 @@ export default class TemplateStream extends Transform {
6361
_flush (done: Function) {
6462
this.emit('beforeEnd')
6563

66-
// inline initial store state
67-
const state = this.renderer.renderState(this.context)
68-
if (state) {
69-
this.push(state)
70-
}
64+
if (this.inject) {
65+
// inline initial store state
66+
const state = this.renderer.renderState(this.context)
67+
if (state) {
68+
this.push(state)
69+
}
7170

72-
// embed scripts needed
73-
const scripts = this.renderer.renderScripts(this.context)
74-
if (scripts) {
75-
this.push(scripts)
71+
// embed scripts needed
72+
const scripts = this.renderer.renderScripts(this.context)
73+
if (scripts) {
74+
this.push(scripts)
75+
}
7676
}
7777

7878
this.push(this.template.tail(this.context))

test/ssr/ssr-template.spec.js

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import VueSSRClientPlugin from '../../packages/vue-server-renderer/client-plugin
66
import { createRenderer as createBundleRenderer } from './ssr-bundle-render.spec.js'
77

88
const defaultTemplate = `<html><head></head><body><!--vue-ssr-outlet--></body></html>`
9+
const interpolateTemplate = `<html><head><title>{{ title }}</title></head><body><!--vue-ssr-outlet-->{{{ snippet }}}</body></html>`
910

1011
function generateClientManifest (file, cb) {
1112
compileWithWebpack(file, {
@@ -65,6 +66,38 @@ describe('SSR: template option', () => {
6566
}, context)
6667
})
6768

69+
it('renderToString with interpolation', done => {
70+
const renderer = createRenderer({
71+
template: interpolateTemplate
72+
})
73+
74+
const context = {
75+
title: '<script>hacks</script>',
76+
snippet: '<div>foo</div>',
77+
head: '<meta name="viewport" content="width=device-width">',
78+
styles: '<style>h1 { color: red }</style>',
79+
state: { a: 1 }
80+
}
81+
82+
renderer.renderToString(new Vue({
83+
template: '<div>hi</div>'
84+
}), (err, res) => {
85+
expect(err).toBeNull()
86+
expect(res).toContain(
87+
`<html><head>` +
88+
// double mustache should be escaped
89+
`<title>&lt;script&gt;hacks&lt;/script&gt;</title>` +
90+
`${context.head}${context.styles}</head><body>` +
91+
`<div data-server-rendered="true">hi</div>` +
92+
`<script>window.__INITIAL_STATE__={"a":1}</script>` +
93+
// triple should be raw
94+
`<div>foo</div>` +
95+
`</body></html>`
96+
)
97+
done()
98+
}, context)
99+
})
100+
68101
it('renderToStream', done => {
69102
const renderer = createRenderer({
70103
template: defaultTemplate
@@ -95,6 +128,43 @@ describe('SSR: template option', () => {
95128
})
96129
})
97130

131+
it('renderToStream with interpolation', done => {
132+
const renderer = createRenderer({
133+
template: interpolateTemplate
134+
})
135+
136+
const context = {
137+
title: '<script>hacks</script>',
138+
snippet: '<div>foo</div>',
139+
head: '<meta name="viewport" content="width=device-width">',
140+
styles: '<style>h1 { color: red }</style>',
141+
state: { a: 1 }
142+
}
143+
144+
const stream = renderer.renderToStream(new Vue({
145+
template: '<div>hi</div>'
146+
}), context)
147+
148+
let res = ''
149+
stream.on('data', chunk => {
150+
res += chunk
151+
})
152+
stream.on('end', () => {
153+
expect(res).toContain(
154+
`<html><head>` +
155+
// double mustache should be escaped
156+
`<title>&lt;script&gt;hacks&lt;/script&gt;</title>` +
157+
`${context.head}${context.styles}</head><body>` +
158+
`<div data-server-rendered="true">hi</div>` +
159+
`<script>window.__INITIAL_STATE__={"a":1}</script>` +
160+
// triple should be raw
161+
`<div>foo</div>` +
162+
`</body></html>`
163+
)
164+
done()
165+
})
166+
})
167+
98168
it('bundleRenderer + renderToString', done => {
99169
createBundleRenderer('app.js', {
100170
asBundle: true,
@@ -204,6 +274,24 @@ describe('SSR: template option', () => {
204274
})
205275
})
206276

277+
it('bundleRenderer + renderToString + clientManifest + inject: false', done => {
278+
createRendererWithManifest('split.js', {
279+
runInNewContext,
280+
template: `<html>` +
281+
`<head>{{{ renderLinks() }}}</head>` +
282+
`<body><!--vue-ssr-outlet-->{{{ renderScripts() }}}</body>` +
283+
`</html>`,
284+
inject: false
285+
}, renderer => {
286+
const context = {}
287+
renderer.renderToString(context, (err, res) => {
288+
expect(err).toBeNull()
289+
expect(res).toContain(expectedHTMLWithManifest(false))
290+
done()
291+
})
292+
})
293+
})
294+
207295
it('bundleRenderer + renderToString + clientManifest + no template', done => {
208296
createRendererWithManifest('split.js', {
209297
runInNewContext,
@@ -215,8 +303,7 @@ describe('SSR: template option', () => {
215303

216304
const customOutput =
217305
`<html><head>${
218-
context.renderPreloadLinks() +
219-
context.renderPrefetchLinks()
306+
context.renderLinks()
220307
}</head><body>${
221308
res +
222309
context.renderScripts()

0 commit comments

Comments
 (0)