Giter Club home page Giter Club logo

composition-api's Introduction

πŸ—οΈ Nuxt Composition API

Composition API hooks for Nuxt 2

@nuxtjs/composition-api provides a way to use the Vue Composition API with Nuxt-specific features.


Nuxt Bridge has now been released in beta. It has full composition API support and it's strongly recommended to migrate from @nuxtjs/composition-api, if possible, by following the steps in the Bridge migration guide. Feedback welcome at https://github.com/nuxt-community/composition-api/discussions/585.


Features

  • πŸƒ Fetch: Support for the new Nuxt fetch() in v2.12+
  • ℹ️ Context: Easy access to router, app, store within setup()
  • πŸ—ΊοΈ Head: Interact directly with your vue-meta properties within setup()
  • ✨ Automatic hydration: Drop-in replacement for ref with automatic SSR stringification and hydration (ssrRef)
  • πŸ“ SSR support: Allows using the Composition API with SSR
  • πŸ’ͺ TypeScript: Written in TypeScript

Read Documentation

Contributors

Contributions are very welcome.

  1. Clone this repo

    git clone [email protected]:nuxt-community/composition-api.git
  2. Install dependencies and build project

    yarn
    # Compile library and watch for changes
    yarn watch
    # Start a test Nuxt fixture with hot reloading
    yarn fixture
    # Test
    yarn test

Tip: You can also use yarn link to test the module locally with your Nuxt project.

License

MIT License - Copyright Β© Daniel Roe

composition-api's People

Contributors

andoshin11 avatar andrzejewsky avatar antfu avatar aussieboi avatar axelhzf avatar charlie0228 avatar danielroe avatar dependabot[bot] avatar destaq avatar edumudu avatar filipsobol avatar harlan-zw avatar jamiecurnow avatar kazupon avatar kolbins avatar mango-martin avatar mannil avatar mathe42 avatar mathieutu avatar nbili avatar nvitaterna avatar pi0 avatar rchl avatar renovate-bot avatar renovate[bot] avatar satyawikananda avatar seanghay avatar tahul avatar takmar avatar vaiil avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

composition-api's Issues

async functions require extra time with `nuxt generate`

πŸ› The bug
When generated files are produced, async functions or serverPrefetches don't correctly populate the Nuxt context.

Note: I believe this is an issue with Nuxt rather than with nuxt-composition-api.

πŸ› οΈ To reproduce
Steps to reproduce the behavior:

  1. Clone this repo.
  2. Remove interval: 2000 from test/fixture/nuxt.config.js
  3. Run yarn nuxt generate -c test/fixture/nuxt.config.js
  4. Inspect ./dist/ssr-ref/index.html to see not all ssrRefs injected in page

ℹ️ Workaround
You can add time between pages being generated to allow for any async functions to resolve, if you are pre-generating any of your pages.

nuxt.config.js:

{
  generate: {
    // choose to suit your project
    interval: 2000,
  }
}

Ok all ready

πŸ› The bug
What isn't working? Describe what the bug is.

πŸ› οΈ To reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

I'd be very grateful for a link to a gist or repo that reproduces the bug.

🌈 Expected behaviour
What did you expect to happen? Is there a section in the docs about this?

ℹ️ Additional context
Add any other context about the problem here.

fix:

πŸ› The bug
What isn't working? Describe what the bug is.

πŸ› οΈ To reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

I'd be very grateful for a link to a gist or repo that reproduces the bug.

🌈 Expected behaviour
What did you expect to happen? Is there a section in the docs about this?

ℹ️ Additional context
Add any other context about the problem here.

fix: Not working in Nuxt < 2.13

πŸ› The bug
If you install the Plugin with Nuxt 2.12 or lower the plugin doesn't work because TypeError: isFullStatic is not a function
it's imported from nuxt here

const { isFullStatic } = require('@nuxt/utils')

πŸ› οΈ To reproduce
Steps to reproduce the behavior:

Just install the plugin on nuxt 2.12 and the error appears

Thanks for the cool plugin :)

fix: `ssrRef` and `useAsync` do not support HMR

πŸ› The bug
On hot module reloading in development, ssrRef factory functions will not be re-run.

πŸ› οΈ To reproduce

  1. git clone https://github.com/danielroe/repro-hmr-composition-api
  2. cd repro-hmr-composition-api && yarn && yarn dev
  3. Visit http://localhost:3000/api
  4. Edit ~/content/index.md
  5. (Contrast http://localhost:3000/vanilla.)

🌈 Expected behaviour
I would expect HMR to trigger a refresh of the factory function on client-side.

ℹ️ Additional context
See nuxt/content#80

feat: a promise returning function to transfer state between server and client

πŸ†’ Your use case
I'm fetching data in a callback passed to a different hook:

const task = useTask(function*(){
 return ajax('/some/api');
});

In order to pass make this work with SSR well, the result needs to be passed through ssrContext.

Current solutions can be used but are not ideal:

useAsync returns a ref and probably needs to be used right in the setup()
useFetch expects you to assign to a ref and it does some error handling I don't necessarily need in this case

πŸ†• The solution you'd like
It would be great if there was a function that would behave similarly as useFetch or useAsync in terms of executing on the server and returning data from ssrContext on the client.

But the difference would be

  • result would be a promise that needs to be handled for rejection
  • it could be called not directly in setup (in a callback)

API proposal

setup() {
  const prefetch = usePrefetch();
  // used directly in setup:
  const data = await prefetch(() => ajax('/foo'));

  // or in some callback:
  const task = useTask(function *() {
    const data = yield prefetch(() => ajax('/foo'));
    return data;
  });
}

I struggle with naming here a bit. It's already a 3rd approach towards data loading besides useAsync and useFetch. But maybe usePrefetch seems right?

Besides my usecase with vue-concurrency I believe this could also be useful when using Suspense together with onErrorCaptured, but I'm not sure what's the state of using Susepense within Nuxt.

fix: useMeta() throws error if used in a layout

πŸ› The bug
The head: {} property triggers an error inside @vue/composition-api if used in a layout component, thus useMeta() cannot be used.

[vue-composition-api] must call Vue.use(plugin) before using any function

Pages seems to work as expected. The problem is caused by reactive() not being used in the correct scope (too soon in the Nuxt lifecycle?).

export const getHeadOptions = (options: any) => {
const _head: ReactiveHead = reactive<MetaInfo>({})
if (!(options.head instanceof Function)) {
Object.assign(_head, options.head)
}
const head =
options.head instanceof Function
? () => defu(_head, options.head())
: () => _head
return { _head, head }
}

I've resolved the issue myself in a fork by using Vue.observable() instead of reactive().
I'll submit a PR when it's ready to be reviewed.

πŸ› οΈ To reproduce
Steps to reproduce the behavior:

  1. Add head: {} to your layout
  2. See error

Use this sandbox to reproduce the error.
https://codesandbox.io/s/nuxt-composition-api-usemeta-layout-issue-r14yy?file=/layouts/default.vue

🌈 Expected behaviour
useMeta() should work in layout components as expected.

feat: Why don't we have predefined verb for posting intermediate progress statement for xAPI statements?

πŸ†’ Your use case
SumTotal is an LMS which has integrated with many content providers and import their content in our LMS. We are using xAPI to interact with the content providers to exchange details like start , completion and the score of the content. Our customers also want us to capture the
intermediate progress for content

Ex. When I do [...] I would expect to be able to do [...]

πŸ†• The solution you'd like
Have a standardized verb like 'Completed' to capture the intermediate progress percentage for content so that every provider do not define their own extension to capture the same

πŸ” Alternatives you've considered
Have you considered any alternative solutions or features?
Extensions can be used to capture but it will only support just one provider. If it wont be standardized, it will be difficult to support multiple providers.

ℹ️ Additional info
Is there any other context you think would be helpful to know?

help: How do i transition from the vue-meta head function to the composition meta

πŸ“š What are you trying to do? Please describe.
I'm trying to use the head function for meta info. and all im getting are errors.

πŸ” What have you tried?
This is the code im using:

    head () {
        const i18nSeo = this.$nuxtI18nSeo()
        return {
            htmlAttrs: {
                ...i18nSeo.htmlAttrs
            },
            bodyAttrs: {
                class: [this.$auth.loggedIn && this.$auth.user.preferences && this.$auth.user.preferences.theme === 'dark' ? 'uk-light' : 'uk-dark'],
                ...i18nSeo.bodyAttrs
            },
            meta: [
                ...i18nSeo.meta
            ],
            link: [
                ...i18nSeo.link
            ]
        }
    }

How would I turn that into something that works for the composition api.
Ive tried:

        useMeta({ 
            htmlAttrs: {
                ...i18nSeo.htmlAttrs
            },
            bodyAttrs: {
                class: [$auth.loggedIn && $auth.user.preferences && $auth.user.preferences.theme === 'dark' ? 'uk-light' : 'uk-dark'],
                ...i18nSeo.bodyAttrs
            },
            meta: [
                ...i18nSeo.meta
            ],
            link: [
                ...i18nSeo.link
            ]
        })

but all that tells me is that it's not iterable.

feat: improve the head API

Currently according to the README useHead() is being used outside of the component.

Usually functions starting with useXXX are composition API used inside components.
Which to me, I think it might cause confusion.

I think the API would be cleaner like the following, but not sure if the implementation is possible.
Just giving my opinion.

import { defineComponent, head, useMeta } from 'nuxt-composition-api';

export default defineComponent({
  // this line is needed!
  head,
  setup() {
    // This will allow you to set the title in head - but won't allow you to read its state outside of this component.
    const { title } = useMeta()

    title.value = 'newSetTitle'
  },
})

help: Some problem with useFetch

What I'm trying to do?
I was trying to build a composable method where it has the state wrapped within a ref and some methods to get and set a post fetched from an API (https://jsonplaceholder.typicode.com/posts) and use the useFetch method to get the post and render it on the page.

What happens ?
The SSR HTML is ok, but the browser console fires some errors:
imagem

*How to reproduce ?
Test it here: https://codesandbox.io/s/runtime-sky-zcg6v

Am I doing something wrong?

Anyway, that's a lot for this package, Congratulations πŸ‘Œ!

help: Merging of refs and asyncData in setup() method

πŸ“š What are you trying to do? Please describe.
In the Vue 2 Nuxt API, asyncData() keys would be merged into data() keys. I'm struggling to figure out how to do a similar thing with the composition API.

πŸ” What have you tried?
My intention is to create a reactive variable using ref() with an initial state that is an empty object. If story can be retrieved from the Storyblok API, then it should override the initial state. The call to retrieve the Storyblok content is done in asyncData(), but I'm unsure how to execute this within the composition API using useAsync().

Here is my code so far:

import { defineComponent, useContext, useAsync, ref } from 'nuxt-composition-api';
import { useStoryblok } from '@/modules/Storyblok';

export default defineComponent({
  setup() {
    let story = ref({ story: {} });

    let newVariable = useAsync(useStoryblok(useContext()));
    
    return { story }
  }
})
import { useAsync } from 'nuxt-composition-api';

interface StoryblokSuccess {
  data: Object
}

interface StoryblokError {
  response: {
    status: Number,
    data: String,
  }
}

export const useStoryblok = async (context: any): Promise<StoryblokSuccess | StoryblokError> => {
  let version = context.query._storyblok || context.isDev
    ? 'draft'
    : 'published';

  return await context.app.$storyapi.get(
    `cdn/stories/${context.params.slug ?? 'home'}`, {
    version: version
  }).then((response: StoryblokSuccess) => {
    return { story: response.data };
  }).catch((response: StoryblokError) => {
    context.error({
      statusCode: response.response.status,
      message: response.response.data,
    });
  });
}

ℹ️ Additional context
Add any other context or information.

fix: does not work with `pinia`

Error message: cannot read property 'req' of undefined

vuejs/pinia#179

I'm not entirely sure why this happens. setSSRContext should just assign extra properties to the context, not replace it right?

fix: fetchOnServer always true with @vue/apollo-composable

πŸ› The bug
With a "simple" http request I can toggle 'fetchOnServer' it works, same with @nuxtjs/apollo. But with @vue/apollo-composable all queries are fetch on server.

πŸ› οΈ To reproduce
Launch the repo:
https://github.com/shenron/vue-nuxt-tsx

There a 3 pages:

  • index.vue, an http fetchOnServer = false
  • graphql.vue, prefetch: false
  • graphql_composition.vue, an fetchOnServer = false

🌈 Expected behaviour
To be able to swich fetchOnServer

Thank you for your help.

fix: generated composition-api/index.js file fails on windows

πŸ› The bug
On windows, when generating file .nuxt/composition-api/index.js, here is what happens:
image

Because windows by default uses backaslashes as path separators, they have to be properly escaped, or otherwise are treated as escape characters, and result in invalid string.

Here is the line of code, that produces that result.

const staticPath = join(this.options.buildDir || '', 'static-json')

I checked code from @nuxt/vue-app that generates routes, and it uses relativeTo function from @nuxt/utils. I checked it locally and it works, but I'm not sure if relative path here is fine.

Would love to give you PR, but I was not be able to easily run the source code locally on my windows 😐.

πŸ› οΈ To reproduce
Try to build app on windows.

🌈 Expected behaviour
Should compile, even on windows πŸ˜‰

help: Use `@vue/apollo-composable` with `asyncData` or `fetch` composition functions

πŸ“š What are you trying to do? Please describe.
I feel I should be able to use useQuery from @vue/apollo-composable but I can't see how to do it from the docs.
useQuery requires to be called synchronously within setup() so does useFetch or useAsync.

πŸ” What have you tried?
I've tried to call refetch method from useQuery within useFetch or useAsync but it doesn't work:

    const { result, loading, onResult, refetch } = useQuery(/*...*/)
    useAsync(() => {
      refetch()
    })

Since useQuery must be called in setup() function, I was waiting for the nuxt-composition-api module to be able to use @vue/apollo-composable properly but I failed.

I believe that I may encounter this issue using another asynchronous composable library that require to call the useX() within setup().

fix: useFetch not returning fetch and fetchState on SSR

πŸ› The bug
OK this might be intentional but it might be worth a discussion

I was previously using 0.9.3 and had a composition function that looked like this:

const { fetch, fetchState } = useFetch(async () => {
    data.value = await hasura
      .query({ query: query.query })
      .then(select(query.returning))
  })

After upgrading to 0.10.3 I found that on server rendering useFetch() was returning undefined and therefore my destructuring would throw and error. However, all would be OK when mounting the component on the client side only.

Given that the docs use the example:

const { fetch, fetchState } = useFetch(async () => {
      name.value = await axios.get('https://myapi.com/name')
})

I'm wondering if this is intentional, or a regression.

πŸ› οΈ To reproduce
Use the example useFetch() in the docs using 0.10.3 and check if error 'Can not structured from undefined` shows on server render.

🌈 Expected behaviour
useFetch() always returns and object with fetch and fetchState properties, on both client and server.

ℹ️ Additional context
I am using this inside a separate file, I don't think this matters but will detail below:

index.vue

<script>
import { defineComponent, ref } from 'nuxt-composition-api'
import { useQuery, ALL_LOUNGES } from '@/data'

export default defineComponent({
  layout: 'collection',
  setup() {
    const activeTab = ref('London Heathrow')

    const { lounges, fetch, fetchState } = useQuery(ALL_LOUNGES)

    return { lounges, activeTab }
  },
})
</script>

@/data

// imports and some utility functions above
function useQuery(query) {
  const { app } = useContext()
  const hasura = app.apolloProvider.defaultClient

  const data = ssrRef(false)

  const { fetch, fetchState } = useFetch(async () => {
    data.value = await hasura
      .query({ query: query.query })
      .then(select(query.returning))
  })

  return { fetch, fetchState, [query.returning]: data }
}

export { useQuery }

feat: `ssrRef`

For improved composability (given that a lot of state is stored off-component with the Composition API), there is a need for a ssrRef function that will automatically stringify and rehydrate refs on client-side, independent of component context.

help: The setup binding property "$fetchState" is already declared.

πŸ“š What are you trying to do? Please describe.
I using

const { $fetchState } = useFetch(async () => {
    articles.value = await app.$axios.$get('/articles')
 })
return { $fetchState }

and the console throw
"ERROR [Vue warn]: The setup binding property "$fetchState" is already declared."

πŸ” What have you tried?
If I remove $fetchState from return the error don't appear but I can't use $fetchState on template

ℹ️ Additional context

feat: use Nuxt lifecycle hooks

https://nuxtjs.org/api/internals-renderer

I guess these hooks are not intended to be used in components in general, but with some of them it would actually make sense to me.

My specific usecase would be render:routeContext. It could provide an alternative to ssrRef. I could serialize anything in a custom way just at the last moment. My custom hook is returning a reactive object and only some of the state makes sense to serialize (there's a bunch of derived state).

(This is what I'm working on: https://vue-concurrency.netlify.app/ssr-support/)

onSetupContext((context, sanitize) => {
 context[myKey] = sanitize(someCustomSerialization(obj));
});

fix: Set asynchronously properties from `useMeta` does not react for the first load

πŸ› The bug
I try to set the title asynchronously:

    const { title } = useMeta({ title: 'Page' })
    setTimeout(() => {
      title.value = 'My page'
    }, 1000)

When navigating to the page for the first time, the page title is "Page" and does not react to be "My page" after 1 second as it should be. Navigating again to the page (without browser hard reload), the page title is cached and set to be "My page" if keep-alive is configured, otherwise the page title would remain the same.

When the meta properties are cached, it's unconvenient for dynamic routes such as /blog/_slug.vue where content are fetched asynchronously. In this case, navigating to /blog/article-2 with title page "Article 2" after visiting /blog/article-1 display cached page title "Article 1"

πŸ› οΈ To reproduce
Steps to reproduce the behavior:

  1. Set keep-alive
  2. Hard reload browser on /blog/
  3. Navigate to /blog/article-1
  4. Page title is not set
  5. Go back to /blog/
  6. Navigate to /blog/article-1 again
  7. Page title is set to "Article 1"
  8. Navigate to /blog/article-2
  9. Page title is not set (first time visiting this page)
  10. Go back to /blog/
  11. Navigate to /blog/article-2
  12. Page title is set to "Article 1" because of keep-alive
  13. Implement activated hook to set this.title from useMeta() => this.title = this.post?.title ?? 'Default title' to fix step 12.
  14. Unfortunately, step 13 does not fix steps 4 and 9.

🌈 Expected behaviour
I expect ref properties from useMeta to be reactive.
Needing to use activated hook along with keep-alive to update the meta data is a gotcha so I don't know if it's intended. If so, add it into the documentation?

ℹ️ Additional context
I am still using apollo-client with @vue/apollo-composable instead of useFetch() to fetch the post data.

docs: explain useAsync 'refresh' strategy

πŸ› The bug
When use useAsync method in setup function, it puts loaded data in window.nuxt.ssrRefs

ssrContext.nuxt.ssrRefs = data

And when you go to another page (with vue router) and return back - nuxt doesn't send request again, because you still have preloaded data in window.nuxt.ssrRefs

πŸ› οΈ To reproduce
With SSR (universal) mode:

  1. Use useAsync in setup function, write some request here or add debugger
  2. After page loaded (requests completed) go to another page (with nuxt-link)
  3. Return back (browser's back button)
  4. You will see, that first opened in SSR page on returning doesn't execute code inside useAsync again. But it has to!

When you go to another pages everything works fine, because there is no hydration step in browser's useAsync implementation.

I'd be very grateful for a link to a gist or repo that reproduces the bug.
// @todo

🌈 Expected behaviour
I think window.nuxt.ssrRefs has to be cleared after hydration. Or maybe we could add some flag for this behaviour in useAsync function.

ℹ️ Additional context
Also this line of code looks really strange :)

data = Object.assign({}, {})

help: useMeta and TypeScript error

πŸ“š What are you trying to do? Please describe.

I've just tried to useMeta and I've put the head: {} into the component, but getting this typescript compile error:

TS2769: No overload matches this call.
  Overload 1 of 3, '(options: ComponentOptionsWithoutProps<unknown, { journal: Ref<JournalResult | null>; }, Data, {}, {}>): VueProxy<unknown, { journal: Ref<JournalResult | null>; }, Data, {}, {}>', gave the following error.
    Argument of type '{ head: {}; setup(this: void): { journal: Ref<JournalResult | null>; }; }' is not assignable to parameter of type 'ComponentOptionsWithoutProps<unknown, { journal: Ref<JournalResult | null>; }, Data, {}, {}>'.
      Object literal may only specify known properties, and 'head' does not exist in type 'ComponentOptionsWithoutProps<unknown, { journal: Ref<JournalResult | null>; }, Data, {}, {}>'.
  Overload 2 of 3, '(options: ComponentOptionsWithArrayProps<string, { journal: Ref<JournalResult | null>; }, Data, {}, {}, Readonly<{ [x: string]: any; }>>): VueProxy<...>', gave the following error.
    Argument of type '{ head: {}; setup(this: void): { journal: Ref<JournalResult | null>; }; }' is not assignable to parameter of type 'ComponentOptionsWithArrayProps<string, { journal: Ref<JournalResult | null>; }, 
Data, {}, {}, Readonly<{ [x: string]: any; }>>'.
      Object literal may only specify known properties, and 'head' does not exist in type 'ComponentOptionsWithArrayProps<string, { journal: Ref<JournalResult | null>; }, Data, {}, {}, Readonly<{ [x: string]: any; }>>'.
  Overload 3 of 3, '(options: ComponentOptionsWithProps<ComponentPropsOptions<Data>, { journal: Ref<JournalResult | null>; }, Data, {}, {}, ({ [x: number]: string; } & { length?: number | undefined; ... 30 more ...; flat?: unknown[] | undefined; }) | ({} & { ...; })>): VueProxy<...>', gave the following error.
    Argument of type '{ head: {}; setup(this: void): { journal: Ref<JournalResult | null>; }; }' is not assignable to parameter of type 'ComponentOptionsWithProps<ComponentPropsOptions<Data>, { journal: Ref<JournalResult | null>; }, Data, {}, {}, ({ [x: number]: string; } & { length?: number | undefined; ... 30 more ...; flat?: unknown[] | undefined; }) | ({} & { ...; })>'.
      Object literal may only specify known properties, and 'head' does not exist in type 'ComponentOptionsWithProps<ComponentPropsOptions<Data>, { journal: Ref<JournalResult | null>; }, Data, {}, {}, ({ [x: number]: 
string; } & { length?: number | undefined; ... 30 more ...; flat?: unknown[] | undefined; }) | ({} & { ...; })>'.
    34 | 
    35 | const journalSlug = defineComponent({
  > 36 |   head: {},
       |   ^^^^^^^^
    37 |   setup () {
    38 |     const { params, $content } = useContext();
    39 |     const slug = computed(() => params.value.slug);

Do I need to type cast the object literal? If I remove line 36 it complains, and I can't think of alternatives...

πŸ” What have you tried?
Have you looked through the docs? Tried different approaches? The more detail the better.

ℹ️ Additional context
Add any other context or information.

fix: calling `context.error()` from `useFetch` throws 'The client-side rendered virtual DOM tree is not matching server-rendered'

πŸ› The bug

When using onFetch hook that fails, we want to call NuxtContext.error to redirecto to 500 or 404 page.

However, this error triggers the following error in browser's console :

[Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.

Also, we can see a flash when loading the page due to the redirection being done on client-side.

πŸ› οΈ To reproduce

I made a codesandbox forked from the example in the docs.
https://codesandbox.io/s/youthful-bas-dfhu5?file=/pages/posts/_id.vue

When navigating on the /posts/404 page with SSR (refreshing the /posts/404 page from the codesandbox's inline-browser), we can see the error in the console.

Parent:  
<DIV data-fetch-key="0">…</DIV>

Mismatching childNodes vs. VNodes:  
NodeList {0: HTMLButtonElement, 1: Text, 2: HTMLHeadingElement, 3: Text, 4: HTMLParagraphElement…}

[VNode]

[Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.

🌈 Expected behaviour

The error should not occurs.

ℹ️ Additional context

As a workaround, we can redirect on client-side like this

    const { fetchState } = useFetch(async () => {
      throw new Error('Article not found')
    });

    watchEffect(() => {
      if (fetchState.error?.message === 'Article not found') {
        error({ statusCode: 404, message: 'Article not found' })
      }
    })

The console error disappears.
However, we can still see a flash when loading the page as this is a client-side only redirect.

fix: Warning "Cannot stringify a function..." when using useFetch

πŸ› The bug
When I use useFetch inside of a setup function that returns other functions (e.g. as event handlers), when the page is rendered on the server, the server starts to throw warnings along the lines of "WARN Cannot stringify a function bound onClick" (function name changes of course). This happens regardless of what I do in useFetch or if the exported function is actually used anywhere.

Interestingly, if I add a call to console.log anywhere in the setup function, the warning goes away, but the log is then printed twice (which doesn't happen without the useFetch).

πŸ› οΈ To reproduce
Minimal example that should reliably throw the warning on every page reload:

<template>
  <div />
</template>

<script lang="ts">
import { defineComponent, useFetch } from "nuxt-composition-api";

export default defineComponent({
  setup() {
    useFetch(() => {});

    function test() {}
    
    // uncomment this to silence the warning (and get 2 logs) 
    // console.log("test");

    return { test };
  },
});
</script>

🌈 Expected behaviour
Since this is the official approach to make event handlers available to the template and it's the way it's taught in the docs, this should just work without warnings.

ℹ️ Additional context
I noticed this first on the lastes release (0.10.2) but I can't say for sure if it happened before.

help: Dependency injection at the plugin level

πŸ“š What are you trying to do? Please describe.
I'm trying to provide a value on the root Vue instance, and then inject this inside the various components / pages / layouts.

πŸ” What have you tried?
I tried calling provide from setup() inside layouts/default.vueas was suggested in a couple of places, which kind of worked, but it doesn't look very clean to me (plus I'd need to have this code in every layout .... not very DRY)

I also tried creating a Nuxt plugin, which seemed like the proper way to do this, but the global provide / inject method described in the proposed RFC isn't available.

I also encountered the suggestion of assigning a new setup function to app, but this seems like it would break as soon as another plugin also assigns its own setup function.

ℹ️ Additional context
Having some kind of onSetup hook available in plugins or global provide would solve this kind of issue, people using vue-apollo-composable would have a cleaner way of providing the apollo client.

I'm not sure how dependency injection interacts with SSR and if provide could be used independently on the server and client Vue instance.

fix: import of ComponentInstance fails

πŸ› The bug

5:35 Cannot find module '@vue/composition-api/dist/component' or its corresponding type declarations.
    3 | import { Context } from '@nuxt/types';
    4 | import { Route } from 'vue-router';
  > 5 | import { ComponentInstance } from '@vue/composition-api/dist/component';
      |                                   ^
    6 | import { MetaInfo } from 'vue-meta';
    7 | 
    8 | /**

πŸ› οΈ To reproduce
"@vue/composition-api": "^0.6.1",
"nuxt-composition-api": "^0.9.0",

It seems like this type is not exported?

help: i dont want any development at all on my phone

πŸ“š What are you trying to do? Please describe.
A clear and concise description of your objective. Ex. I'm not sure how to [...].

πŸ” What have you tried?
Have you looked through the docs? Tried different approaches? The more detail the better.

ℹ️ Additional context
Add any other context or information.

docs: How should I use route, params and other reactive context data ?

πŸ“š Is your documentation request related to a problem? Please describe.
I need to to access a url param (an ID) that is needed in my page, to use it in the title (using useMeta) and for accessing a backend resource by this id with a Axxios call. This was previously simply working with route.params.id, now I don't know what to do, I get a "params is undefined" exception. I don't know if my code below is wrong or if there is a bug in this 0.7.0 change.

import { defineComponent, useContext, watch } from 'nuxt-composition-api'

export default defineComponent({
  layout: 'empty',
  head: {}, // needed for meta
  setup() {
    // params from context
    const { params } = useContext()

    function logParam(params: Dictionary<string>) {
      console.log("id = " + params.id)
    }
    watch(() => params.value, logParam);
  }
} 

πŸ” Where should you find it?
Vue-doc mention that these context properties are now reactive, but it could be interesting to complete the example app with all new features of this plugin.

ℹ️ Additional context
Add any other context or information.

help: setting a non-reactive const with useFetch()

FOA thanks for the module, was looking for this!

πŸ“š What are you trying to do? Please describe.
I'd like to set a const items[] as a result of the useFetch(). I explicitly want items array to be non-reactive to prevent performance issues while observing a huge array.

Using Apollo in a regular Vue CLI app I'm able to achieve this with:

const { result, loading } = useQuery(aQuery);

so while result is not set, I can use loading. I see there is no simple way to achieve this.

My global aim is to refactor an existing Nuxt.js app with less reactivity. Am I looking to the right direction at all?

Oh and BTW, a check for globalName from the Nuxt config would be nice )

help: Is there a way to use Jest with 'nuxt-composition-api'

Hello,

I'm trying to test a component using 'nuxt-composition-api' with Jest.

I'm wondering if there is a tip to mock 'nuxt-composition-api' with '@vue/composition-api' to be able to test.

Error message:

/home/shenron/Documents/dev/workspaces/js/vue/vue-nuxt-tsx/node_modules/nuxt-composition-api/lib/index.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import { resolve, join } from 'path';
                                                                                             ^^^^^^

    SyntaxError: Cannot use import statement outside a module

TypeError: Module should export a function: nuxt-composition-api

Hi

I was looking in to the library today. Thank you for bringing this module to life.

Problem:

It seems there are problems with the module initialization in nuxt.

Solution

const compositionApiModule: Module<any> = function () {
 // do something
}

export default compositionApiModule

May I can add a PR - have fixed some parts.

Regards

feat: defineNuxtPlugin

πŸ†’ Your use case
When writing a typed Nuxt plugin, developer currently needs to do this:

import { Plugin } from '@nuxt/types';
const plugin: Plugin = (ctx) => {
   //
};
export default plugin;

The downside is that export is separate from definition.

πŸ†• The solution you'd like
A type helper would be nicer, e.g.:

import { defineNuxtPlugin } from 'nuxt-composition-api';
export default defineNuxtPlugin((ctx) => {
  //
});

I propose defineNuxtPlugin and not just definePlugin, because Vue itself has a concept of plugins, so there is a possibility for export name conflicts.

fix: [Vue warn]: Write operation failed: computed value is readonly.

πŸ› The bug
At the moment, if a component that calls useFetch has a computed property returned from setup, it will give the following error:

[Vue warn]: Computed property was assigned to but it has no setter.

It still works correctly, but this is unattractive, and ideally we wouldn't be attempting to assign a value to a computed property at all.

fix: not working with @vue/composition-api#1.0.0-beta.2

πŸ› The bug
What isn't working? Describe what the bug is.

I tried to spin up the nuxt typescript example with the latest @vue/composition-api version. get:

 FATAL  The requested module 'file:///Users/shauncutts/src/other/nuxt-typescript/examples/composition-api/minimal/node_modules/@vue/composition-api/index.js' does not provide an export named 'createComponent'

  import { resolve, join } from 'path';
  
  SyntaxError: The requested module 'node_modules/@vue/composition-api/index.js' does not provide an export named 'createComponent'
  at Object.<anonymous> (node_modules/nuxt-composition-api/lib/index.js:1)
  at Generator.next (<anonymous>)
  at Resolver.requireModule (node_modules/@nuxt/core/dist/core.js:609:31)
  at ModuleContainer.addModule (node_modules/@nuxt/core/dist/core.js:174:38)
  at node_modules/@nuxt/utils/dist/utils.js:1821:43
  at async ModuleContainer.ready (node_modules/@nuxt/core/dist/core.js:45:7)
  at async Nuxt._init (node_modules/@nuxt/core/dist/core.js:699:5)

πŸ› οΈ To reproduce
Steps to reproduce the behavior:

  1. clone from https://github.com/nuxt/typescript.git
  2. modify as follows (though the port 3003 is obviously not germane):
diff --git a/examples/composition-api/minimal/nuxt.config.js b/examples/composition-api/minimal/nuxt.config.js
index 79a94bb..4e0c39e 100644
--- a/examples/composition-api/minimal/nuxt.config.js
+++ b/examples/composition-api/minimal/nuxt.config.js
@@ -1,4 +1,5 @@
 export default {
-  buildModules: ['@nuxt/typescript-build'],
-  plugins: ['~/plugins/composition-api']
+  buildModules: ['@nuxt/typescript-build',
+    'nuxt-composition-api'],
+  // plugins: ['~/plugins/composition-api']
 }
diff --git a/examples/composition-api/minimal/package.json b/examples/composition-api/minimal/package.json
index 1a04faa..22a717a 100644
--- a/examples/composition-api/minimal/package.json
+++ b/examples/composition-api/minimal/package.json
@@ -4,10 +4,11 @@
   "private": true,
   "dependencies": {
     "@vue/composition-api": "latest",
-    "nuxt": "latest"
+    "nuxt": "latest",
+    "nuxt-composition-api": "^0.10.3"
   },
   "scripts": {
-    "dev": "nuxt",
+    "dev": "nuxt --port 3003",
     "build": "nuxt build",
     "start": "nuxt start",
     "generate": "nuxt generate",
@@ -16,5 +17,8 @@
   "devDependencies": {
     "@nuxt/types": "latest",
     "@nuxt/typescript-build": "latest"
+  },
+  "resolutions": {
+    "@vue/composition-api": "1.0.0-beta.2"
   }
 }

I'd be very grateful for a link to a gist or repo that reproduces the bug.

🌈 Expected behaviour
What did you expect to happen? Is there a section in the docs about this?

To work...

ℹ️ Additional context
Add any other context about the problem here.

I presume the 1.0.0 vue Composition API makes some breaking changes ... this is a heads up.

help: useFetch - Cannot read property 'isPreview' of undefined

πŸ“š What are you trying to do? Please describe.
I was trying to transition into using the composition API and was going to use fetch but when I use it i get this error:

TypeError: Cannot read property 'isPreview' of undefined

πŸ” What have you tried?
This was my previous apprach before composition:

    async fetch () {
        this.getEpisodes();
    },
    activated () {
        // Call fetch again if last fetch more than 30 sec ago
        if (this.$fetchState.timestamp <= (Date.now() - 60000)) {
            this.$fetch()
        }
    }, 

this is my new approach in transtition:

        const { $fetch, $fetchState } = useFetch(async () => {
            getEpisodes()
        })

        onActivated(() => {
            // Call fetch again if last fetch more than 30 sec ago
            if ($fetchState.timestamp <= (Date.now() - 60000)) {
                $fetch()
            }
        })

ℹ️ Additional context
The getEpisodes method:

        let getEpisodes = async function (page) {
            const { data, meta } = await $axios.$get('/api/shows/details/episodes',  { params: { id: params.value.id, page: page } });

            info.episodes = data;
            info.pagination = {
                current_page: meta.current_page,
                last_page: meta.last_page,
                total: meta.total,
                per_page: meta.per_page,
                from: meta.from,
                to: meta.to
            }
        }

Upon looking fetch would be called client side and does call the getEpisodes method so i think it has to be something server sided

feat: use customRef

In the latest releases of @vue/composition-api we got custom-ref. With this we can optimize ssrRef and other helpers.

I will look into it.

fix: useFetch's does not implement static target (payload is not saved)

πŸ› The bug
When using useFetch hook and generating a full-static build (target: static) and nuxt export, the useFetch payload is not saved.

πŸ› οΈ To reproduce

pages/test.vue

export default defineComponent({
  setup () {
    const name = ref('')

    useFetch(async () => {
      name.value = await axios.get('https://myapi.com/name')
    })
  }
})

nuxt.config.js

export default {
  target: 'static'
}

yarn run nuxt build && yarn run nuxt export && http-server dist && xdg-open localhost:8080

When I load index and navigate to the page test, I can see the network request in the Network tab of the browser.

🌈 Expected behaviour

The HTTP request should not be executed on client-side.

ℹ️ Additional context

I know there is useStatic but it does not allow to set a server target (if you want to make a second build which get data from client-side), does not support enablePreview, and other features implemented by nuxt static mode.
Also, useStatic requires code changes (which is specific to this package) instead of the useFetch implementation which has the same behavior as Nuxt's Options API.

Btw, thanks for this module :) It's awesome to combine the Composition API with Nuxt ! πŸŽ‰

withContext doesn't look right

The problem I have with withContext is that my code doesn't look so clean and linear anymore.

The callback gets called immediatly so why use a callback?

I think we should provide useContext:

import { getCurrentInstance } from '@vue/composition-api'

export const useContext = () => {
  const vm = getCurrentInstance()
  if (!vm) throw new Error('This must be called within a setup function.')

  return vm.$nuxt.context
}

withContext

  setup() {
    const post = ref({})

    withContext(({ $http, route }) => {
      useFetch(async () => {
        post.value = await $http.$get(
          `https://jsonplaceholder.typicode.com/posts/${route.params.id}`
        )
      })
    })

    return { post }
  }

useContext

  setup() {
    const post = ref({})

    const { $http, route }  = useContext()

    useFetch(async () => {
      post.value = await $http.$get(
        `https://jsonplaceholder.typicode.com/posts/${route.params.id}`
      )
    })

    return { post }
  }

BTW: is useFetch the right name it suggest that it returns something

I want to setting the metaInfo before client side render~

πŸ“š What are you trying to do? Please describe.
I want to setting the metaInfo before client side render~

I see the doc, use the useMeta funciton;

It can run, but it is not accord with my expect.

I expect the metaInfo can generate before the page client rendered

image

i think the metaInfo can run in fetch function inside can fixed it

image

πŸ” What have you tried?
I try to use three functions to do, but not one can resolve my problem;

  1. useAysnc
  2. useFetch
  3. onServerPrefetch

docs: example of how to use with component lifecycle events

πŸ“š Is your documentation request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I feel I should be able to [...] but I can't see how to do it from the docs.

The issue from which composition-api sprung concerned component lifecycle events. This package seems to solve some of the problems, but I'm wondering what to do about mounted and beforeDestroy ... when are they called wrt to setup() and how to interact with them?
πŸ” Where should you find it?
What page of the docs do you expect this information to be found on?

ℹ️ Additional context
Add any other context or information.

I am trying to use tiptap example here: ueberdosis/tiptap#131 (comment) I want to use state that is wired up in setup() in mounted(). Or simply do something "composition-api-like" instead of beforeDestroy.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.