The presentation slide for Vue.js meetup
http://abeja-innovation-meetup.connpass.com/event/38214/
That contains mainly about SSR (Server side rendering) + SPA with isomorphic fetch and client hydration
Application of Residue Theorem to evaluate real integrations.pptx
How to Build SPA with Vue Router 2.0
1. How to Build SPA with Vue
Router 2.0
2016/08/24
Takuya Tejima
2. Who?
• Takuya Tejima @tejitak
• Co-Founder & CTO at Indie Inc. (ex-IBM, ex-LINE)
• Server & Web Front-End & iOS Engineer
• Community
• Vue.js core team member
• Dev Morning community founder
• http://devmorning.connpass.com/
• Global Startup Creators co-founder
• https://www.facebook.com/globalstartupcreators/
3. What’s SPA
• SPA (Single Page Aplication)
• SPA is a web application or web site that fits on a single web page with the goal of providing a more fluid user
experience similar to a desktop application.
• Important things to introduce
• Does you app really need to be SPA, such as partial rendering?
• It may not be easy compare to typical standard server side implementation
• There are no best frameworks for all situations
• There are a lot of frameworks
• Backbone? Ember? Riot? Angular + ui-router? Angular 2? React + React-Router (+ Redux)? Vue.js + Vue-
Router (+ Vuex)?
• If you decide to build SPA on your next webapp project, Vue.js + Vue Router would be a good option
4. • Vue Router Features
• Dead simple for component mapping with routes
• Nested routes and sub components
• Support SSR (Server Side Rendering) and Virtual DOM
• Async load
• Flexible hooks
• History management, Scroll behavior, transition etc.
• Vue Router 2.0 (Currently Beta) is really powerful!! Especially on…
• Better performance for SPA by reactive components mechanism
• SSR & SPA with isomorphic fetch and client hydration
• It means the components will dynamically work in client side generated by server side
same modules. It’s available without server side template engine like EJS! And, it has
better SEO compared to ordinary SPA
What’s Vue Router?
5. Work with SSR
• What’s BundleRenderer?
• Generate components for each requests from code to prevent shared modules on node
• TIPS: To skip parsing entire app dependencies every requests, we can specify webpack externals
options
6. Cont. Work with SSR
import Vue from 'vue'
import App from './App.vue'
import store from './store'
import router from './router'
import { sync } from 'vuex-router-sync'
// sync the router with the vuex store.
// this registers `store.state.route`
sync(store, router)
const app = new Vue({
router,
store,
...App
})
export { app, router, store }
app.js
require('es6-promise').polyfill()
import { app, store } from './app'
store.replaceState(window.__INITIAL_STATE__)
app.$mount('#app')
client-entry.js
import { app, router, store } from './app'
const isDev = process.env.NODE_ENV !== 'production'
export default context => {
router.push(context.url)
const s = isDev && Date.now()
return
Promise.all(router.getMatchedComponents().map(component => {
if (component.preFetch) {
return component.preFetch(store)
}
})).then(() => {
context.initialState = store.state
return app
})
}
server-entry.js
7. Client Side Hydration
• Client side Vue instance will attempt to "hydrate" the existing DOM instead of creating
new DOM nodes when the server-rendered="true" attribute exists
• Demo: Vue hackernews 2.0
• https://github.com/vuejs/vue-hackernews-2.0
• SSR + SPA (Client side hydration) can be achieved by Vue 2.0 & Vue Router
2.0 & Vuex 2.0!
• Vue: SSR
• Vue Router: Routing mapping management
• Vuex: State management & Isomorphic data fetch
8. Isomorphic Data Fetch with Vuex
import Vue from 'vue'
import Vuex from 'vuex'
import {fetchItems} from './api'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
itemsPerPage: 20,
items: {/* [id: number]: Item */}
},
actions: {
FETCH_ITEMS: ({ commit, state }, { ids }) => {
ids = ids.filter(id => !state.items[id])
if (ids.length) {
return fetchItems(ids).then(items =>
commit('SET_ITEMS', { items }))
} else {
return Promise.resolve()
}
}
},
mutations: {
SET_ITEMS: (state, { items }) => {
items.forEach(item => {
if (item) {
Vue.set(state.items, item.id, item)
}
})
}
}
})
export default store
store/index.js store/api.js
import Firebase from 'firebase'
const api = new Firebase('https://hacker-
news.firebaseio.com/v0')
function fetch (child) {
return new Promise((resolve, reject) => {
api.child(child).once('value', snapshot => {
resolve(snapshot.val())
}, reject)
})
}
export function fetchItem (id) {
return fetch(`item/${id}`)
}
export function fetchItems (ids) {
return Promise.all(ids.map(id =>
fetchItem(id)))
}
9. Server Side Component Cache
• Server side cache makes SSR +
SPA faster
• Component layer server side cache
• cache components by implementing
the serverCacheKey function
• API layer server side cache
• LRU cache examples:
const cache = inBrowser
? null
: (process.__API_CACHE__ || (process.__API_CACHE__ =
createCache()))
function createCache () {
return LRU({
max: 1000,
maxAge: 1000 * 60 * 15 // 15 min cache
})
}
const api = inBrowser
? new Firebase('https://hacker-news.firebaseio.com/v0')
: (process.__API__ || (process.__API__ =
createServerSideAPI()))
export default {
name: 'item', // required
props: ['item'],
serverCacheKey: props => props.item.id,
render (h) {
return h('div', this.item.id)
}
}
10. • Picked breaking changes from previous version
• Install
• routes config are changed to Array
• Navigations
• history.go -> history.push
• v-link directive -> <router-link> component
• Hooks
• The hooks data, activate, deactivate, canActivate, canDeactivate, canReuse are now replaced
• activate & deactivate -> Component's own lifecycle hooks
• data -> Use a watcher on $route to react to route changes
• canActivate -> beforeEnter guards declared in route configurations
• canDeactivate -> beforeRouteLeave defined at the root level of a component's definition
• canReuse -> removed because it is confusing and rarely useful
Migration from Vue Router v0.x.x
const router = new VueRouter({
mode: 'history',
base: __dirname,
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About },
{ path: '/users', component: Users,
children: [
{ path: ':username', component: User }
]
}
]
})
watch: {
'$route': 'fetchData'
}
17. • Webpack will automatically split and lazy-load the split modules
when using AMD require syntax
Vue Router 2.0 - Async Components
const Foo = resolve => require(['./Foo.vue'], resolve)
const Bar = resolve => require(['./Bar.vue'], resolve)
const router = new VueRouter({
mode: 'history',
base: __dirname,
routes: [
{ path: '/', component: Home },
// Just use them normally in the route config
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
})
https://github.com/vuejs/vue-router/blob/next/examples/lazy-loading/app.js
18. • scrollBehavior
• only available in html5 history mode
• defaults to no scroll behavior
• return false to prevent scroll
Vue Router 2.0 - scrollBehavior
const scrollBehavior = (to, from, savedPosition) => {
if (savedPosition) {
return savedPosition
} else {
const position = {}
// new navigation.
// scroll to anchor by returning the selector
if (to.hash) {
position.selector = to.hash
}
if (to.matched.some(m => m.meta.scrollToTop)) {
// cords will be used if no selector is provided,
// or if the selector didn't match any element.
position.x = 0
position.y = 0
}
// if the returned position is falsy or an empty object,
// will retain current scroll position.
return position
}
}
const router = new VueRouter({
mode: 'history',
base: __dirname,
scrollBehavior,
routes: [
{ path: '/', component: Home, meta: { scrollToTop: true }},
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar, meta: { scrollToTop: true }}
]
})
https://github.com/vuejs/vue-router/blob/next/examples/scroll-behavior/app.js
20. • Vue Router x Vuex
• Inject (sync) router states to Vuex states
• Components can access router data (path, params, query)
through vuex getter in components router
• https://github.com/vuejs/vuex-router-sync
Vue Router 2.0 - Vuex Router Sync
21. SPA with Awesome Vue Family
• Building SPA with Vue.js 2.0 Family
• Better performance for SPA by reactive components mechanism
• SSR & SPA with isomorphic fetch and client hydration
• No worried about SEO & server side template like EJS
• Seamless integration with Vue-Router & Vuex modules compare to
React & React-Router & Redux because the author is same Evan :)
It allows us more consistent & intuitive coding manner