I've recently started a Nuxt project, and as an answer to its size and complexity, I decided to use TypeScript everywhere I can - Vue, Nuxt + Nuxt runtime, and Vuex.
After going through a lot of documentation, it seems Vue Composition API - https://vue-composition-api-rfc.netlify.com/ - will become the de-facto way to create components in Vue 3.x, and is the best way to create components with native type inference.
Using https://github.com/vuejs/composition-api we can use the Composition API with Vue 2.x, and we should: as it's the way to go with the upcoming major release, it seems much more sensible to use this instead of the Class API - which is based on decorators, and thus will not be more supported in Vue 3.x - or the Options API which has a lot of flaws, particularly regarding type inference.
But I'm really having a hard time understanding if - and how - we can use Nuxt page lifecycle - say, asyncData
- in the "mental framework" that the Composition API provides.
I'm currently using createComponent
, and use both asyncData
and setup
top-level object properties, but that's almost an anti-pattern to the Composition API.
The example in https://typescript.nuxtjs.org/examples/composition-api/minimal.html, while a great initiative, is actually useless: we only see a tiny part of the API, and nothing specific to Nuxt :/
An example if it's compatible - or a disclaimer to tell people that Nuxt is not compatible with this API yet - would be great.
A new example with the composition API, showing how to use the Nuxt lifecycle methods (asyncData, fetch, validate, head....)
Hello, IM curious about the same
Looking forward to some information about this as well!
Please note that the Composition API is a major feature of Vue v3 which is still in pre-alpha state. Its probably safe to say that there won't be any official Nuxt.js documentation about it until Vue v3 is at least in beta state but maybe not even until v3 stable has been released.
That said, we welcome all early adopters to share their experiences in this topic.
Ok, i'm gonna create a non-profit web brand with Nuxt, using Typescript, Composition API & GraphQL.
I'll let you know any progress.
@reilue thanks, good luck with that!
@pimlie you're right BUT many library authors are already rewriting their solutions to composition API (not to look far vuelidate). People are just using better API and making their software future-proof. By not supporting current Composition API plugin NUXT is cutting itself off from every modern solution that will use it.
@filrak Indeed we will follow vue roadmap to have the best support for composition API out of the box. The vue2 plugin currently lacks SSR support (vuejs/composition-api#80)
Agree, we should have at least a community module for it and some examples. But still not recommended for everyday use until we test it enough :)
@pi0 I just came across the same PR, saved my day ^^
Also, 100% agree with you. I believe most of the new Vue projects right now will choose composition API over the old one either to be more future-proof or just because it's better than previous composition options. It would be great if you make Nuxt a good environment for such projects. Are there any plans for such module already?
@filrak Yep. Actually, this module does nothing than registring composition-api plugin. More for making it more official and accessible, and providing examples, docs, tips, etc. We also already have typescript support.
Re SSR, it is under question. runtimeContext depends on a global reference. We need to ensure no context sharing will happen when making concurrent requests.
@pi0 good to know this topic and moreover SSR support is given the attention it deserves!
I'd like to help but unfortunately that's above my TS skillset for now.
I'd be happy to help write some examples when Nuxt starts providing composition-api-ready lifecycle hooks though.
Should this issue stay opened until the Composition API PR makes it?
I think we can solve this issue via creating asyncProp
function which does same logic with asyncData
and merges returning object into props. Because we cannot access this.data
in setup
function.
Inspired from getInitialProps
in next.js. :)
As an example, I started to rebuild my portfolio page with the composition API ☺️
Code is Open Source!
Ok, i could develop and deploy the non-profit web app, that i mention early, Peace Builder South Africa using Nuxt, GraphQL, Apollo and Typescript.
I see the potential benefits and disadvantages.
TL:DR; Benefits: make the web software development a walk on a sunny day.
TL:DR; Disadvantages: (to me, so far) can't use Ref. I would like to know any alternative strategic for this ;)
I'm guilty by not use Typescript due legacy JS plugins that i've to used (as you can see, client's choose the template, and i didn't, guilty again, use some modern vue plugins, due matter of time and because 🇻🇪, next time i'll definitely use vue plugins ).
Also i didn't search for any tools that generate TS-Definitions from JS files.
Nevertheless i'll recommend use Composition API.
Caveats
Need generate TS Definition for legacy JS plugins
@reilue can you offer examples of what plugins don't have typings? It's not hard to add typings. I have a PR submitted for nuxt-auth right now that shows how to do it.
Also i didn't search for any tools that generate TS-Definitions from JS files.
Typescript itself does, something like tsc --declarationOnly --allowJS input.js
@surmon-china the example only uses the Composition API to add reactive data like we would have done with a data
Option, still it's unfortunately no help regarding how to implement Nuxt lifecycle using the composition API.
@manniL thanks for sharing, you're apparently using the same workaround as me, using the Options API for Nuxt and composition for stuff that allow using it.
So after all it still depends on https://github.com/vuejs/composition-api/pull/80 to make it to the Vue 2 plugin (or Vue 3 to be released and Nuxt to be updated to work with it but that may not be tomorrow)
https://github.com/vuejs/composition-api/pull/80 was merged :tada:
I don't know if you guys developing Nuxt already have an idea of how you're going to build it to be composition-friendly, but if you want some feedback, I think that providing a global Nuxt hook for asyncData
/ fetch
, would be great and make it really easy to use asyncData
in any component. If this is a reasonable thing to allow :sweat_smile:
I managed to run composition-api with NUXT, and it works fine with SSR.
It works on my open-source project: https://greenpress.herokuapp.com/
I found that it doesn't work well with components that uses nuxt-middleware or vuex getters.
the frontend repository for my platform based on nuxt.js is located here:
https://github.com/greenpress/blog-front
@davidmeirlevy where do you use the composition api in combination with asyncData
or fetch
. I can't seem to find it
@jessielaf i admit that to my opinion, it’s not as elegant as the nuxt middlewares, so I kept using middlewares.
Also, I’ll use the async soon to handle using vuex state inside the setup method (currently not playing together very well).
Looking forward for SSR support for @vue/composition-api
🙏
I just managed to use async state using useServerPrefetch
the example in my commit: https://github.com/greenpress/blog-front/commit/c2c8dc190f8818956a5e699c5206fc68289dabe5
previously I used nuxt-middlewares to create async calls and state change, and I set the data in vuex-store, and I managed to replace the nuxt-middlwares to compositions functions.
The only sad thing is that I couldn't use the getNamespacedState of vuex, and I can't return the result of mapState as the return of the setup function.
I found a small problem with a lack of context in the error function. Since onServerPrefetch
already exists, the ability to specify the desired HTTP response for the error is required. But for the moment, it will cause an error.
import { createComponent, onServerPrefetch } from '@vue/composition-api';
export default createComponent({
setup(props, { root }) {
onServerPrefetch(async () => {
await new Promise((resolve) => {
setTimeout(resolve, 3e3);
});
root.nuxt.error({
statusCode: 404,
message: 'Not found'
});
});
return {};
}
});
The result will be:
At the moment, this can only be used like this:
root.nuxt.error.call({ nuxt: root.nuxt }, {
statusCode: 404,
message: 'Not found'
});
But such use is not a stable API
@filrak Indeed we will follow vue roadmap to have the best support for composition API out of the box. The vue2 plugin currently lacks SSR support (vuejs/composition-api#80)
Agree, we should have at least a community module for it and some examples. But still not recommended for everyday use until we test it enough :)
I don't know how closely you guys follow the progress but since I just checked vue-next: SSR is now working and the linked issues seemed closed
That's not entirely correct. There is a serverPrefetchHook though it is not the final implementation (still better than nothing).
Also, SSR support for vue-next is not present so far ☺️
Ah, sorry for the confusion and low effort research then! Keep on trucking!
On Sat, Jan 18, 2020 at 11:57 AM Alexander Lichter notifications@github.com
wrote:
That's not entirely correct. There is a serverPrefetchHook though it is
not the final implementation (still better than nothing).Also, SSR support for vue-next is not present so far ☺️
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/nuxt/nuxt.js/issues/6517?email_source=notifications&email_token=AB6WSHSUMSXG3LYAJ7OUYWDQ6LOCNA5CNFSM4I5RUHU2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEJJVVXY#issuecomment-575888095,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AB6WSHUPW733ZXMVQBNYKP3Q6LOCNANCNFSM4I5RUHUQ
.
Looking at the latest plans for Vue 3 (including SSR and async components), it seems like a lot of Nuxt is getting built into Vue 3 itself. Is there any insight as to what this means for Nuxt in the future?
@Arcaster42 Vue 2 already supports SSR, so that isn't a change with Vue 3.
But the new features present in Vue 3 will make Nuxt even better 🙃
@Arcaster42 do you know exactly what changes Vue 3 will be making to better support SSR out of the box? Do you have any references for us?
@MarkSonn Feel free to check out Evan's talks from Vue Amsterdam 2020 and VueConf US 2020 (https://www.vuemastery.com/conferences/vueconf-us-2020/state-of-the-vuenion) ☺️
So this is the best way I've found to use asyncData
so far with @vue/composition-api
type Await<T> = T extends {
then(onfulfilled?: (value: infer U) => unknown): unknown;
}
? U
: T;
export function useAsyncData<T extends (...args: any) => void>(
cb: (arg: Await<ReturnType<T>>) => void
) {
onBeforeMount(function(this: any) {
cb(this);
});
}
You can then use this helper to get type safe access to the asyncData
results in a _callback_ (not immediately when setup
is called, as setup
isn't always called before asyncData
is resolved).
function asyncData() {
return new Promise(resolve=> {
... data fetching
});
};
export default defineComponent({
asyncData,
setup() {
useAsyncData<typeof asyncData>(data => {
... // can use async data results or assign to refs outside callback
});
}
});
let me know if anyone finds a better way as this is a bit kludgy.
I haven't tinkered with asyncData
this much for now as the app I'm using the Composition API for will be deployed soon, so I need it to be quite stable.
In the meantime I've struggled pretty much to build composition "hooks" and make them work nicely with Nuxt on both server and client side, particularly when using programmatic components (with Buefy) that rely on a global Vue instance. Here's my two cents on how to use hooks while still using Nuxt's Vuex store and everything:
// composable/useServices.js
/**
* Services hook.
*
* @param nuxtContext
* Nuxt context, injected from plugin.
* @param setupContext
* Optional. The component context, which is the 2nd argument of the component's `setup` function.
* Required only when using Buefy modal components from hooks (dialog, toast...)
* @return Object
*/
function useServices(nuxtContext, setupContext = null) {
const { store } = nuxtContext
const { $api, $toast, $useAuth } = nuxtContext.app
const { currentLocale } = nuxtContext.app.$useI18n() // Using another hook in this hook.
// Example of generic reactive getter/setter using vuex-map-fields mutations under the hood.
const getServiceFieldByServiceId = (field, id) => computed({
get: () => {
try {
return store.getters['services/getField'](id)(field)
} catch (e) {
console.log(e, field)
}
},
set: val => {
return store.commit('services/updateField', {
id,
path: field,
value: val,
})
},
})
// Example of using an API (previously injected as $api)
async function fetchAll(providerId) {
const res = await $api.get(`providers/${providerId}/services`)
await store.dispatch('services/createMany', res)
}
// Example of using 2nd argument setupContext which is the 2nd argument of setup() fn.
function deletePicture(id) {
setupContext.root.$buefy.dialog.confirm({
title: setupContext.root.$t('dialog.picture_delete.title'),
message: setupContext.root.$t('dialog.picture_delete.message'),
hasIcon: true,
type: 'is-danger',
async onConfirm() {
await deleteFile(id)
},
})
}
}
export default useServices
// plugins/hooks.js
import useServices from '~/composable/useServices'
export default function(context, inject) {
// Pass Nuxt context so we get access to store etc.
inject('useServices', setupContext => useServices(context, setupContext))
// Make HMR work as hooks are edited quite frequently.
if (module.hot) {
module.hot.accept(['../composable/useServices'], () => {
inject('useServices', setupContext => require('../composable/useServices')
.default(context, setupContext))
})
}
}
// nuxt.config.js
module.exports = {
// ...
plugins: ['~/plugins/hooks.js'],
}
export default {
setup({ service }, ctx) {
// Call the hook and pass the setup context.
const { getServiceFieldByServiceId } = ctx.root.useServices(ctx)
return {
// I'm using this kind of mapping a lot to keep things generic in my hooks.
getField: field => getServiceFieldByServiceId(field, service.id),
}
},
}
I'm not sure why Nuxt doesn't play well when I'm using the hooks directly - probably something about the Vue global instance or so - but now that I've rewritten all my hooks this way there's not a single weird issue happening.
I know this may not help for the actual issue but this could be useful for "optimists" like me who are already using @vue/composition-api
in production
I would recommend using getCurrentInstance()
instead of passing context around.
For an example of using the Composition API with Nuxt SSR and serverPrefetch, see https://github.com/danielroe/vue-sanity/blob/master/src/cache.ts.
@danielroe thanks, man! somehow I didn't see it in the API documentation.
@danielroe very useful, seems I missed that in the docs too. Thanks!
I've just thrown together an onFetch
hook to use the new Nuxt Fetch API.
An observation: setup()
runs in the beforeCreated()
lifecycle method, which is the same method wherein the Nuxt fetch()
is set up. Sadly, this means it is not possible to access that by programmatically instantiating $options.fetch
(unless @Atinux or Nuxt team would be up for moving some of the logic into created()
? I'd happily create a PR if so).
However, it is possible to clone the methodology. If anyone's interested, you can find a gist here.
(unless @Atinux or Nuxt team would be up for moving some of the logic into
created()
? I'd happily create a PR if so).
That'd be a breaking change :/ Anyway, will pass it along.
Hi, @danielroe gist looks nice. But just as @manniL mentioned, this would be a breaking change. If it is required for hook implementation of fetch
, we may make it customizable by an option :)
I've converted the gist above into a composition API module for Nuxt. Feature requests and bug reports very much welcome 😄
I strongly recommend anyone interested in this topic to try at @danielroe 's module, it's evolving fast and is actually the most advanced solution I've used so far. Cheers Daniel, this was a wonderful initiative and really helps, even at a late development stage :1st_place_medal:
https://github.com/danielroe/nuxt-composition-api
Module is now moved to nuxt-community. Let's move further works (for Nuxt2 support) over there:
Most helpful comment
Ok, i'm gonna create a non-profit web brand with Nuxt, using Typescript, Composition API & GraphQL.
I'll let you know any progress.