Skip to content

How to handle lazy-loading #17

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ygm125 opened this issue Aug 31, 2016 · 12 comments
Open

How to handle lazy-loading #17

ygm125 opened this issue Aug 31, 2016 · 12 comments

Comments

@ygm125
Copy link

ygm125 commented Aug 31, 2016

ssr这种的如何做前端 lazy-loading,路由如何配置呢?

@nqdy666
Copy link

nqdy666 commented Oct 2, 2016

同问

@yyx990803 yyx990803 changed the title 如何处理 lazy-loading How to handle lazy-loading Nov 1, 2016
@atinux
Copy link

atinux commented Nov 3, 2016

Hi,

I made a version of vue-hackernews-2.0 with lazy-loading: https://github.com/Atinux/vue-hackernews-2.0-lazy

Live demo: https://vue-hn-lazy.now.sh

If you're interested, I can explain you how I achieved this.

@yyx990803
Copy link
Member

@atinux would love to hear about it.

@atinux
Copy link

atinux commented Nov 3, 2016

I will try to explain as simple as possible @yyx990803

First, you can see all the changes here: #65

When we require the components for the router, we need to tell Webpack to require it only on demand (code splitting), here we're using Webpack 2, so we need to use System.import():

// router/index.js
const ItemView = process.BROWSER  ? () => System.import('../views/ItemView.vue') : require('../views/ItemView.vue')
const UserView = process.BROWSER  ? () => System.import('../views/UserView.vue') : require('../views/UserView.vue')

See router/index.js changes.

Actually, System.import() doesn't work very well on the server-side and we don't need to load the components on demand on the server. So I added a variable in webpack to specify if we're from the server-bundle or client-bundle:

// webpack.client.config.js
new webpack.DefinePlugin({
  // ...
  'process.BROWSER': true
})
// webpack.server.config.js
new webpack.DefinePlugin({
  // ...
  'process.BROWSER': false
})

See: webpack.client.config.js and webpack.server.config.js changes

The crucial point is to instantiate the app only when the components to render the page are loaded, so now, we need to export the object, see app.js changes.

Then, in server-entry.js, we need to instantiate the app before returning it.

The big changes has been made in client-entry.js, indeed, we need to get the Components before instantiating the app. I just got back the methods flatMapComponents(route, fn) and getLocation (base) from vue-router.
When the components matching the actual route are loaded, we can start the app:

const _app = new Vue(app)
store.replaceState(window.__INITIAL_STATE__)
_app.$mount('#app')

I hope everything is clear enough 😄

@zspecza
Copy link

zspecza commented Nov 3, 2016

I'd also like to point out the importance of @atinux' decision to add a new build-time flag using DefinePlugin over just using process.env.VUE_ENV - Webpack's module resolution when code splitting is not smart enough to detect dead code when comparing string values like so:

if (something === 'some string') {}

It is possible, however, to detect primitives like so:

if (something) {}

@lijiakof
Copy link

lijiakof commented Nov 4, 2016

it's amazing! thank you, and can you tell us how you achieved this!

@BorjaRafols
Copy link

How was this never merged? @atinux

@atinux
Copy link

atinux commented Feb 26, 2018

@BorjaRafols
Copy link

BorjaRafols commented Feb 26, 2018

Can't see it on the demo...

If you look a the developer tools network tab, all files get preloaded. Your example on the other hand really does lazy loading.

I can attach screenshot if you want.
image

But if you go to:
https://vue-hn.now.sh/top

The following files get loaded:
https://vue-hn.now.sh/dist/0.685d9541a8b030833ec2.js
https://vue-hn.now.sh/dist/1.2230fda73206b44dc689.js
https://vue-hn.now.sh/dist/2.b3068c7c37138b1cfc05.js

The if you click on a username this file gets loaded again:
https://vue-hn.now.sh/dist/2.b3068c7c37138b1cfc05.js

This means that route splitting works but I have the feeling that all chunks get loaded on first render.

@BorjaRafols
Copy link

Your other repository on the other hand does this flawlesly.

https://vue-hn-lazy.now.sh

https://github.com/Atinux/vue-hackernews-2.0-lazy

@atinux
Copy link

atinux commented Feb 26, 2018

@BorjaRafols This is because the actual repo uses preload and prefetch to make it even faster, so it's better (I have implemented the same feature in Nuxt.js also)

@BorjaRafols
Copy link

Ok, let me read something about service workers and prefetch/preload :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants