+349
-9
lines changedFilter options
+349
-9
lines changed Original file line number Diff line number Diff line change
@@ -44,6 +44,7 @@ declare type ComponentOptions = {
44
44
beforeDestroy?: Function;
45
45
destroyed?: Function;
46
46
errorCaptured?: () => boolean | void;
47
+
ssrPrefetch?: Function;
47
48
48
49
// assets
49
50
directives?: { [key: string]: Object };
Original file line number Diff line number Diff line change
@@ -79,6 +79,9 @@ export function createRenderer ({
79
79
}, cb)
80
80
try {
81
81
render(component, write, context, err => {
82
+
if (context && context.rendered) {
83
+
context.rendered(context)
84
+
}
82
85
if (template) {
83
86
result = templateRenderer.renderSync(result, context)
84
87
}
@@ -106,13 +109,25 @@ export function createRenderer ({
106
109
render(component, write, context, done)
107
110
})
108
111
if (!template) {
112
+
if (context && context.rendered) {
113
+
const rendered = context.rendered
114
+
renderStream.once('beforeEnd', () => {
115
+
rendered(context)
116
+
})
117
+
}
109
118
return renderStream
110
119
} else {
111
120
const templateStream = templateRenderer.createStream(context)
112
121
renderStream.on('error', err => {
113
122
templateStream.emit('error', err)
114
123
})
115
124
renderStream.pipe(templateStream)
125
+
if (context && context.rendered) {
126
+
const rendered = context.rendered
127
+
renderStream.once('beforeEnd', () => {
128
+
rendered(context)
129
+
})
130
+
}
116
131
return templateStream
117
132
}
118
133
}
Original file line number Diff line number Diff line change
@@ -42,6 +42,7 @@ export default class RenderStream extends stream.Readable {
42
42
})
43
43
44
44
this.end = () => {
45
+
this.emit('beforeEnd')
45
46
// the rendering is finished; we should push out the last of the buffer.
46
47
this.done = true
47
48
this.push(this.buffer)
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ let warned = Object.create(null)
19
19
const warnOnce = msg => {
20
20
if (!warned[msg]) {
21
21
warned[msg] = true
22
+
// eslint-disable-next-line no-console
22
23
console.warn(`\n\u001b[31m${msg}\u001b[39m\n`)
23
24
}
24
25
}
@@ -49,6 +50,27 @@ const normalizeRender = vm => {
49
50
}
50
51
}
51
52
53
+
function waitForSsrPrefetch (vm, resolve, reject) {
54
+
let handlers = vm.$options.ssrPrefetch
55
+
if (isDef(handlers)) {
56
+
if (!Array.isArray(handlers)) handlers = [handlers]
57
+
try {
58
+
const promises = []
59
+
for (let i = 0, j = handlers.length; i < j; i++) {
60
+
const result = handlers[i].call(vm, vm)
61
+
if (result && typeof result.then === 'function') {
62
+
promises.push(result)
63
+
}
64
+
}
65
+
Promise.all(promises).then(resolve).catch(reject)
66
+
return
67
+
} catch (e) {
68
+
reject(e)
69
+
}
70
+
}
71
+
resolve()
72
+
}
73
+
52
74
function renderNode (node, isRoot, context) {
53
75
if (node.isString) {
54
76
renderStringNode(node, context)
@@ -166,13 +188,20 @@ function renderComponentInner (node, isRoot, context) {
166
188
context.activeInstance
167
189
)
168
190
normalizeRender(child)
169
-
const childNode = child._render()
170
-
childNode.parent = node
171
-
context.renderStates.push({
172
-
type: 'Component',
173
-
prevActive
174
-
})
175
-
renderNode(childNode, isRoot, context)
191
+
192
+
const resolve = () => {
193
+
const childNode = child._render()
194
+
childNode.parent = node
195
+
context.renderStates.push({
196
+
type: 'Component',
197
+
prevActive
198
+
})
199
+
renderNode(childNode, isRoot, context)
200
+
}
201
+
202
+
const reject = context.done
203
+
204
+
waitForSsrPrefetch(child, resolve, reject)
176
205
}
177
206
178
207
function renderAsyncComponent (node, isRoot, context) {
@@ -394,6 +423,10 @@ export function createRenderFunction (
394
423
})
395
424
installSSRHelpers(component)
396
425
normalizeRender(component)
397
-
renderNode(component._render(), true, context)
426
+
427
+
const resolve = () => {
428
+
renderNode(component._render(), true, context)
429
+
}
430
+
waitForSsrPrefetch(component, resolve, done)
398
431
}
399
432
}
Original file line number Diff line number Diff line change
@@ -17,5 +17,6 @@ export const LIFECYCLE_HOOKS = [
17
17
'destroyed',
18
18
'activated',
19
19
'deactivated',
20
-
'errorCaptured'
20
+
'errorCaptured',
21
+
'ssrPrefetch'
21
22
]
Original file line number Diff line number Diff line change
@@ -102,4 +102,26 @@ describe('SSR: renderToStream', () => {
102
102
stream1.read(1)
103
103
stream2.read(1)
104
104
})
105
+
106
+
it('should call context.rendered', done => {
107
+
let a = 0
108
+
const stream = renderToStream(new Vue({
109
+
template: `
110
+
<div>Hello</div>
111
+
`
112
+
}), {
113
+
rendered: () => {
114
+
a = 42
115
+
}
116
+
})
117
+
let res = ''
118
+
stream.on('data', chunk => {
119
+
res += chunk
120
+
})
121
+
stream.on('end', () => {
122
+
expect(res).toContain('<div data-server-rendered="true">Hello</div>')
123
+
expect(a).toBe(42)
124
+
done()
125
+
})
126
+
})
105
127
})
Original file line number Diff line number Diff line change
@@ -1311,6 +1311,194 @@ describe('SSR: renderToString', () => {
1311
1311
done()
1312
1312
})
1313
1313
})
1314
+
1315
+
it('should support ssrPrefetch option', done => {
1316
+
renderVmWithOptions({
1317
+
template: `
1318
+
<div>{{ count }}</div>
1319
+
`,
1320
+
data: {
1321
+
count: 0
1322
+
},
1323
+
ssrPrefetch () {
1324
+
return new Promise((resolve) => {
1325
+
setTimeout(() => {
1326
+
this.count = 42
1327
+
resolve()
1328
+
}, 1)
1329
+
})
1330
+
}
1331
+
}, result => {
1332
+
expect(result).toContain('<div data-server-rendered="true">42</div>')
1333
+
done()
1334
+
})
1335
+
})
1336
+
1337
+
it('should support ssrPrefetch option (nested)', done => {
1338
+
renderVmWithOptions({
1339
+
template: `
1340
+
<div>
1341
+
<span>{{ count }}</span>
1342
+
<nested-prefetch></nested-prefetch>
1343
+
</div>
1344
+
`,
1345
+
data: {
1346
+
count: 0
1347
+
},
1348
+
ssrPrefetch () {
1349
+
return new Promise((resolve) => {
1350
+
setTimeout(() => {
1351
+
this.count = 42
1352
+
resolve()
1353
+
}, 1)
1354
+
})
1355
+
},
1356
+
components: {
1357
+
nestedPrefetch: {
1358
+
template: `
1359
+
<div>{{ message }}</div>
1360
+
`,
1361
+
data () {
1362
+
return {
1363
+
message: ''
1364
+
}
1365
+
},
1366
+
ssrPrefetch () {
1367
+
return new Promise((resolve) => {
1368
+
setTimeout(() => {
1369
+
this.message = 'vue.js'
1370
+
resolve()
1371
+
}, 1)
1372
+
})
1373
+
}
1374
+
}
1375
+
}
1376
+
}, result => {
1377
+
expect(result).toContain('<div data-server-rendered="true"><span>42</span> <div>vue.js</div></div>')
1378
+
done()
1379
+
})
1380
+
})
1381
+
1382
+
it('should support ssrPrefetch option (nested async)', done => {
1383
+
renderVmWithOptions({
1384
+
template: `
1385
+
<div>
1386
+
<span>{{ count }}</span>
1387
+
<nested-prefetch></nested-prefetch>
1388
+
</div>
1389
+
`,
1390
+
data: {
1391
+
count: 0
1392
+
},
1393
+
ssrPrefetch () {
1394
+
return new Promise((resolve) => {
1395
+
setTimeout(() => {
1396
+
this.count = 42
1397
+
resolve()
1398
+
}, 1)
1399
+
})
1400
+
},
1401
+
components: {
1402
+
nestedPrefetch (resolve) {
1403
+
resolve({
1404
+
template: `
1405
+
<div>{{ message }}</div>
1406
+
`,
1407
+
data () {
1408
+
return {
1409
+
message: ''
1410
+
}
1411
+
},
1412
+
ssrPrefetch () {
1413
+
return new Promise((resolve) => {
1414
+
setTimeout(() => {
1415
+
this.message = 'vue.js'
1416
+
resolve()
1417
+
}, 1)
1418
+
})
1419
+
}
1420
+
})
1421
+
}
1422
+
}
1423
+
}, result => {
1424
+
expect(result).toContain('<div data-server-rendered="true"><span>42</span> <div>vue.js</div></div>')
1425
+
done()
1426
+
})
1427
+
})
1428
+
1429
+
it('should merge ssrPrefetch option', done => {
1430
+
const mixin = {
1431
+
data: {
1432
+
message: ''
1433
+
},
1434
+
ssrPrefetch () {
1435
+
return new Promise((resolve) => {
1436
+
setTimeout(() => {
1437
+
this.message = 'vue.js'
1438
+
resolve()
1439
+
}, 1)
1440
+
})
1441
+
}
1442
+
}
1443
+
renderVmWithOptions({
1444
+
mixins: [mixin],
1445
+
template: `
1446
+
<div>
1447
+
<span>{{ count }}</span>
1448
+
<div>{{ message }}</div>
1449
+
</div>
1450
+
`,
1451
+
data: {
1452
+
count: 0
1453
+
},
1454
+
ssrPrefetch () {
1455
+
return new Promise((resolve) => {
1456
+
setTimeout(() => {
1457
+
this.count = 42
1458
+
resolve()
1459
+
}, 1)
1460
+
})
1461
+
}
1462
+
}, result => {
1463
+
expect(result).toContain('<div data-server-rendered="true"><span>42</span> <div>vue.js</div></div>')
1464
+
done()
1465
+
})
1466
+
})
1467
+
1468
+
it(`should skip ssrPrefetch option that doesn't return a promise`, done => {
1469
+
renderVmWithOptions({
1470
+
template: `
1471
+
<div>{{ count }}</div>
1472
+
`,
1473
+
data: {
1474
+
count: 0
1475
+
},
1476
+
ssrPrefetch () {
1477
+
setTimeout(() => {
1478
+
this.count = 42
1479
+
}, 1)
1480
+
}
1481
+
}, result => {
1482
+
expect(result).toContain('<div data-server-rendered="true">0</div>')
1483
+
done()
1484
+
})
1485
+
})
1486
+
1487
+
it('should call context.rendered', done => {
1488
+
let a = 0
1489
+
renderToString(new Vue({
1490
+
template: '<div>Hello</div>'
1491
+
}), {
1492
+
rendered: () => {
1493
+
a = 42
1494
+
}
1495
+
}, (err, res) => {
1496
+
expect(err).toBeNull()
1497
+
expect(res).toContain('<div data-server-rendered="true">Hello</div>')
1498
+
expect(a).toBe(42)
1499
+
done()
1500
+
})
1501
+
})
1314
1502
})
1315
1503
1316
1504
function renderVmWithOptions (options, cb) {
You can’t perform that action at this time.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4