Skip to content

Commit

Permalink
SSR!
Browse files Browse the repository at this point in the history
  • Loading branch information
bangbang93 committed Aug 25, 2017
1 parent c83d3a3 commit 510a537
Show file tree
Hide file tree
Showing 17 changed files with 334 additions and 100 deletions.
12 changes: 0 additions & 12 deletions .idea/haruhi.iml

This file was deleted.

2 changes: 1 addition & 1 deletion .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 40 additions & 19 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const history = require('connect-history-api-fallback');
const { createBundleRenderer } = require('vue-server-renderer')
const fs = require('fs')

const app = express();
app.set('trust proxy', 'loopback');
Expand Down Expand Up @@ -36,28 +38,47 @@ app.use('/', require('./route/index'));

require('express-simple-route')(path.join(__dirname, 'route'), app);

if (app.get('env') === 'development'){
app.use(history({
verbose: true
}));
} else {
app.use(history());
const template = fs.readFileSync(path.join(__dirname, './client/src/html/index.html'), 'utf-8')
function createRenderer (bundle, options) {
// https://github.com/vuejs/vue/blob/dev/packages/vue-server-renderer/README.md#why-use-bundlerenderer
return createBundleRenderer(bundle, Object.assign(options, {
template,
// for component caching
// cache: LRU({
// max: 1000,
// maxAge: 1000 * 60 * 15
// }),
// recommended for performance
runInNewContext: false
}))
}

if (app.get('env') === 'development'){
let webpack = require('webpack');
let webpackConfig = require('./client/webpack.conf');
let compiler = webpack(webpackConfig);
let devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: webpackConfig.output.publicPath,
stats: {
colors: true,
chunks: false
let renderer
if (app.get('env') === 'production') {
// In production: create server renderer using built server bundle.
// The server bundle is generated by vue-ssr-webpack-plugin.
const bundle = require('./dist/vue-ssr-server-bundle.json')
// The client manifests are optional, but it allows the renderer
// to automatically infer preload/prefetch links and directly add <script>
// tags for any async chunks used during render, avoiding waterfall requests.
const clientManifest = require('./dist/vue-ssr-client-manifest.json')
renderer = createRenderer(bundle, {
clientManifest
})
} else {
const promise = require('./setup-dev-server')(app, (bundle, options) => {
renderer = createRenderer(bundle, options)
renderer = require('./middleware/server-render')(renderer)
})
app.get('*', function (req, res) {
if (promise.isFulfilled) {
renderer(req, res)
} else {
promise.then(() => {
renderer(req, res)
})
}
});
let hotMiddleware = require('webpack-hot-middleware')(compiler);
app.use(devMiddleware);
app.use(hotMiddleware);
})
}

app.use(express.static(path.join(__dirname, 'public')));
Expand Down
10 changes: 10 additions & 0 deletions client/src/entries/entry-client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Created by bangbang93 on 2017/8/25.
*/
'use strict';
import {createApp} from './index'


const {app} = createApp()

app.$mount('app');
20 changes: 20 additions & 0 deletions client/src/entries/entry-server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Created by bangbang93 on 2017/8/25.
*/
'use strict';
import {createApp} from './index'

export default (context) => {
return new Promise((resolve, reject) => {
const {app, router} = createApp()
router.push(context.url)

router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
if (!matchedComponents.length) {
return reject({code: 404})
}
resolve(app)
}, reject)
})
}
42 changes: 12 additions & 30 deletions client/src/entries/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,21 @@ import Element from 'element-ui'
import 'element-ui/lib/theme-default/index.css'
import App from '../pages/index.vue'
import VueRouter from 'vue-router'
import VueFetch from 'vue-fetch'
// import VueFetch from 'vue-fetch'
import {createRouter} from '../router/index'

require('es6-promise').polyfill();

import FirstPage from '../pages/home/first.vue'
import SecondPage from '../pages/home/second.vue'
// require('es6-promise').polyfill();

Vue.use(Element);
Vue.use(VueRouter);
Vue.use(VueFetch);

const routes = [{
path: '/1',
component: FirstPage,
name: 'first',
alias: '/'
}, {
path: '/2',
component: SecondPage,
name: 'second'
},
{
path: '*',
redirect: '/profile'
}];
// Vue.use(VueFetch);

const router = new VueRouter({
routes,
mode: 'history',
base: '/',
});
const router = createRouter()

const app = new Vue({
router,
render: (h)=>h(App),
}).$mount('app');
export function createApp() {
const app = new Vue({
router,
render: (h)=>h(App),
})
return {app, router}
}
4 changes: 2 additions & 2 deletions client/src/html/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
<title>Register</title>
</head>
<body>
<app></app>
<app><!--vue-ssr-outlet--></app>
</body>
</html>
</html>
27 changes: 27 additions & 0 deletions client/src/router/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Created by bangbang93 on 2017/8/25.
*/
'use strict';
import VueRouter from 'vue-router'

export function createRouter () {
const routes = [{
path: '/1',
component: require('../pages/home/first.vue').default,
name: 'first',
alias: '/'
}, {
path: '/2',
component: require('../pages/home/second.vue').default,
name: 'second'
}, {
path: '*',
redirect: '/profile'
}]

return new VueRouter({
routes,
mode: 'history',
base: '/',
})
}
7 changes: 2 additions & 5 deletions client/webpack.js → client/webpack.base.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,12 @@ let config = (function(){
devtool: false,
},
dev: {
devtool: '#eval-source-map',
devtool: '#source-map',
},
};
return config[IS_PRODUCTION? 'build' : 'dev']
})();
module.exports = Object.assign(config, {
entry: {
index: path.resolve(__dirname, '../client/src/entries/index.js'),
},
output: {
path: path.resolve(__dirname, '../public'),
publicPath: '/',
Expand Down Expand Up @@ -55,7 +52,7 @@ module.exports = Object.assign(config, {
},
{
test: /\.css$/,
loader: 'style-loader!css-loader'
loader: 'vue-style-loader!css-loader'
},
{
test: /\.html$/,
Expand Down
18 changes: 13 additions & 5 deletions client/webpack.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,21 @@
*/
'use strict';

const config = require('./webpack');
const config = require('./webpack.base.config');
const webpack = require('webpack');
const merge = require('webpack-merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const path = require('path');
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin')

const IS_PRODUCTION = process.env.NODE_ENV === 'production'

const entry = {
index: path.resolve(__dirname, '../client/src/entries/entry-client.js'),
}


let plugins;
if (IS_PRODUCTION) {
Expand All @@ -35,7 +41,7 @@ if (IS_PRODUCTION) {
new webpack.optimize.CommonsChunkPlugin('vendor.js'),
new ExtractTextPlugin('style.css'),
]
let entries = Object.keys(config.entry)
let entries = Object.keys(entry)
entries.forEach((entry) => {
plugins.push(new HtmlWebpackPlugin({
filename: `${entry}.html`,
Expand All @@ -47,8 +53,8 @@ if (IS_PRODUCTION) {
} else {

// add hot-reload related code to entry chunks
Object.keys(config.entry).forEach(function (name) {
config.entry[name] = ['./client/dev-client'].concat(config.entry[name])
Object.keys(entry).forEach(function (name) {
entry[name] = ['./client/dev-client'].concat(entry[name])
})
plugins = [
new webpack.DefinePlugin({
Expand All @@ -57,8 +63,9 @@ if (IS_PRODUCTION) {
}
}),
new webpack.HotModuleReplacementPlugin(),
new VueSSRClientPlugin(),
]
let entries = Object.keys(config.entry)
let entries = Object.keys(entry)
entries.forEach((entry) => {
plugins.push(new HtmlWebpackPlugin({
filename: `${entry}.html`,
Expand All @@ -70,5 +77,6 @@ if (IS_PRODUCTION) {
}

module.exports = merge(config, {
entry,
plugins
});
19 changes: 19 additions & 0 deletions client/webpack.server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Created by bangbang93 on 2017/8/25.
*/
'use strict';
const merge = require('webpack-merge')
const baseConfig = require('./webpack.base.config')
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
const path = require('path')

module.exports = merge(baseConfig, {
entry: path.join(__dirname, './src/entries/entry-server.js'),
target: 'node',
output: {
libraryTarget: 'commonjs2',
},
plugins: [
new VueSSRServerPlugin(),
],
})
54 changes: 54 additions & 0 deletions middleware/server-render.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* Created by bangbang93 on 2017/8/25.
*/
'use strict';


module.exports = function (renderer) {
return function render (req, res) {
const s = Date.now()

res.setHeader("Content-Type", "text/html")

const handleError = err => {
if (err.url) {
res.redirect(err.url)
} else if(err.code === 404) {
res.status(404).end('404 | Page Not Found')
} else {
// Render Error Page or Redirect
res.status(500).end('500 | Internal Server Error')
console.error(`error during render : ${req.url}`)
console.error(err.stack)
}
}

// const cacheable = isCacheable(req)
// if (cacheable) {
// const hit = microCache.get(req.url)
// if (hit) {
// if (!isProd) {
// console.log(`cache hit!`)
// }
// return res.end(hit)
// }
// }

const context = {
title: 'Vue HN 2.0', // default title
url: req.url
}
renderer.renderToString(context, (err, html) => {
if (err) {
return handleError(err)
}
res.end(html)
// if (cacheable) {
// microCache.set(req.url, html)
// }
if (!req.app.get('env') !== 'production') {
console.log(`whole request: ${Date.now() - s}ms`)
}
})
}
}
Loading

0 comments on commit 510a537

Please sign in to comment.