Skip to content

Lazy load for components #185

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

Closed
wants to merge 1 commit into from
Closed

Conversation

rhengles
Copy link

@rhengles rhengles commented Jul 6, 2020

@CyberAP
Copy link
Contributor

CyberAP commented Jul 7, 2020

Lazy load for components is already supported in Vue 2 by defining component as a function (foo: () => import('./Foo.vue')) and in Vue 3 via RFC #26.

@yyx990803
Copy link
Member

This has been in Vue 2 since the very beginning: https://vuejs.org/v2/guide/components-dynamic-async.html#Async-Components

@yyx990803 yyx990803 closed this Jul 7, 2020
@rhengles
Copy link
Author

rhengles commented Jul 7, 2020

This has left out the part about "no webpack" and "no build step". Could I get an answer about that? I wrote extensively about it on "motivation".

@rhengles
Copy link
Author

rhengles commented Jul 7, 2020

@CyberAP Also, about RFC #26, it requires that you predefine the component names. My proposal doesn't have this limitation. The compiler finds a component name in the template and calls a function to get that component definition. All I'm asking is that my code can provide that function. Why are we so constrained with build tools? I'm sure there's an audience that would prefer to get rid of them if possible.

The rfc template mentions that increase of conplexity is a concern for Vue codebase. Why then the complexity of webpack is shoven down our throats? I'm trying to reduce the complexity of the final application. This is such a simple change, what is the motivation to decline it? I honestly can't understand.

@CyberAP
Copy link
Contributor

CyberAP commented Jul 7, 2020

Sorry I don't understand what exactly are you proposing from reading the rendered proposal.
If you need runtime template compilation it is already possible. You don't have to define a component name in order to create a component in runtime:

<component :is="{ template: `<div>hello world</div>` }" />

It also does not require a build step.

@yyx990803
Copy link
Member

The API doesn't have a hard requirement on the build setup. You can do anything inside the async component factory, including custom AJAX/fetch requests.

@rhengles
Copy link
Author

rhengles commented Jul 7, 2020

@CyberAP what? How would that resemble anything that looks like a organized codebase? You mean I have to replace every single component call into < component is="foo">< /component>? Really? Every single one?? You're telling me I can't have simply < foo>< /foo>?

That would look very strange, maybe ugly. Probably ugly. See, people use < component is=""> when they don't know beforehand what component will be rendered. When I call < foo>, I know I want < foo>, no need to repeat it again in the options : components: { foo: { getFoo } }, because that list will get big and tedious to be constantly updating.

I'm sorry if I come across as unpleasant or rude, but I can't reasonably think you have seen my examples from the answers I got. For instance, this:

https://github.com/arijs/vue-next-example/blob/master/js/index.js

That example is a little too succint, because the only component getting loaded is < app--root>< /app--root>. But assume I have several dozens of components, and all and each of them will be loaded in this manner.

When a template finds < app--foo>< /app--foo>, I need it to load by ajax without defining it in the "components:{}" object, and it is possible.

@privatenumber
Copy link

privatenumber commented Jul 7, 2020

A build step (eg. Webpack) should only be necessary for compiling the SFC. You might not even need it considering Codepen seems to offer client-side support (vueify?).

Here's an example using async components without a build: https://jsfiddle.net/hirokiosame/076s9em4/

Here's an example using globally registered async components (not in components hash): https://jsfiddle.net/hirokiosame/076s9em4/3/

Here's an example that resolves async components globally & dynamically:
https://jsfiddle.net/hirokiosame/v0s4zron/

(I simulate an external file using URL.createObjectURL(new Blob(...)), which you can ignore)

Hope that helps

@rhengles
Copy link
Author

rhengles commented Jul 7, 2020

Thank you @privatenumber for your genuine effort into writing those examples and trying to help me. 🙏

Wait, what? There exists a function called

resolveComponent?

😳😱 That's exactly what I needed!!!!!!

However, there's one small issue - it doesn't fallback to the standard resolving of components if I return undefined.

Example:

Vue.resolveComponent = function(name) {
	console.log('ResolveComponent', name);
};
// output:
// => ResolveComponent block--header
// => ResolveComponent router-view
// => [Vue warn]: Invalid vnode type when creating vnode: undefined. 
//  at <Anonymous> 
//  at <AsyncComponentWrapper>

How do I resolve router-view and every other component created by plugins?

@rhengles
Copy link
Author

rhengles commented Jul 7, 2020

Ah, I got it:

var originalResolveComponent = Vue.resolveComponent;

Vue.resolveComponent = function(name) {
	console.log('ResolveComponent', name);
	return originalResolveComponent.apply(this, arguments);
};

I ❤ U @privatenumber !

After all these years, this was the answer... I'm sad that this wasn't shown before.

@rhengles
Copy link
Author

rhengles commented Jul 28, 2020

@privatenumber @CyberAP

Now I'm having an issue trying to combine my solution above with <component>.

Here's an reproduction link: https://jsbin.com/bejupuyuli/edit?html,js,console,output

Can anyone shine a light on this issue? Is it related to Vue.resolveDynamicComponent() ?

Here's a sample code. The static works, the dynamic doesn't.

function compAsyncTimeout(comp, time) {

return Vue.defineAsyncComponent(function() {
  return new Promise(function(resolve) {
    setTimeout(resolve, time, comp);
  });
});

}

var MyComp = {
  foo: compAsyncTimeout({
    template: '<div class="foo">foo component resolve async</div>'
  }, 3000)
};

var originalResolveComponent = Vue.resolveComponent;

Vue.resolveComponent = function(name) {
  return MyComp[name] || originalResolveComponent(name);
};

Vue.createApp({
  template: "\
  <div class=\"app-root\">\
    <p>static:</p>\
    <foo></foo>\
    <p>dynamic:</p>\
    <component is=\"foo\"></component>\
  </div>\
  "
}).mount('#app');

@rhengles
Copy link
Author

@privatenumber @CyberAP @underfin

Oh, I had to extend resolveDynamicComponent as well. I don't understand the relation between RC and RDC. Why doesn't RDC consume the output of RC by default?

var originalRDC = Vue.resolveDynamicComponent;

Vue.resolveDynamicComponent = function(name) {
	var res = Vue.resolveComponent(name);
	if (!res || 'string' === typeof res) {
		return originalRDC.apply(this, arguments);
	} else {
		return res;
	}
};

@rhengles
Copy link
Author

@privatenumber @CyberAP @underfin

Since today is a two-month "anniversary" of last post, I would be very grateful if the purpose of the resolveDynamicComponent function would be explained. The docs don't mention it and I couldn't find the reasoning by search, maybe if you could just point me in the right direction that'd already be enough.

Thanks!

@privatenumber
Copy link

I'm not apart of the core team or have any involvement with building Vue 3, and I'm still using Vue 2 in my projects so I'm probably not the best person to ask.

Based on the source code (resolveComponent & resolveDynamicComponent), it seems like the differences are:

  • resolveComponent only supports a component name (name: string), and warns if it can't resolve it. If it can't resolve, it returns the name as a string.
  • resolveDynamicComponent accepts any type for component. If it's a string, it tries to resolve it but won't warn if it can't. If it's not a string, it warns but fall through to creating a vNode.

There's probably more if you dig deeper.


vue/rfcs is a place to propose changes to Vue. When you have questions in the future, try the forums, chats, or Stack Overflow (as recommended at the top of the page here). People that are proactively looking to help browse these places so you'll get more traffic there.

Alternatively, if it's a simple question "What's the difference between Vue 3's RDC and RC?", you might have some luck tweeting at some of the core members -- they're very friendly and helpful.

PS If you want more responses, be less wordy with posts as most people are busy and want to skim. A lot of people won't even read if it's too long.

Good luck

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

Successfully merging this pull request may close these issues.

4 participants