Skip to content

Commit dd72231

Browse files
committed
Initial public release
1 parent cc3fcb3 commit dd72231

File tree

7 files changed

+407
-145
lines changed

7 files changed

+407
-145
lines changed

packages/vue-ssr/README.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,115 @@
11
# Vue+Meteor SSR
22

3+
> Add Server-Side Rendering in your Vue+Meteor application
4+
5+
## Installation:
6+
7+
```
8+
meteor add akryum:vue-ssr
9+
```
10+
11+
## Usage
12+
13+
**:warning: All your client-side code should be available on the server (which means they shouldn't be in a `client` folder), and the code and libraries should be able to run on the server.**
14+
15+
*:warning: vuex & apollo are not tested yet.*
16+
17+
Wrap your Vue root instance in a `createApp` function and export it, alongside with the router instance:
18+
19+
```javascript
20+
import Vue from 'vue'
21+
22+
// Meteor Tracker integration
23+
import VueMeteorTracker from 'vue-meteor-tracker'
24+
Vue.use(VueMeteorTracker)
25+
26+
import App from './ui/App.vue'
27+
import router from './router'
28+
29+
function createApp () {
30+
return {
31+
app: new Vue({
32+
el: '#app',
33+
router,
34+
...App,
35+
}),
36+
router,
37+
}
38+
}
39+
40+
export default createApp
41+
```
42+
43+
In your client code, start the app as usual:
44+
45+
```javascript
46+
import { Meteor } from 'meteor/meteor'
47+
import CreateApp from './app'
48+
49+
Meteor.startup(() => {
50+
CreateApp()
51+
})
52+
```
53+
54+
In your server code, you need to set the `VueSSR.createApp` method with a function that returns the Vue instance:
55+
56+
```javascript
57+
import { VueSSR } from 'meteor/akryum:vue-ssr'
58+
import CreateApp from './app'
59+
60+
VueSSR.createApp = function ({ url }) {
61+
const { app, router } = CreateApp()
62+
// Set the url in the router
63+
router.push(url)
64+
return app
65+
}
66+
```
67+
68+
Returning a promise works too:
69+
70+
```javascript
71+
VueSSR.createApp = function ({ url }) {
72+
return new Promise((resolve, reject) => {
73+
const { app, router } = CreateApp()
74+
// Set the URL in the router
75+
router.push(url)
76+
77+
router.onReady(() => {
78+
const matchedComponents = router.getMatchedComponents()
79+
80+
// no matched routes
81+
if (!matchedComponents.length) {
82+
reject({ code: 404 })
83+
}
84+
85+
// Can use components prefetch here...
86+
87+
resolve(app)
88+
})
89+
})
90+
}
91+
```
92+
93+
Add the `<!--vue-ssr-outlet-->` comment in you HTML where you want to render the Vue app. If you don't, the app will be rendered at the beginning of the page body.
94+
95+
You can change the replacing snippet by setting the `VUE_OUTLET` environment variable, or by setting the `VueSSR.outlet` property:
96+
97+
```javascript
98+
VueSSR.outlet = '<!--my-app-here-->'
99+
```
100+
101+
You can also customize the template of the rendered HTML with the `VueSSR.template` property:
102+
103+
```javascript
104+
VueSSR.template = `
105+
<div class="app-wrapper">
106+
<!--vue-ssr-outlet-->
107+
</div>
108+
`
109+
```
110+
111+
*:warning: The CSS can flicker in developpement mode and load after the app is rendered. This is due to the HMR system having to append dynamic style tag in the page to get the fastest reloading possible. This is not the case in production mode (try running your app with `meteor --production`).*
112+
3113
---
4114

5115
LICENCE ISC - Created by Guillaume CHAU (@Akryum)

packages/vue-ssr/compile-html.js

Lines changed: 0 additions & 89 deletions
This file was deleted.

packages/vue-ssr/npm.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"dependencies": {
33
"vue": "2.2.4",
4-
"vue-router": "^2.3.0"
4+
"vue-router": "^2.3.0",
5+
"vue-meteor-tracker": "^1.2.0"
56
}
67
}

packages/vue-ssr/package.js

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
11
Package.describe({
22
name: 'akryum:vue-ssr',
3-
version: '0.0.1',
3+
version: '0.1.0',
44
summary: 'Render Vue server-side',
55
git: 'https://github.com/Akryum/meteor-vue-component',
66
documentation: 'README.md'
77
});
88

9-
10-
Package.registerBuildPlugin({
11-
name: "compileStaticHtmlBatch",
12-
use: [
13-
'ecmascript@0.6.3',
14-
'underscore@1.0.10',
15-
'caching-html-compiler@1.1.1',
16-
'templating-tools@1.1.1'
17-
],
18-
sources: [
19-
'compile-html.js'
20-
]
21-
});
22-
239
Package.onUse(function(api) {
2410
api.versionsFrom('1.4.3.1');
25-
api.use('akryum:npm-check@0.0.3');
26-
api.use('isobuild:compiler-plugin@1.0.0');
27-
api.use('ecmascript');
11+
api.use([
12+
'isobuild:compiler-plugin@1.0.0',
13+
'ecmascript',
14+
'tracker',
15+
'minimongo',
16+
'underscore',
17+
'webapp',
18+
'mongo',
19+
'routepolicy',
20+
'url',
21+
'akryum:npm-check@0.0.3',
22+
'staringatlights:fast-render@2.16.2',
23+
'staringatlights:inject-data@2.0.4',
24+
]);
2825
api.mainModule('server/index.js', 'server');
2926
api.export('VueSSR', 'server');
3027
});
3128

3229
Npm.depends({
3330
'vue-server-renderer': '2.2.4',
31+
'vue-ssr-html-stream': '2.2.0',
32+
'cookie-parser': '1.4.1',
33+
'cheerio': '0.20.0',
3434
})

packages/vue-ssr/server/context.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// server/ssr_context.js
2+
// stolen from https://github.com/kadirahq/flow-router/blob/ssr/server/ssr_context.js
3+
4+
export default class SsrContext {
5+
constructor() {
6+
this._collections = {};
7+
}
8+
9+
getCollection(collName) {
10+
let collection = this._collections[collName];
11+
if (!collection) {
12+
const minimongo = Package.minimongo;
13+
collection = this._collections[collName] = new minimongo.LocalCollection();
14+
}
15+
16+
return collection;
17+
}
18+
19+
addSubscription(name, params) {
20+
const fastRenderContext = FastRender.frContext.get();
21+
if (!fastRenderContext) {
22+
throw new Error(
23+
`Cannot add a subscription: ${name} without FastRender Context`
24+
);
25+
}
26+
27+
const data = fastRenderContext.subscribe(name, ...params);
28+
this.addData(data);
29+
}
30+
31+
addData(data) {
32+
_.each(data, (collDataCollection, collectionName) => {
33+
const collection = this.getCollection(collectionName);
34+
collDataCollection.forEach((collData) => {
35+
collData.forEach((item) => {
36+
const existingDoc = collection.findOne(item._id);
37+
if (existingDoc) {
38+
const newDoc = { ...existingDoc, ...item };
39+
delete newDoc._id;
40+
collection.update(item._id, { $set: newDoc });
41+
} else {
42+
collection.insert(item);
43+
}
44+
});
45+
});
46+
});
47+
}
48+
}

0 commit comments

Comments
 (0)