Skip to content

Commit 21b853d

Browse files
committed
Lazy loading on
1 parent 90411aa commit 21b853d

File tree

11 files changed

+72
-27
lines changed

11 files changed

+72
-27
lines changed

build/webpack.base.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module.exports = {
55
devtool: '#source-map',
66
entry: {
77
app: './src/client-entry.js',
8-
vendor: ['vue', 'vue-router', 'vuex', 'firebase', 'lru-cache', 'es6-promise']
8+
vendor: ['vue', 'vue-router', 'vuex', 'vuex-router-sync', 'firebase', 'es6-promise']
99
},
1010
output: {
1111
path: path.resolve(__dirname, '../dist'),

build/webpack.client.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ const config = Object.assign({}, base, {
66
plugins: (base.plugins || []).concat([
77
// strip comments in Vue code
88
new webpack.DefinePlugin({
9-
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
9+
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
10+
'process.BROWSER': true
1011
}),
1112
// extract vendor chunks for better caching
1213
new webpack.optimize.CommonsChunkPlugin({

build/webpack.server.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ module.exports = Object.assign({}, base, {
1313
plugins: [
1414
new webpack.DefinePlugin({
1515
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
16-
'process.env.VUE_ENV': '"server"'
16+
'process.env.VUE_ENV': '"server"',
17+
'process.BROWSER': false
1718
})
1819
]
1920
})

index.html

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@
66
<meta name="mobile-web-app-capable" content="yes">
77
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
88
<link href='https://fonts.googleapis.com/css?family=Roboto:300,400,700' rel='stylesheet' type='text/css'>
9-
{{ STYLE }}
9+
<script src="/dist/client-vendor-bundle.js"></script>
10+
<script src="/dist/client-bundle.js"></script>
1011
</head>
1112
<body>
1213
{{ APP }}
13-
<script src="/dist/client-vendor-bundle.js"></script>
14-
<script src="/dist/client-bundle.js"></script>
1514
</body>
1615
</html>

server.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@ const html = (() => {
1919
const template = fs.readFileSync(resolve('./index.html'), 'utf-8')
2020
const i = template.indexOf('{{ APP }}')
2121
// styles are injected dynamically via vue-style-loader in development
22-
const style = isProd ? '<link rel="stylesheet" href="/dist/styles.css">' : ''
2322
return {
24-
head: template.slice(0, i).replace('{{ STYLE }}', style),
23+
head: template.slice(0, i),
2524
tail: template.slice(i + '{{ APP }}'.length)
2625
}
2726
})()

src/app.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ Object.keys(filters).forEach(key => {
1717
// create the app instance.
1818
// here we inject the router and store to all child components,
1919
// making them available everywhere as `this.$router` and `this.$store`.
20-
const app = new Vue({
20+
const app = {
2121
router,
2222
store,
2323
...App // Object spread copying everything from App.vue
24-
})
24+
}
2525

2626
// expose the app, the router and the store.
2727
// note we are not mounting the app here, since bootstrapping will be

src/client-entry.js

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,51 @@
11
require('es6-promise').polyfill()
2-
import { app, store } from './app'
2+
import Vue from 'vue'
3+
import { app, store, router } from './app'
34

4-
// prime the store with server-initialized state.
5-
// the state is determined during SSR and inlined in the page markup.
6-
store.replaceState(window.__INITIAL_STATE__)
5+
// Get matched components by route and load them
6+
const path = getLocation(router.options.base)
7+
const resolveComponents = flatMapComponents(router.match(path), (Component, _, match, key, index) => {
8+
if (typeof Component === 'function' && !Component.options) {
9+
return new Promise(function (resolve, reject) {
10+
const _resolve = (Component) => {
11+
match.components[key] = Component
12+
resolve(Component)
13+
}
14+
var res = Component(_resolve, reject)
15+
if (res && res.then) {
16+
res.then(_resolve).catch(reject)
17+
}
18+
})
19+
}
20+
return Component
21+
})
722

8-
// actually mount to DOM
9-
app.$mount('#app')
23+
Promise.all(resolveComponents)
24+
.then((Components) => {
25+
const _app = new Vue(app)
26+
// prime the store with server-initialized state.
27+
// the state is determined during SSR and inlined in the page markup.
28+
store.replaceState(window.__INITIAL_STATE__)
29+
_app.$mount('#app')
30+
})
31+
.catch((err) => {
32+
console.error('Cannot load components', err)
33+
})
34+
35+
// Imported for vue-router
36+
export function flatMapComponents (route, fn) {
37+
return Array.prototype.concat.apply([], route.matched.map(function (m, index) {
38+
return Object.keys(m.components).map(function (key) {
39+
return fn(m.components[key], m.instances[key], m, key, index)
40+
})
41+
}))
42+
}
43+
44+
// Imported from vue-router
45+
export function getLocation (base) {
46+
var path = window.location.pathname
47+
if (base && path.indexOf(base) === 0) {
48+
path = path.slice(base.length)
49+
}
50+
return (path || '/') + window.location.search + window.location.hash
51+
}

src/router/index.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import Router from 'vue-router'
33

44
Vue.use(Router)
55

6-
import { createListView } from '../views/CreateListView'
7-
import ItemView from '../views/ItemView.vue'
8-
import UserView from '../views/UserView.vue'
6+
const createListView = process.BROWSER ? (type) => {
7+
return (resolve) => { System.import('../views/CreateListView').then((createListView) => resolve(createListView(type))) }
8+
} : require('../views/CreateListView')
9+
const ItemView = process.BROWSER ? () => System.import('../views/ItemView.vue') : require('../views/ItemView.vue')
10+
const UserView = process.BROWSER ? () => System.import('../views/UserView.vue') : require('../views/UserView.vue')
911

1012
export default new Router({
1113
mode: 'history',

src/server-entry.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import Vue from 'vue'
12
import { app, router, store } from './app'
23

4+
const _app = new Vue(app)
5+
36
const isDev = process.env.NODE_ENV !== 'production'
47

58
// This exported function will be called by `bundleRenderer`.
@@ -30,6 +33,6 @@ export default context => {
3033
// store to pick-up the server-side state without having to duplicate
3134
// the initial data fetching on the client.
3235
context.initialState = store.state
33-
return app
36+
return _app
3437
})
3538
}

src/store/api.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import Firebase from 'firebase'
2-
import LRU from 'lru-cache'
3-
4-
const inBrowser = typeof window !== 'undefined'
1+
const Firebase = require('firebase')
2+
const LRU = process.BROWSER ? null : require('lru-cache')
53

64
// When using bundleRenderer, the server-side application code runs in a new
75
// context for each request. To allow caching across multiple requests, we need
86
// to attach the cache to the process which is shared across all requests.
9-
const cache = inBrowser
7+
const cache = process.BROWSER
108
? null
119
: (process.__API_CACHE__ || (process.__API_CACHE__ = createCache()))
1210

@@ -18,7 +16,7 @@ function createCache () {
1816
}
1917

2018
// create a single api instance for all server-side requests
21-
const api = inBrowser
19+
const api = process.BROWSER
2220
? new Firebase('https://hacker-news.firebaseio.com/v0')
2321
: (process.__API__ || (process.__API__ = createServerSideAPI()))
2422

src/views/CreateListView.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import ItemList from '../components/ItemList.vue'
33
// This is a factory function for dynamically creating root-level list views,
44
// since they share most of the logic except for the type of items to display.
55
// They are essentially higher order components wrapping ItemList.vue.
6-
export function createListView (type) {
6+
module.exports = function (type) {
77
return {
88
name: `${type}-stories-view`,
99
// this will be called during SSR to pre-fetch data into the store!

0 commit comments

Comments
 (0)