Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
How to Build SPA with Vue
Router 2.0
2016/08/24
Takuya Tejima
Who?
• Takuya Tejima @tejitak
• Co-Founder & CTO at Indie Inc. (ex-IBM, ex-LINE)
• Server & Web Front-End & iOS Engineer
•...
What’s SPA
• SPA (Single Page Aplication)
• SPA is a web application or web site that fits on a single web page with the g...
• Vue Router Features
• Dead simple for component mapping with routes
• Nested routes and sub components
• Support SSR (Se...
Work with SSR
• What’s BundleRenderer?
• Generate components for each requests from code to prevent shared modules on node...
Cont. Work with SSR
import Vue from 'vue'
import App from './App.vue'
import store from './store'
import router from './ro...
Client Side Hydration
• Client side Vue instance will attempt to "hydrate" the existing DOM instead of creating
new DOM no...
Isomorphic Data Fetch with Vuex
import Vue from 'vue'
import Vuex from 'vuex'
import {fetchItems} from './api'
Vue.use(Vue...
Server Side Component Cache
• Server side cache makes SSR +
SPA faster
• Component layer server side cache
• cache compone...
• Picked breaking changes from previous version
• Install
• routes config are changed to Array
• Navigations
• history.go ...
1. Use plugin
2. Define route components
3. Create the router
4. Create and mount root instance.
Vue Router 2.0 - Install
...
• Examples
Vue Router 2.0 - <router-link>
<li><router-link to="/">/</router-link></li>
<li><router-link to="/users" exact>...
• A single route can define multiple named components
Vue Router 2.0 - Named view
const router = new VueRouter({
mode: 'hi...
• Alias / Redirect examples
Vue Router 2.0 - Alias / Redirect
routes: [
{ path: '/home', component: Home,
children: [
// a...
• beforeEnter examples
Vue Router 2.0 - Guard Examples 1
import Dashboard from './components/Dashboard.vue'
import Login f...
• beforeRouterLeave examples
Vue Router 2.0 - Guard Examples 2
const Baz = {
data () {
return { saved: false }
},
template...
• Webpack will automatically split and lazy-load the split modules
when using AMD require syntax
Vue Router 2.0 - Async Co...
• scrollBehavior
• only available in html5 history mode
• defaults to no scroll behavior
• return false to prevent scroll
...
• Transition
• Dynamically transition setting on route change are available
Vue Router 2.0 - Transition
const Parent = {
d...
• Vue Router x Vuex
• Inject (sync) router states to Vuex states
• Components can access router data (path, params, query)...
SPA with Awesome Vue Family
• Building SPA with Vue.js 2.0 Family
• Better performance for SPA by reactive components mech...
Thanks!
Join Slack (Japanese)
https://vuejs-jp-slackin.herokuapp.com/
Upcoming SlideShare
Loading in …5
×

How to Build SPA with Vue Router 2.0

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

  • Be the first to comment

How to Build SPA with Vue Router 2.0

  1. 1. How to Build SPA with Vue Router 2.0 2016/08/24 Takuya Tejima
  2. 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. 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. 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. 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. 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. 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. 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. 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. 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' }
  11. 11. 1. Use plugin 2. Define route components 3. Create the router 4. Create and mount root instance. Vue Router 2.0 - Install import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) const router = new VueRouter({ mode: 'history', base: __dirname, routes: [ { path: '/', component: { template: '<div>home</div>' } }, { path: '/foo', component: { template: '<div>foo</div>' } }, { path: '/bar', component: { template: '<div>bar</div>' } } ] }) new Vue({ router, template: ` <div id="app"> <ul> <li><router-link to="/">/</router-link></li> <li><router-link to="/foo">/foo</router-link></li> <li><router-link to="/bar">/bar</router-link></li> </ul> <router-view class="view"></router-view> </div> ` }).$mount('#app')
  12. 12. • Examples Vue Router 2.0 - <router-link> <li><router-link to="/">/</router-link></li> <li><router-link to="/users" exact>/users (exact match)</router-link></li> <li><router-link to="/users/evan#foo">/users/evan#foo</router-link></li> <li> <router-link :to="{ path: '/users/evan', query: { foo: 'bar', baz: 'qux' }}"> /users/evan?foo=bar&baz=qux </router-link> </li>
  13. 13. • A single route can define multiple named components Vue Router 2.0 - Named view const router = new VueRouter({ mode: 'history', base: __dirname, routes: [ { path: '/', components: { default: Foo, a: Bar, b: Baz } }, { path: '/other', components: { default: Baz, a: Bar, b: Foo } } ] }) new Vue({ router, data () { return { name: 'b' } }, watch: { '$route' () { this.name = 'a' } }, template: ` <div id="app"> <h1>Named Views</h1> <ul> <li><router-link to="/">/</router-link></li> <li><router-link to="/other">/other</router-link></li> </ul> <router-view class="view one"></router-view> <router-view class="view two" :name="name"></router-view> <router-view class="view three" name="b"></router-view> </div> ` }).$mount('#app') router config vue instance
  14. 14. • Alias / Redirect examples Vue Router 2.0 - Alias / Redirect routes: [ { path: '/home', component: Home, children: [ // absolute alias { path: 'foo', component: Foo, alias: '/foo' }, // relative alias (alias to /home/bar-alias) { path: 'bar', component: Bar, alias: 'bar-alias' }, // multiple aliases { path: 'baz', component: Baz, alias: ['/baz', 'baz-alias'] } ] }, // absolute redirect { path: '/absolute-redirect', redirect: '/bar' }, // named redirect { path: '/named-redirect', redirect: { name: 'baz' }}, // redirect with params { path: '/redirect-with-params/:id', redirect: '/with-params/:id' }, // catch all redirect { path: '*', redirect: '/' } ]
  15. 15. • beforeEnter examples Vue Router 2.0 - Guard Examples 1 import Dashboard from './components/Dashboard.vue' import Login from './components/Login.vue' function requireAuth (route, redirect, next) { if (!auth.loggedIn()) { redirect({ path: '/login', query: { redirect: route.fullPath } }) } else { next() } } const router = new VueRouter({ mode: 'history', base: __dirname, routes: [ { path: '/dashboard', component: Dashboard, beforeEnter: requireAuth }, { path: '/login', component: Login } ] }) https://github.com/vuejs/vue-router/blob/next/examples/auth-flow/app.js
  16. 16. • beforeRouterLeave examples Vue Router 2.0 - Guard Examples 2 const Baz = { data () { return { saved: false } }, template: ` <div> <p>baz ({{ saved ? 'saved' : 'not saved' }})<p> <button @click="saved = true">save</button> </div> `, beforeRouteLeave (route, redirect, next) { if (this.saved || window.confirm('Not saved, are you sure you want to navigate away?')) { next() } } } const router = new VueRouter({ mode: 'history', base: __dirname, routes: [ { path: '/', component: Home }, { path: '/baz', component: Baz } ] }) https://github.com/vuejs/vue-router/blob/next/examples/navigation-guards/app.js
  17. 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. 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
  19. 19. • Transition • Dynamically transition setting on route change are available Vue Router 2.0 - Transition const Parent = { data () { return { transitionName: 'slide-left' } }, // dynamically set transition based on route change watch: { '$route' (to, from) { const toDepth = to.path.split('/').length const fromDepth = from.path.split('/').length this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left' } }, template: ` <div class="parent"> <h2>Parent</h2> <transition :name="transitionName"> <router-view class="child-view"></router-view> </transition> </div> ` } https://github.com/vuejs/vue-router/blob/next/examples/transitions/app.js
  20. 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. 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
  22. 22. Thanks! Join Slack (Japanese) https://vuejs-jp-slackin.herokuapp.com/

×