Closed rhengles closed 4 years ago
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.
This has been in Vue 2 since the very beginning: https://vuejs.org/v2/guide/components-dynamic-async.html#Async-Components
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".
@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.
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.
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.
@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.
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
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?
Ah, I got it:
var originalResolveComponent = Vue.resolveComponent;
Vue.resolveComponent = function(name) {
console.log('ResolveComponent', name);
return originalResolveComponent.apply(this, arguments);
};
After all these years, this was the answer... I'm sad that this wasn't shown before.
@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');
@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;
}
};
@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!
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
Full Rendered Proposal