Skip to content

Commit fae6b87

Browse files
committed
refactor: pull in vue-ssr-html-stream and refactor into generic template renderer
1 parent e165b32 commit fae6b87

File tree

10 files changed

+361
-37
lines changed

10 files changed

+361
-37
lines changed

flow/modules.js

+3-14
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,8 @@ declare module 'de-indent' {
3030
}
3131
}
3232

33-
declare module 'vue-ssr-html-stream' {
34-
declare interface parsedTemplate {
35-
head: string;
36-
neck: string;
37-
tail: string;
38-
}
39-
declare interface HTMLStreamOptions {
40-
template: string | parsedTemplate;
41-
context?: ?Object;
42-
}
43-
declare class exports extends stream$Transform {
44-
constructor(options: HTMLStreamOptions): void;
45-
static parseTemplate(template: string): parsedTemplate;
46-
static renderTemplate(template: parsedTemplate, content: string, context?: ?Object): string;
33+
declare module 'serialize-javascript' {
34+
declare var exports: {
35+
(input: string, options: { isJSON: boolean }): string
4736
}
4837
}

packages/vue-server-renderer/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"de-indent": "^1.0.2",
2323
"resolve": "^1.2.0",
2424
"source-map": "0.5.6",
25-
"vue-ssr-html-stream": "^2.1.0"
25+
"serialize-javascript": "^1.3.0"
2626
},
2727
"homepage": "https://github.com/vuejs/vue/tree/dev/packages/vue-server-renderer#readme"
2828
}

src/entries/web-server-renderer.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
process.env.VUE_ENV = 'server'
44

55
import { createRenderer as _createRenderer } from 'server/create-renderer'
6-
import { createBundleRendererCreator } from 'server/create-bundle-renderer'
6+
import { createBundleRendererCreator } from 'server/bundle-renderer/create-bundle-renderer'
77
import { isUnaryTag, canBeLeftOpenTag } from 'web/compiler/util'
88
import modules from 'web/server/modules/index'
99
import baseDirectives from 'web/server/directives/index'

src/server/create-bundle-renderer.js src/server/bundle-renderer/create-bundle-renderer.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* @flow */
22

33
import { createBundleRunner } from './create-bundle-runner'
4-
import type { Renderer, RenderOptions } from './create-renderer'
4+
import type { Renderer, RenderOptions } from '../create-renderer'
55
import { createSourceMapConsumers, rewriteErrorTrace } from './source-map-support'
66

77
const fs = require('fs')

src/server/create-bundle-runner.js src/server/bundle-renderer/create-bundle-runner.js

+7-6
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ function compileModule (files, basedir) {
3838
return script
3939
}
4040

41-
function evaluateModule (filename, context, evaluatedModules) {
42-
if (evaluatedModules[filename]) {
43-
return evaluatedModules[filename]
41+
function evaluateModule (filename, context, evaluatedFiles) {
42+
if (evaluatedFiles[filename]) {
43+
return evaluatedFiles[filename]
4444
}
4545

4646
const script = getCompiledScript(filename)
@@ -49,7 +49,7 @@ function compileModule (files, basedir) {
4949
const r = file => {
5050
file = path.join('.', file)
5151
if (files[file]) {
52-
return evaluateModule(file, context, evaluatedModules)
52+
return evaluateModule(file, context, evaluatedFiles)
5353
} else if (basedir) {
5454
return require(
5555
resolvedModules[file] ||
@@ -64,7 +64,7 @@ function compileModule (files, basedir) {
6464
const res = Object.prototype.hasOwnProperty.call(m.exports, 'default')
6565
? m.exports.default
6666
: m.exports
67-
evaluatedModules[filename] = res
67+
evaluatedFiles[filename] = res
6868
return res
6969
}
7070
return evaluateModule
@@ -74,7 +74,8 @@ export function createBundleRunner (entry, files, basedir) {
7474
const evaluate = compileModule(files, basedir)
7575
return (_context = {}) => new Promise((resolve, reject) => {
7676
const context = createContext(_context)
77-
const res = evaluate(entry, context, {})
77+
const evaluatedFiles = _context._evaluatedFiles = {}
78+
const res = evaluate(entry, context, evaluatedFiles)
7879
resolve(typeof res === 'function' ? res(_context) : res)
7980
})
8081
}

src/server/create-renderer.js

+18-14
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
/* @flow */
22

3-
const HTMLStream = require('vue-ssr-html-stream')
4-
53
import RenderStream from './render-stream'
4+
import TemplateRenderer from './template-renderer/index'
65
import { createWriteFunction } from './write'
76
import { createRenderFunction } from './render'
87

@@ -24,17 +23,25 @@ export type RenderOptions = {
2423
cache?: RenderCache;
2524
template?: string;
2625
basedir?: string;
26+
manifest?: {
27+
server: Object;
28+
client: Object;
29+
}
2730
};
2831

2932
export function createRenderer ({
3033
modules = [],
3134
directives = {},
3235
isUnaryTag = (() => false),
3336
template,
34-
cache
37+
cache,
38+
manifest
3539
}: RenderOptions = {}): Renderer {
3640
const render = createRenderFunction(modules, directives, isUnaryTag, cache)
37-
const parsedTemplate = template && HTMLStream.parseTemplate(template)
41+
const templateRenderer = template && new TemplateRenderer({
42+
template,
43+
manifest
44+
})
3845

3946
return {
4047
renderToString (
@@ -48,8 +55,8 @@ export function createRenderer ({
4855
}, done)
4956
try {
5057
render(component, write, () => {
51-
if (parsedTemplate) {
52-
result = HTMLStream.renderTemplate(parsedTemplate, result, context)
58+
if (templateRenderer) {
59+
result = templateRenderer.renderSync(result, context)
5360
}
5461
done(null, result)
5562
})
@@ -65,18 +72,15 @@ export function createRenderer ({
6572
const renderStream = new RenderStream((write, done) => {
6673
render(component, write, done)
6774
})
68-
if (!parsedTemplate) {
75+
if (!templateRenderer) {
6976
return renderStream
7077
} else {
71-
const htmlStream = new HTMLStream({
72-
template: parsedTemplate,
73-
context
74-
})
78+
const templateStream = templateRenderer.createStream(context)
7579
renderStream.on('error', err => {
76-
htmlStream.emit('error', err)
80+
templateStream.emit('error', err)
7781
})
78-
renderStream.pipe(htmlStream)
79-
return htmlStream
82+
renderStream.pipe(templateStream)
83+
return templateStream
8084
}
8185
}
8286
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* @flow */
2+
3+
/**
4+
* Creates a mapper that maps files used during a server-side render
5+
* to async chunk files in the client-side build, so that we can inline them
6+
* directly in the rendered HTML to avoid waterfall requests.
7+
*/
8+
9+
export function createMapper (serverStats: Object, clientStats: Object) {
10+
const fileMap = createFileMap(serverStats, clientStats)
11+
return function mapFiles (files: Array<string>): Array<string> {
12+
const res = new Set()
13+
for (let i = 0; i < files.length; i++) {
14+
const mapped = fileMap.get(files[i])
15+
if (mapped) {
16+
for (let j = 0; j < mapped.length; j++) {
17+
res.add(mapped[j])
18+
}
19+
}
20+
}
21+
return Array.from(res)
22+
}
23+
}
24+
25+
function createFileMap (serverStats, clientStats) {
26+
const fileMap = new Map()
27+
serverStats.assets
28+
.filter(asset => /\.js$/.test(asset.name))
29+
.forEach(asset => {
30+
const mapped = mapFile(asset.name, serverStats, clientStats)
31+
fileMap.set(asset.name, mapped)
32+
})
33+
return fileMap
34+
}
35+
36+
function mapFile (file, serverStats, clientStats) {
37+
// 1. server file -> server chunk ids
38+
const serverChunkIds = new Set()
39+
const asset = serverStats.assets.find(asset => asset.name === file)
40+
if (!asset) return []
41+
asset.chunks.forEach(id => {
42+
const chunk = serverStats.chunks.find(c => c.id === id)
43+
if (!chunk.initial) { // only map async chunks
44+
serverChunkIds.add(id)
45+
}
46+
})
47+
48+
// 2. server chunk ids -> module identifiers
49+
const moduleIdentifiers = []
50+
serverStats.modules.forEach(module => {
51+
if (module.chunks.some(id => serverChunkIds.has(id))) {
52+
moduleIdentifiers.push(module.identifier)
53+
}
54+
})
55+
56+
// 3. module identifiers -> client chunk ids
57+
const clientChunkIds = new Set()
58+
moduleIdentifiers.forEach(identifier => {
59+
const clientModule = clientStats.modules.find(m => m.identifier === identifier)
60+
if (clientModule && clientModule.chunks.length === 1) { // ignore modules duplicated in multiple chunks
61+
clientChunkIds.add(clientModule.chunks[0])
62+
}
63+
})
64+
65+
// 4. client chunks -> client files
66+
const clientFiles = new Set()
67+
Array.from(clientChunkIds).forEach(id => {
68+
const chunk = clientStats.chunks.find(chunk => chunk.id === id)
69+
if (!chunk.initial) {
70+
chunk.files.forEach(file => clientFiles.add(file))
71+
}
72+
})
73+
74+
return Array.from(clientFiles)
75+
}

0 commit comments

Comments
 (0)