Skip to content

Commit fc71e1f

Browse files
authored
feat: enable onload callbacks (#414)
* refactor(examples): run ssr example from server * chore: switch to babel for build buble complains too much * feat: enable loaded callbacks feat: add skip option * examples: add async-callback browser example * examples: fix server * examples(ssr): add reactive script with callback * fix: also skip on ssr * chore: remove unused var * feat: only add mutationobserver if DOM is still loading feat: disconnect mutation observer once DOM has loaded * examples: pass vmid to loadCallback instead of el * feat: also support load callbacks for link/style tags * test: add unit tests for load * test: add load e2e test * chore: fix lint * chore: remove unused files * test: fix e2e load callback test * test: fix attempt * examples: ie9 compatiblity destructuring doesnt work in ie9 * fix: add onload attribute on ssr dont rely on mutationobserver * chore: lint ci conf * refactor: remove loadCallbackAttribute config option test: fix coverage for load * test: improve coverage * fix: only use console when it exists (for ie9) * chore: fix coverage
1 parent 05163a7 commit fc71e1f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+957
-626
lines changed

.circleci/config.yml

-2
Original file line numberDiff line numberDiff line change
@@ -134,5 +134,3 @@ workflows:
134134
requires: [test-e2e-ssr]
135135
filters:
136136
branches: { ignore: /^pull\/.*/ }
137-
138-
File renamed without changes.

examples/index.html renamed to examples/_static/index.html

+2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ <h1>Vue Meta Examples</h1>
1111
<li><a href="basic-render">Basic Render</a></li>
1212
<li><a href="keep-alive">Keep alive</a></li>
1313
<li><a href="multiple-apps">Usage with multiple apps</a></li>
14+
<li><a href="ssr">SSR</a></li>
1415
<li><a href="vue-router">Usage with vue-router</a></li>
1516
<li><a href="vuex">Usage with vuex</a></li>
1617
<li><a href="vuex-async">Usage with vuex + async actions</a></li>
18+
<li><a href="async-callback">Async Callback</a></li>
1719
</ul>
1820
</body>
1921
</html>

examples/_static/user-1.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
window.users.push({
2+
'id': 1,
3+
'name': 'Leanne Graham',
4+
'username': 'Bret',
5+
'email': '[email protected]',
6+
'address': {
7+
'street': 'Kulas Light',
8+
'suite': 'Apt. 556',
9+
'city': 'Gwenborough',
10+
'zipcode': '92998-3874',
11+
'geo': {
12+
'lat': '-37.3159',
13+
'lng': '81.1496'
14+
}
15+
},
16+
'phone': '1-770-736-8031 x56442',
17+
'website': 'hildegard.org',
18+
'company': {
19+
'name': 'Romaguera-Crona',
20+
'catchPhrase': 'Multi-layered client-server neural-net',
21+
'bs': 'harness real-time e-markets'
22+
}
23+
})

examples/_static/user-2.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
window.users.push({
2+
'id': 2,
3+
'name': 'Ervin Howell',
4+
'username': 'Antonette',
5+
'email': '[email protected]',
6+
'address': {
7+
'street': 'Victor Plains',
8+
'suite': 'Suite 879',
9+
'city': 'Wisokyburgh',
10+
'zipcode': '90566-7771',
11+
'geo': {
12+
'lat': '-43.9509',
13+
'lng': '-34.4618'
14+
}
15+
},
16+
'phone': '010-692-6593 x09125',
17+
'website': 'anastasia.net',
18+
'company': {
19+
'name': 'Deckow-Crist',
20+
'catchPhrase': 'Proactive didactic contingency',
21+
'bs': 'synergize scalable supply-chains'
22+
}
23+
})

examples/_static/user-3.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
window.users.push({
2+
'id': 3,
3+
'name': 'Clementine Bauch',
4+
'username': 'Samantha',
5+
'email': '[email protected]',
6+
'address': {
7+
'street': 'Douglas Extension',
8+
'suite': 'Suite 847',
9+
'city': 'McKenziehaven',
10+
'zipcode': '59590-4157',
11+
'geo': {
12+
'lat': '-68.6102',
13+
'lng': '-47.0653'
14+
}
15+
},
16+
'phone': '1-463-123-4447',
17+
'website': 'ramiro.info',
18+
'company': {
19+
'name': 'Romaguera-Jacobson',
20+
'catchPhrase': 'Face to face bifurcated interface',
21+
'bs': 'e-enable strategic applications'
22+
}
23+
})

examples/_static/user-4.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
window.users.push({
2+
'id': 4,
3+
'name': 'Patricia Lebsack',
4+
'username': 'Karianne',
5+
'email': '[email protected]',
6+
'address': {
7+
'street': 'Hoeger Mall',
8+
'suite': 'Apt. 692',
9+
'city': 'South Elvis',
10+
'zipcode': '53919-4257',
11+
'geo': {
12+
'lat': '29.4572',
13+
'lng': '-164.2990'
14+
}
15+
},
16+
'phone': '493-170-9623 x156',
17+
'website': 'kale.biz',
18+
'company': {
19+
'name': 'Robel-Corkery',
20+
'catchPhrase': 'Multi-tiered zero tolerance productivity',
21+
'bs': 'transition cutting-edge web services'
22+
}
23+
})

examples/async-callback/app.js

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import Vue from 'vue'
2+
import VueMeta from 'vue-meta'
3+
4+
Vue.use(VueMeta)
5+
6+
window.users = []
7+
8+
new Vue({
9+
metaInfo () {
10+
return {
11+
title: 'Async Callback',
12+
titleTemplate: '%s | Vue Meta Examples',
13+
script: [
14+
{
15+
skip: this.count < 2,
16+
vmid: 'potatoes',
17+
src: '/user-3.js',
18+
async: true,
19+
callback: this.updateCounter
20+
},
21+
{
22+
skip: this.count < 1,
23+
vmid: 'vegetables',
24+
src: '/user-2.js',
25+
async: true,
26+
callback: this.updateCounter
27+
},
28+
{
29+
vmid: 'meat',
30+
src: '/user-1.js',
31+
async: true,
32+
callback: el => this.loadCallback(el.getAttribute('data-vmid'))
33+
},
34+
...this.scripts
35+
]
36+
}
37+
},
38+
data () {
39+
return {
40+
count: 0,
41+
scripts: [],
42+
users: window.users
43+
}
44+
},
45+
watch: {
46+
count (val) {
47+
if (val === 3) {
48+
this.addScript()
49+
}
50+
}
51+
},
52+
methods: {
53+
updateCounter () {
54+
this.count++
55+
},
56+
addScript () {
57+
this.scripts.push({
58+
src: '/user-4.js',
59+
callback: () => {
60+
this.updateCounter()
61+
}
62+
})
63+
},
64+
loadCallback (vmid) {
65+
if (vmid === 'meat') {
66+
this.updateCounter()
67+
}
68+
}
69+
},
70+
template: `
71+
<div id="app">
72+
<h1>Async Callback</h1>
73+
<p>{{ count }} scripts loaded</p>
74+
75+
<div>
76+
<h2>Users</h2>
77+
<ul>
78+
<li
79+
v-for="user in users"
80+
:key="user.id"
81+
>
82+
<strong>{{ user.id }}</strong>: {{ user.name }}
83+
</li>
84+
</ul>
85+
</div>
86+
</div>
87+
`
88+
}).$mount('#app')

examples/async-callback/index.html

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Async Callback Title</title>
5+
<link rel="stylesheet" href="/global.css">
6+
</head>
7+
<body>
8+
<a href="/">&larr; Examples index</a>
9+
<div id="app"></div>
10+
11+
<script src="/__build__/async-callback.js"></script>
12+
</body>
13+
</html>

examples/basic-render/app.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ Vue.component('child', {
1111
default: ''
1212
}
1313
},
14-
render(h) {
14+
render (h) {
1515
return h('h3', null, this.page)
1616
},
17-
metaInfo() {
17+
metaInfo () {
1818
return {
1919
title: this.page
2020
}

examples/keep-alive/app.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ Vue.component('foo', {
1111
})
1212

1313
new Vue({
14-
data() {
14+
data () {
1515
return { showFoo: false }
1616
},
1717
methods: {
18-
show() {
18+
show () {
1919
this.showFoo = !this.showFoo
2020
}
2121
},

examples/multiple-apps/app.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,23 @@ Vue.use(VueMeta)
66
// index.html contains a manual SSR render
77

88
const app1 = new Vue({
9-
metaInfo() {
9+
metaInfo () {
1010
return {
1111
title: 'App 1 title',
1212
bodyAttrs: {
1313
class: 'app-1'
1414
},
1515
meta: [
1616
{ name: 'description', content: 'Hello from app 1', vmid: 'test' },
17-
{ name: 'og:description', content: this.ogContent }
17+
{ name: 'og:description', content: this.ogContent }
1818
],
1919
script: [
2020
{ innerHTML: 'var appId=1.1', body: true },
21-
{ innerHTML: 'var appId=1.2', vmid: 'app-id-body' },
21+
{ innerHTML: 'var appId=1.2', vmid: 'app-id-body' }
2222
]
2323
}
2424
},
25-
data() {
25+
data () {
2626
return {
2727
ogContent: 'Hello from ssr app'
2828
}
@@ -44,7 +44,7 @@ const app2 = new Vue({
4444
],
4545
script: [
4646
{ innerHTML: 'var appId=2.1', body: true },
47-
{ innerHTML: 'var appId=2.2', vmid: 'app-id-body', body: true },
47+
{ innerHTML: 'var appId=2.2', vmid: 'app-id-body', body: true }
4848
]
4949
}),
5050
template: `
@@ -60,7 +60,6 @@ const app3 = new Vue({
6060
`
6161
}).$mount('#app3')
6262

63-
6463
setTimeout(() => {
6564
console.log('trigger app 1')
6665
app1.$data.ogContent = 'Hello from app 1'
@@ -75,8 +74,9 @@ setTimeout(() => {
7574
console.log('trigger app 3')
7675
app3.$meta().refresh()
7776
}, 7500)
77+
7878
setTimeout(() => {
7979
console.log('trigger app 4')
8080
const App = Vue.extend({ template: `<div>app 4</div>` })
81-
const app4 = new App().$mount()
81+
new App().$mount()
8282
}, 10000)

examples/server.js

+18-1
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import rewrite from 'express-urlrewrite'
66
import webpack from 'webpack'
77
import webpackDevMiddleware from 'webpack-dev-middleware'
88
import WebpackConfig from './webpack.config'
9+
import { renderPage } from './ssr/server'
910

1011
const app = express()
1112

1213
app.use(webpackDevMiddleware(webpack(WebpackConfig), {
1314
publicPath: '/__build__/',
15+
writeToDisk: false,
1416
stats: {
1517
colors: true,
1618
chunks: false
@@ -21,12 +23,27 @@ fs.readdirSync(__dirname)
2123
.filter(file => file !== 'ssr')
2224
.forEach((file) => {
2325
if (fs.statSync(path.join(__dirname, file)).isDirectory()) {
24-
app.use(rewrite('/' + file + '/*', '/' + file + '/index.html'))
26+
app.use(rewrite(`/${file}/*`, `/${file}/index.html`))
2527
}
2628
})
2729

30+
app.use(express.static(path.join(__dirname, '_static')))
2831
app.use(express.static(__dirname))
2932

33+
app.use(async (req, res, next) => {
34+
if (!req.url.startsWith('/ssr')) {
35+
next()
36+
}
37+
38+
try {
39+
const html = await renderPage()
40+
res.send(html)
41+
} catch (e) {
42+
consola.error('SSR Oops:', e)
43+
next()
44+
}
45+
})
46+
3047
const host = process.env.HOST || 'localhost'
3148
const port = process.env.PORT || 3000
3249

0 commit comments

Comments
 (0)