Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

it's hard for developer to write a common component with vue-demi #153

Open
xuemanchi opened this issue Apr 15, 2022 · 17 comments
Open

it's hard for developer to write a common component with vue-demi #153

xuemanchi opened this issue Apr 15, 2022 · 17 comments

Comments

@xuemanchi
Copy link

【description】:
I want to try create the same component for Vue2 & Vue3 in the same source code, so I find vue-demi. But.. I have seen some projects likes json-editor-vue. For compact Vue2 & Vue3, I found its source code write render options for 2 & 3. But i think it's hard for developer to code.

I prefer to code in template in a sfc file. So i have some idea(We can smooth the difference with Vue2 & Vue3 when we compile components). Can we write a component with setup & composition-api in a sfc. And then when we compile the component, we can use a series of plugins for Vue2: unplugin-auto-import, unplugin-vue2-script-setup, vite-plugin-vue2, [email protected], and plugins for Vue3: @vitejs/plugin-vue.

@antfu Maybe u have thought some idea before create this repo. So can u give me some advice or info?

@antfu
Copy link
Member

antfu commented Apr 15, 2022

I would suggest directly shipping SFC to npm and let userland plugin to compile it.

@xuemanchi
Copy link
Author

xuemanchi commented Apr 15, 2022

I would suggest directly shipping SFC to npm and let userland plugin to compile it.

Thanks for ur reply.
This is also a way to resolve. I think i may find a way to implement .
How about create a monorepo, one package to create SFC, and a package to compile it for Vue2, a package to compile it for Vue3. :bowtie:

@wobsoriano
Copy link
Contributor

wobsoriano commented Apr 15, 2022

Use unbuild for shipping the component directly

@xuemanchi
Copy link
Author

Thanks! I will use it for my project.

@rorry121
Copy link

rorry121 commented Jun 24, 2022

Use unbuild for shipping the component directly

@wobsoriano any example?

@sadeghbarati
Copy link

sadeghbarati commented Jul 21, 2022

I have the same problem, I prefer to code in SFC syntax too

I'm using v-once ( head to JS tab on sfc playground ) directive on SFC component ( for example Vue component for datatables.net )

I would suggest directly shipping SFC to npm and let userland plugin to compile it.

  • requires to add "type": "module" in package.json

  • Component must be defined separate exports field in package.json ( separate from other compiled files, if component use hook or composable )


Compiled component.vue

vue 2.6 vite-plugin-vue2:

Vue 2 Component.vue

vue 2.7 @vitejs/plugin-vue2 :

Vue 2 7 Component.vue

vue 3 @vitejs/plugin-vue:

Vue 3 Component.vue

@sadeghbarati
Copy link

sadeghbarati commented Jul 21, 2022

Use unbuild for shipping the component directly

unbuild is good with .ts defineComponent and composable, at this time it's not compatible with .vue files

unjs/unbuild#80

@Hisioni
Copy link

Hisioni commented Nov 24, 2022

have u find the way use monorepo to adapt to use vue-demi for SFC?
i try to this but when i use vite-plugin-dts generate d.ts there still have many compatibility issues.

@sadeghbarati
Copy link

sadeghbarati commented Nov 25, 2022

have u find the way use monorepo to adapt to use vue-demi for SFC? i try to this but when i use vite-plugin-dts generate d.ts there still have many compatibility issues.

Hi,

Unfortunately no, I end up using defineComponent(.ts) way instead of SFC(.vue) files


for monorepo answer can be yes, but it questions the duty of vue-demi

- packages/
  -- vue3
  -- vue2

@Hisioni
Copy link

Hisioni commented Nov 26, 2022

have u find the way use monorepo to adapt to use vue-demi for SFC? i try to this but when i use vite-plugin-dts generate d.ts there still have many compatibility issues.

Hi,

Unfortunately no, I end up using defineComponent(.ts) way instead of SFC(.vue) files

for monorepo answer can be yes, but it questions the duty of vue-demi

- packages/
  -- vue3
  -- vue2

Yeah, still I am same problem with the questioner, use TS render way it's hard to my team, we perfer to SFC more, then will use antfu says that publish components, use different project v2, v2.7, v3 to build it, use git branch to manage it.

@sadeghbarati
Copy link

this issue also related to this pull-request

#154

@sadeghbarati
Copy link

@Hisioni can you share your vue-demi repo? If it possible

@Hisioni
Copy link

Hisioni commented Nov 26, 2022

@Hisioni can you share your vue-demi repo? If it possible

Of course, in this repository, still have question, i don't know how to config to generate d.ts on every vue version

@sadeghbarati
Copy link

sadeghbarati commented Dec 12, 2022

have u find the way use monorepo to adapt to use vue-demi for SFC? i try to this but when i use vite-plugin-dts generate d.ts there still have many compatibility issues.

@Hisioni I have same issue too, I thought generating types only required once with Vue3 as main version in package.json

the error I got when installing vue-demi lib on vue2.7 project I think it was editor problem
Generic type 'DefineComponent' requires between 0 and 11 type arguments.

However, autocomplete props on component only pops up on Vue3 (using Volar)

Found an example for handling type definitions separately 😨 also installed this package on Vue2 app autocomplete props are not showing only showed up on Vue3
https://github.com/alibaba/formily/tree/formily_next/packages/vue

an example that autocompletes props are showing up ctrl + space on Vue2.6
https://github.com/DanSnow/vue-recaptcha


https://discord.com/channels/793943652350427136/1052340776186695751

@Shimada666
Copy link
Contributor

You can refer to my project, I believe I have explored a relatively elegant solution. It allows you to use the script setup syntax and other latest Vue3 syntax to develop a universal component library. The idea is to package different versions together and use the postinstall script to distinguish the user's Vue version and release the corresponding build files.
https://github.com/Shimada666/vue-demi-sfc-component-template

@sadeghbarati
Copy link

sadeghbarati commented Jan 18, 2023

For vue-demi components, it's better to use local registration over global registration, because of this 👇

// global.d.ts or volar.d.ts

declare module '@vue/runtime-core' {  // Vue 3
// declare module 'vue' {   // Vue 2.7
// declare module '@vue/runtime-dom' {  // Vue <= 2.6.14
  export interface GlobalComponents {
    GlobalComponent: typeof import('***')['GlobalComponent']
  }
}

export {}

or you can define preset/resolver for unplugin-vue-components in your package


  • For showing autocomplete props on Vue3 and Vue2.7 component check vue-bridge ( how to generate d.ts files )

  • Also check this one https://www.npmjs.com/package/@smooth-scrollbar-contrib/vue-test?activeTab=explore based on vue-bridge idea

    unbuild config
    import { promises as fsp } from 'fs'
    import { join, resolve } from 'pathe'
    import { definePreset } from 'unbuild'
    
    const clientPreset = definePreset({
      clean: true,
      externals: [
        'vue',
        'vue-demi',
        'smooth-scrollbar',
        '@vueuse/core',
        '@vueuse/shared',
      ],
      rollup: {
        emitCJS: true,
      },
      failOnWarn: false,
    })
    
    const versions = ['v2.6', 'v2.7', 'v3']
    
    async function buildVue() {
      const { build } = await import('unbuild')
      for (const version of versions) {
          await build('.', false, {
            entries: ['src/index'],
            outDir: `dist/${version}`,
            preset: clientPreset,
            declaration: version === 'v3',
            hooks: {
              'build:prepare': async (ctx) => {
                const indexFile = resolve(join(ctx.options.rootDir, 'src/component/index.ts'))
                const versionContent = await fsp.readFile(resolve(join(ctx.options.rootDir, `src/component/${version}.ts`)), 'utf8')
    
                await fsp.writeFile(indexFile, versionContent, 'utf8')
              },
              'build:done': async (ctx) => {
                if (version === 'v2.6' || version === 'v2.7') {
                  const dtsFilePath = resolve(join(ctx.options.rootDir, `dist/${version}`, 'index'))
                  await fsp.writeFile(`${dtsFilePath}.d.ts`, ["export * from '../src/index'"].join('\n'))
                }
              },
            },
          })
        }
    }
    
    buildVue().catch((err) => {
      console.error(err)
      process.exit(1)
    })

Vue3:

// declaration: true
// dist/index.d.ts
import * as vue_demi from 'vue-demi';

declare const Component: vue_demi.DefineComponent<{...}>;

Vue2.7:

// custom index.d.ts
// dist/index.d.ts
// link to source file instead of generating d.ts file

export * from '../src/index'

Warn the user to not use __VUE_OPTIONS_API__: false in their bundler option, since vue-demi package is mixed with Option APIs and Composition APIs

@andresilva-cc
Copy link

I've been trying to make universal components with Vue and using the hints from here I could make it work. The nice thing is that we don't need to write our template by manually calling the h function, which is ugly and hard to maintain, you can use JSX which will compile to the h-demi function that @dnldsht created. There are a lot of little details and they are all described on the README of the repo below, so feel free to read and test it for yourself:

https://github.com/andresilva-cc/poc-vue-universal-component

It is not fully polished, it probably lacks some features, but it's working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants