inertia icon indicating copy to clipboard operation
inertia copied to clipboard

Convert Inertia Vue 2 & 3 adapters to TypeScript

Open ycs77 opened this issue 3 years ago • 10 comments

based on #770

When developing this PR, I found that now Vue 2 adapter only uses Options API, while Vue 3 can use both Options and Composition API, which will be confusing when developing, so I supported the Composition API for Vue 2 adapter for this reason. Although the number of users may not be more, this can unify the Vue 2 / 2.7 / 3 versions of the API, and both the Options API and Composition API can be used at the same time, reducing the cost of conversion when developing, and the introduction in the documentation will also be clearer.

Has a package called vue-demi, I have tested this package to develop vue adapter, I think maybe merge the @inertiajs/inertia-vue and @inertiajs/inertia-vue3, but the code base difference of Vue 2/3 adapters is too big, finally, give up merge it.

Note Update on 2022/07/14: now support the Vue 2.7 support Composition API without @vue/composition-api, use the vue-demi to support both Vue 2 & 2.7 (only use vue-demi in vue 2 version)

For the test part, because there are 4 ways to use the vue adapter, adding Cypress test will be very time-consuming, so we are using PingCRM for now. can see if has plans to increase the test in the future.

I have some examples of using Vue x TypeScript below, and I hope to add them to the documentation after modifying them as a basis.

Any suggestion for this PR? 🤔


⭐ Main Changes

  • Vue 2 adapter
    • Support TypeScript
    • Support Composition API
      • can use usePage(), useForm(), useRemember()
      • if you use Composition API or not, the @vue/composition-api will always be installed.
  • Vue 3 adapter
    • Support TypeScript
  • Other
    • Update microbundle to ^0.14.0, will update typescript to ^4.1.3 (microbundle@^0.12.0 dependents the typescript ^3.9, version too old)
    • Add cross-env to tests to support run cypress:open on Windows OS
    • Add --stages flag to wsrun, will build main @inertiajs/inertia before other packages. (build all packages, in stages, starting from those that don't depend on other packages.) see: https://github.com/hfour/wsrun#examples

⭐ Vue versions & APIs

The Vue now has 2 main versions and 2 style APIs, there are 4 ways to use them:

  • Vue 2 + Options API
  • Vue 2 + Composition API
  • Vue 3 + Options API
  • Vue 3 + Composition API

Only the Vue 2 + Composition API does not have built-in support, so use the @vue/composition-api.

Anyway, you can use the above 4 ways to use Inertia.

PingCRM demo:


⭐ Develop or Try it!

The above PingCRM demo is all using the released version of inertia, if you want to try this PR, clone this branch to local:

git clone https://github.com/ycs77/inertia.git
cd inertia
git checkout inertia-vue23-ts
yarn
yarn build

use Vue 2 version (Don't use yarn link, and must change the [inertia-path]):

# move to vue 2 pingcrm
# fallow the pingcrm README installation...
yarn add @inertiajs/inertia@file:../[inertia-path]/inertia/packages/inertia
yarn add @inertiajs/inertia-vue@file:../[inertia-path]/inertia/packages/inertia-vue
yarn dev
yarn ssr:serve
php artisan serve

use Vue 3 version (Don't use yarn link, and must change the [inertia-path]):

# move to vue 3 pingcrm
# fallow the pingcrm README installation...
yarn add @inertiajs/inertia@file:../[inertia-path]/inertia/packages/inertia
yarn add @inertiajs/inertia-vue3@file:../[inertia-path]/inertia/packages/inertia-vue3
yarn dev
yarn ssr:serve
php artisan serve

⭐ Known Issue

Layout Function has type error on Vue 3

Now can't direct use Layout Function on Vue 3, must add the Layout Function type to complete the type hint and clear error:

<script lang="ts">
import { LayoutFunction } from '@inertiajs/inertia-vue3/types/app'

export default defineComponent({
  layout: ((h, child) => h(child)) as LayoutFunction,
})
</script>

I think this API must be re-design in Composition API, defineLayout() (#1117) is an API that I think is more feasible.

And the function can use Generic and Method Overriding, friendly to TypeScript.

Of course, this issue needs further discussion...


⭐ User Guide (Docs)

With Vue 2 (<=2.6)

Must be added the alias of @vue/composition-api after upgrade @inertiajs/inertia and @inertiajs/inertia-vue:

webpack.config.js

module.exports = {
  resolve: {
    alias: {
      '@vue/composition-api$': path.resolve('./node_modules/@vue/composition-api/dist/vue-composition-api.mjs'),
    },
  },
}

The @vue/composition-api is installed and run the Vue.use() in inertia-vue, Don't re-use in your application.

But if you want to use Composition API in your Vue 2 application, can be added @vue/composition-api todependencies of package.json.

With Vue 3

Upgrade @inertiajs/inertia and @inertiajs/inertia-vue3 to latest version.

Composition API

usePage()

Get page value with Composition API:

import { usePage } from '@inertiajs/inertia-vue3'

// Usage 1:
const { props } = usePage()
console.log(props.value.name) // "Your Name"

// Usage 2:
// If define Vue's props variable, there will be a conflict, so you need to define other variable names.
const { props: pageProps } = usePage()
console.log(pageProps.value.name) // "Your Name"

// Usage 3:
// If use `reactive()` wrap the `usePage()`, no need to add the `.value`.
const page = reactive(usePage())
console.log(page.props.name) // "Your Name"

Follow Best Practice | VueUse.

TypeScript

Define Global Page Props Types

Create a resources/js/inertia.d.ts file, and add the global page props types:

declare module '@inertiajs/inertia' {
  interface PageProps {
    auth: {
      id: number
      name: string
      email: string
    }
    flash: {
      success: string | null
      error: string | null
    }
  }
}

export {}

It should be noted that it cannot be added to env.d.ts, otherwise it will be invalid.

usePage()

Define current page props type:

const { props } = usePage<{ myName: string }>()

props.value.myName // string

If you has define the global page props type, can direct use the props:

const { props } = usePage()

props.value.auth.id // number

Recommended IDE Setup

ycs77 avatar Mar 24 '22 22:03 ycs77

Thanks for picking this up! 🚀

NickSdot avatar Apr 01 '22 02:04 NickSdot

Added the Vue 2.7 support

ycs77 avatar Jul 14 '22 09:07 ycs77

Curious if/when this is going to be merged, the Vue 2 adapter updates (usePage(), etc.) for the new composition API support and <script setup> would be extremely useful.

benjivm avatar Jul 21 '22 18:07 benjivm

Curious if/when this is going to be merged, the Vue 2 adapter updates (usePage(), etc.) for the new composition API support and <script setup> would be extremely useful.

@reinink @claudiodekker

ycs77 avatar Jul 25 '22 15:07 ycs77

@reinink any chance to have composition API in vue 2.7?

makroxyz avatar Sep 20 '22 13:09 makroxyz

@ycs77 wow this is a ton of work, thanks! I'm worried that it might be very out of sync with my current next branch, and I'm not sure I want to implement TS for the Vue adapters quite yet, but I'd love to get this PR rebased against the next branch if you'd be willing – just so I can use it as a reference for now? Thanks! 🙏

reinink avatar Sep 20 '22 23:09 reinink

@reinink any chance to have composition API in vue 2.7?

@makroxyz Yup! I'm actively working on making that happen — see #1282 👍

reinink avatar Sep 22 '22 11:09 reinink

@ycs77 wow this is a ton of work, thanks! I'm worried that it might be very out of sync with my current next branch, and I'm not sure I want to implement TS for the Vue adapters quite yet, but I'd love to get this PR rebased against the next branch if you'd be willing – just so I can use it as a reference for now? Thanks! 🙏

Of course~😊

ycs77 avatar Sep 23 '22 12:09 ycs77

@ycs77 You're also welcome to just wait until I finish the next PR and then we can figure out where to go from there — your call. I'm kind of hoping that we can add composition API (and <script setup>) support without having to add the vue-demi library to the project, since I think we can use the Vue 2.7 APIs for the hooks that will only work in Vue 2.7 projects anyway, but maybe I'm wrong?

reinink avatar Sep 23 '22 15:09 reinink

@reinink

You're also welcome to just wait until I finish the next PR and then we can figure out where to go from there.

No problem! waiting for you to finish.

I'm kind of hoping that we can add composition API (and

I think you are right. If the composition API is the main thing in the future, you can abandon Vue 2.6 and use 2.7.

ycs77 avatar Sep 23 '22 16:09 ycs77