Skip to content
This repository was archived by the owner on May 27, 2019. It is now read-only.

Commit bc74a7e

Browse files
authored
Merge pull request #1 from algolia/feat/ssr-example
Feat/ssr example
2 parents 8833b81 + 21baddc commit bc74a7e

17 files changed

+4493
-0
lines changed

examples/ssr/.babelrc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"presets": [
3+
["env", { "modules": false }]
4+
]
5+
}

examples/ssr/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.DS_Store
2+
node_modules/
3+
dist/
4+
npm-debug.log
5+
yarn-error.log

examples/ssr/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# example-ssr
2+
3+
> An illustration of server side rendering with Algolia Vue InstantSearch.
4+
5+
## Build Setup
6+
7+
``` bash
8+
# install dependencies
9+
npm install
10+
11+
# serve with hot reload at localhost:8080
12+
npm run dev
13+
14+
# build for production with minification
15+
npm run build
16+
```
17+
18+
For detailed explanation on how things work, consult the [docs for vue-loader](http://vuejs.github.io/vue-loader).
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
const path = require('path');
2+
const webpack = require('webpack');
3+
4+
module.exports = {
5+
devtool: '#cheap-module-source-map',
6+
output: {
7+
path: path.resolve(__dirname, '../dist'),
8+
publicPath: '/dist/',
9+
filename: '[name].js',
10+
},
11+
module: {
12+
rules: [
13+
{
14+
test: /\.vue$/,
15+
loader: 'vue-loader',
16+
},
17+
{
18+
test: /\.js$/,
19+
loader: 'babel-loader',
20+
exclude: /node_modules/,
21+
},
22+
{
23+
test: /\.(png|jpg|gif|svg)$/,
24+
loader: 'url-loader',
25+
options: {
26+
limit: 10000,
27+
name: '[name].[ext]?[hash]',
28+
},
29+
},
30+
{
31+
test: /\.css$/,
32+
use: ['vue-style-loader', 'css-loader'],
33+
},
34+
],
35+
},
36+
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const webpack = require('webpack')
2+
const merge = require('webpack-merge')
3+
const baseConfig = require('./webpack.base.config.js')
4+
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin')
5+
6+
module.exports = merge(baseConfig, {
7+
entry: './src/main.client.js',
8+
plugins: [
9+
// Important: this splits the webpack runtime into a leading chunk
10+
// so that async chunks can be injected right after it.
11+
// this also enables better caching for your app/vendor code.
12+
new webpack.optimize.CommonsChunkPlugin({
13+
name: "manifest",
14+
minChunks: Infinity
15+
}),
16+
// This plugins generates `vue-ssr-client-manifest.json` in the
17+
// output directory.
18+
new VueSSRClientPlugin()
19+
]
20+
})
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
const merge = require('webpack-merge')
2+
const nodeExternals = require('webpack-node-externals')
3+
const baseConfig = require('./webpack.base.config.js')
4+
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
5+
6+
module.exports = merge(baseConfig, {
7+
// Point entry to your app's server entry file
8+
entry: './src/main.server.js',
9+
10+
// This allows webpack to handle dynamic imports in a Node-appropriate
11+
// fashion, and also tells `vue-loader` to emit server-oriented code when
12+
// compiling Vue components.
13+
target: 'node',
14+
15+
// For bundle renderer source map support
16+
devtool: 'source-map',
17+
18+
// This tells the server bundle to use Node-style exports
19+
output: {
20+
libraryTarget: 'commonjs2'
21+
},
22+
23+
// https://webpack.js.org/configuration/externals/#function
24+
// https://github.com/liady/webpack-node-externals
25+
// Externalize app dependencies. This makes the server build much faster
26+
// and generates a smaller bundle file.
27+
externals: nodeExternals({
28+
// do not externalize dependencies that need to be processed by webpack.
29+
// you can add more file types here e.g. raw *.vue files
30+
// you should also whitelist deps that modifies `global` (e.g. polyfills)
31+
whitelist: /\.css$/
32+
}),
33+
34+
// This is the plugin that turns the entire output of the server build
35+
// into a single JSON file. The default file name will be
36+
// `vue-ssr-server-bundle.json`
37+
plugins: [
38+
new VueSSRServerPlugin()
39+
]
40+
})

examples/ssr/package.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "example-ssr",
3+
"description": "An illustration of server side rendering with Algolia Vue InstantSearch.",
4+
"version": "1.0.0",
5+
"author": "Raymond Rutjes <raymond.rutjes@gmail.com>",
6+
"private": true,
7+
"scripts": {
8+
"build": "yarn run build:server && yarn run build:client",
9+
"build:client": "cross-env NODE_ENV=production webpack --config build/webpack.client.config.js --progress --hide-modules",
10+
"build:server": "cross-env NODE_ENV=production webpack --config build/webpack.server.config.js --progress --hide-modules"
11+
},
12+
"dependencies": {
13+
"express": "^4.15.3",
14+
"vue": "^2.3.3",
15+
"vue-instantsearch": "^0.0.0",
16+
"vue-router": "^2.5.3",
17+
"vue-server-renderer": "^2.3.3"
18+
},
19+
"devDependencies": {
20+
"babel-core": "^6.0.0",
21+
"babel-loader": "^6.0.0",
22+
"babel-preset-env": "^1.5.1",
23+
"cross-env": "^3.0.0",
24+
"css-loader": "^0.25.0",
25+
"file-loader": "^0.9.0",
26+
"node-sass": "^4.5.0",
27+
"sass-loader": "^5.0.1",
28+
"url-loader": "^0.5.8",
29+
"vue-loader": "^12.1.0",
30+
"vue-ssr-webpack-plugin": "^3.0.0",
31+
"vue-template-compiler": "^2.3.3",
32+
"webpack": "^2.6.1",
33+
"webpack-dev-server": "^2.4.5",
34+
"webpack-merge": "^4.1.0",
35+
"webpack-node-externals": "^1.6.0"
36+
}
37+
}

examples/ssr/server.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const express = require('express');
2+
const server = express();
3+
4+
const template = require('fs').readFileSync(
5+
'./src/index.template.html',
6+
'utf-8'
7+
);
8+
const serverBundle = require('./dist/vue-ssr-server-bundle.json');
9+
const clientManifest = require('./dist/vue-ssr-client-manifest.json');
10+
11+
const { createBundleRenderer } = require('vue-server-renderer');
12+
13+
const renderer = createBundleRenderer(serverBundle, {
14+
runInNewContext: false, // recommended
15+
template, // (optional) page template
16+
clientManifest, // (optional) client build manifest
17+
});
18+
19+
// Serve static assets from ./dist on the /dist route.
20+
server.use('/dist', express.static('dist'));
21+
22+
// inside a server handler...
23+
server.get('*', (req, res) => {
24+
const context = { url: req.url };
25+
// No need to pass an app here because it is auto-created by the
26+
// executing the bundle. Now our server is decoupled from our Vue app!
27+
renderer.renderToString(context, (err, html) => {
28+
if (err !== null) {
29+
if (err.code === 404) {
30+
res.status(404).end('Page not found');
31+
} else {
32+
res.status(500).end('Internal Server Error');
33+
}
34+
console.log(err);
35+
} else {
36+
res.end(html);
37+
}
38+
});
39+
});
40+
41+
server.listen('8080');

examples/ssr/src/App.vue

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<template>
2+
<div id="app">
3+
<router-view></router-view>
4+
</div>
5+
</template>
6+
7+
<script>
8+
export default {
9+
name: 'app',
10+
};
11+
</script>
12+
13+
<style lang="scss">
14+
#app {
15+
font-family: 'Avenir', Helvetica, Arial, sans-serif;
16+
-webkit-font-smoothing: antialiased;
17+
-moz-osx-font-smoothing: grayscale;
18+
text-align: center;
19+
color: #2c3e50;
20+
margin-top: 60px;
21+
}
22+
23+
h1, h2 {
24+
font-weight: normal;
25+
}
26+
27+
ul {
28+
list-style-type: none;
29+
padding: 0;
30+
}
31+
32+
li {
33+
display: inline-block;
34+
margin: 0 10px;
35+
}
36+
37+
a {
38+
color: #42b983;
39+
}
40+
</style>

examples/ssr/src/Search.vue

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<template>
2+
<ais-index :searchStore="searchStore">
3+
<ais-search-box placeholder="Find products"/>
4+
<ul>
5+
<ais-results>
6+
<template scope="{ result }">
7+
<li>
8+
{{ result.name }}
9+
</li>
10+
</template>
11+
</ais-results>
12+
</ul>
13+
</ais-index>
14+
</template>
15+
<script>
16+
import {
17+
createFromAlgoliaCredentials,
18+
createFromSerialized,
19+
} from 'vue-instantsearch';
20+
21+
let store;
22+
23+
export default {
24+
name: 'search',
25+
asyncData({ context, route }) {
26+
store = createFromAlgoliaCredentials(
27+
'latency',
28+
'6be0576ff61c053d5f9a3225e2a90f76'
29+
);
30+
31+
store.indexName = 'ikea';
32+
store.query = route.params.query ? route.params.query : '';
33+
store.start();
34+
35+
return store.waitUntilInSync().then(() => {
36+
context.state = {
37+
searchStore: store.serialize(),
38+
};
39+
});
40+
},
41+
beforeMount() {
42+
if (!window.__INITIAL_STATE__) {
43+
throw new Error('Not state was found.');
44+
}
45+
46+
this.searchStore = createFromSerialized(
47+
window.__INITIAL_STATE__.searchStore
48+
);
49+
},
50+
watch: {
51+
$route(to, from) {
52+
this.searchStore.query = this.$route.params.query ? this.$route.params.query : '';
53+
},
54+
'searchStore.query'(to, from) {
55+
if (to.length === 0) {
56+
this.$router.push({ name: 'home' });
57+
} else {
58+
this.$router.push({ name: 'search', params: { query: to } });
59+
}
60+
},
61+
},
62+
mounted() {
63+
// this.searchStore.start();
64+
},
65+
data() {
66+
return {
67+
searchStore: store,
68+
};
69+
},
70+
};
71+
</script>

0 commit comments

Comments
 (0)