Commit ef4aba2a authored by Evan You's avatar Evan You

fix cache

parent 67b5bf0d
...@@ -89,7 +89,7 @@ app.get('*', (req, res) => { ...@@ -89,7 +89,7 @@ app.get('*', (req, res) => {
renderStream.on('end', () => { renderStream.on('end', () => {
res.end(`<script src="/dist/client-bundle.js"></script></body></html>`) res.end(`<script src="/dist/client-bundle.js"></script></body></html>`)
console.log('whole request: ' + (Date.now() - s)) console.log(`whole request: ${Date.now() - s}ms`)
}) })
renderStream.on('error', err => { renderStream.on('error', err => {
......
...@@ -10,7 +10,7 @@ export default context => { ...@@ -10,7 +10,7 @@ export default context => {
return component.prefetch(store) return component.prefetch(store)
} }
})).then(() => { })).then(() => {
console.log('data fetch: ' + (Date.now() - s)) console.log(`data pre-fetch: ${Date.now() - s}ms`)
context.initialState = store.state context.initialState = store.state
return app return app
}) })
......
import Firebase from 'firebase' import Firebase from 'firebase'
import LRU from 'lru-cache'
const api = new Firebase('https://hacker-news.firebaseio.com/v0') const inBrowser = typeof window !== 'undefined'
// When using bundleRenderer, the server-side application code runs in a new
// context for each request. To allow caching across multiple requests, we need
// to attach the cache to the process which is shared across all requests.
const cache = inBrowser
? null
: (process.__API_CACHE__ || (process.__API_CACHE__ = LRU({ max: 1000 })))
// create a single api instance for all server-side requests
// and cache the latest top Ids on it.
const api = inBrowser
? new Firebase('https://hacker-news.firebaseio.com/v0')
: (process.__API__ || (process.__API__ = createServerSideAPI()))
function createServerSideAPI () {
const api = new Firebase('https://hacker-news.firebaseio.com/v0')
api.child(`topstories`).on('value', snapshot => {
api.__topIds__ = snapshot.val()
})
return api
}
function fetch (child) { function fetch (child) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
...@@ -11,17 +33,28 @@ function fetch (child) { ...@@ -11,17 +33,28 @@ function fetch (child) {
} }
export function fetchTopIds () { export function fetchTopIds () {
return fetch(`topstories`) return api.__topIds__
? Promise.resolve(api.__topIds__)
: fetch(`topstories`)
} }
export function watchTopIds (cb) { export function watchTopIds (cb) {
api.child(`topstories`).on('value', snapshot => { api.child(`topstories`).on('value', snapshot => {
cb(snapshot.val()) const ids = snapshot.val()
api.__topIds__ = ids
cb(ids)
}) })
} }
export function fetchItem (id) { export function fetchItem (id, forceRefresh) {
return fetch(`item/${id}`) if (!forceRefresh && cache && cache.has(id)) {
return Promise.resolve(cache.get(id))
} else {
return fetch(`item/${id}`).then(item => {
cache && cache.set(id, item)
return item
})
}
} }
export function fetchItems (ids) { export function fetchItems (ids) {
......
...@@ -49,6 +49,7 @@ const store = new Vuex.Store({ ...@@ -49,6 +49,7 @@ const store = new Vuex.Store({
} }
}) })
// watch for realtime top IDs updates on the client
if (inBrowser) { if (inBrowser) {
watchTopIds(ids => { watchTopIds(ids => {
store.commit('RECEIVE_TOP_IDS', { ids }) store.commit('RECEIVE_TOP_IDS', { ids })
......
...@@ -20,14 +20,16 @@ const fetchData = store => { ...@@ -20,14 +20,16 @@ const fetchData = store => {
export default { export default {
name: 'news', name: 'news',
prefetch: fetchData,
data () { data () {
return { return {
transition: 'slide-left' transition: 'slide-left'
} }
}, },
prefetch: fetchData, created () {
mounted () { if (typeof window !== 'undefined') {
fetchData(this.$store) fetchData(this.$store)
}
}, },
watch: { watch: {
'$route' (to, from) { '$route' (to, from) {
......
...@@ -39,19 +39,17 @@ module.exports = { ...@@ -39,19 +39,17 @@ module.exports = {
}, },
plugins: [ plugins: [
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env': { 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development')
}
}) })
] ]
} }
if (process.env.NODE_ENV === 'production' && process.env.VUE_ENV !== 'server') { if (process.env.NODE_ENV === 'production' && process.env.VUE_ENV !== 'server') {
module.exports.plugins = module.exports.plugins.concat([ // module.exports.plugins = module.exports.plugins.concat([
new webpack.optimize.UglifyJsPlugin({ // new webpack.optimize.UglifyJsPlugin({
compress: { // compress: {
warnings: false // warnings: false
} // }
}) // })
]) // ])
} }
...@@ -10,14 +10,13 @@ module.exports = merge(webpackConfig, { ...@@ -10,14 +10,13 @@ module.exports = merge(webpackConfig, {
libraryTarget: 'commonjs2' libraryTarget: 'commonjs2'
}, },
externals: { externals: {
firebase: true firebase: true,
'lru-cache': true
}, },
plugins: [ plugins: [
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env': { 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development'), 'process.env.VUE_ENV': '"server"'
VUE_ENV: '"server"'
}
}) })
] ]
}) })
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment