Closed ch-lukas closed 6 years ago
What purpose does this API solve for you?
I may be missing something, but I feel you can still import modules asynchronously.
const something = import('something')
export default {
async beforeCreate () {
const { exportName } = await something
this.exportName = exportName
}
}
For me it helps with simplicity/readability.
Your example, which I also use in my code, is a 2 step process. 1 - store promise import in a temp const and then 2 - when promise is ready update a reactive data value.
Now image you have 10 imports per component = 20 steps of code. IMHO that's a lot of unnecessary fluff.
Any news please?
This doesn't make sense. The exports from a vue file must be synchronous. I'm not convinced by the simplicity/readability argument either, on the contrary I think it makes things more complicated then it should be.
Async / await is the future and makes things a lot less complicated and allows for dynamic loading. At the moment there are a lot of tedious complicated work arounds to support dynamic loading (e.g. like the one above in this comments chain). You can also for example add async to your methods, but this only works for click events and not methods that are needed during rendering. It makes sense, but it up to you to take the good advice.
@yyx990803 - two questions for you?
BTW, I really do like Vue and what you have created and really just have a different view on this one and only point.
Can this be done with Vuejs?
I'm sorry but what @znck showed looks way cleaner and easier to understand to me than the examples you provided. Components are values, not modules. Async happens inside a component's lifecycle hooks, not where it is defined.
@ch-luke if you want to handle dynamic imports why not load them as @yyx990803 is suggesting, in the lifecycle hooks?
Is that not the purpose of dynamic imports with something like webpack? To do code splitting and lazy load code as needed? I don't see what the point of using a top-level await for a dynamic import. It just means that module will be loaded no matter what, in which case why not just load it synchronously?
@chrisnicola / @znck / @yyx990803 , have you tried the above code snippet in a project before?
It actually doesn't work. Dealing with promises await, by design, does not pause execution so the parser will continue with the rest of the functions / lifecycle stages etc and might get to the point where you used the this.exportName before it has been resolved. Hence it is important to give initial values like in the updated example below:
export default {
async beforeCreate () {
this.exportName = () => undefined
const { exportName } = await import('something')
this.exportName = exportName
}
}
But this example still doesn't always work like I am finding out when using it in modals (components methods are firing quicker than the imports can be resolved). Currently, I am having to define the imports in the parent and then calling them from the child component this.$parent.exportName - not really ideal.
How can we constructively take this forward ?
Yes, I understand how async/await and promises work. However, I may not fully understand what you are trying to achieve though.
So to clarify, are you suggesting that VueJS have a way to have a lifecycle hook await
something before rendering. In order words, if beforeCreate
is async (i.e., returns a promise) it should detect the promise and await it before continuing with the render cycle.
@yyx990803 that's an interesting idea and a problem that I have run into, though I'll admit it isn't particularly hard to work around, but just having some component loading
state associated with the promise or other solution depending on the context.
I wonder if lifecycle hooks that worked similar to router guards (https://router.vuejs.org/en/advanced/navigation-guards.html) would be useful?
export default {
// lifecycle hook that expects a promise
async awaitCreate() {
this.exportName = () => undefined
const { exportName } = await import('something')
this.exportName = exportName
}
// or alternatively passes an explicit continue function argument
async awaitCreate(continue) {
this.exportName = () => undefined
const { exportName } = await import('something')
this.exportName = exportName
continue()
}
}
@ch-luke the snippet assumes you have exportsName
declared as a reactive property in data
. That's common practice if you want to trigger updates by setting a value async.
@yyx990803, thanks for your response. Yes took that into account, but the snippet really does not work.
I do see something here. As you mentioned , components are synchronise and introducing async to any part of it will alter the load sequence . You are suggesting using reactivity as a solution, but by design that is a post-fix band aid approach and believe there is a better way.
So I am suggesting we use async/await to keep components synchronise and ensure the load order of the lifecycle stages . E.g.
// About to load the component
if (hasAsync(comp)) {
// Load stages in order
await loadMethods()
await loadBeforeCreated()
await loadCreated()
...
// Shouldn't we also introduce a asyncMethods tag for non load critical
// code such as button clicks. This will be lazy loaded and not waited for
loadAsyncMethods()
} else {
// Load component normally
}
Is there anyway to make it?
Would allow you to dynamically imports all your modules.