v-wave icon indicating copy to clipboard operation
v-wave copied to clipboard

Nuxt 3 Support

Open razorness opened this issue 2 years ago • 4 comments

For people who are struggling using VWave with Nuxt 3

There are two problems with the current implementation:

  • VWave needs to implement getSSRProps.
  • The method serialize does not exist in /nuxt/plugin.js: https://github.com/justintaddei/v-wave/blob/34f26b639a306ef91b287c53785b8f4a38dbc642/nuxt/plugin.js#L4

So here is a workaround

  • Create a new file in plugins folder, fe: plugins/vWave.directive.ts
  • Paste this snippet:
import { defineNuxtPlugin } from '#app';
import VWave from 'v-wave';

// In this example, we rename the directive to `ripple`
const directiveName = 'ripple';

export default defineNuxtPlugin((app) => {

	const { vWave, vWaveTrigger } = VWave.createLocalWaveDirective({}, app.vueApp);

	app.vueApp.directive(directiveName, {
		...vWave,
		getSSRProps(binding, vnode) {
			return {};
		}
	});
	app.vueApp.directive(`${directiveName}-trigger`, {
		...vWaveTrigger,
		getSSRProps(binding, vnode) {
			return {};
		}
	});

});

That's it. Touching nuxt.config.ts is not needed.

razorness avatar Jul 25 '22 11:07 razorness

Thank you for bringing this to my attention! I'll release support for Nuxt 3 in the next ~~day or two~~ week or two.

justintaddei avatar Jul 26 '22 18:07 justintaddei

Hi @justintaddei, how is the progress going on supporting Nuxt 3?

DamianGlowala avatar Sep 28 '22 13:09 DamianGlowala

@DamianGlowala delayed, but not forgotten. I haven't had a chance to work on this yet, but I plan to soon.

justintaddei avatar Sep 29 '22 06:09 justintaddei

If anyone knows how to make this change with backwards compatibility for Nuxt 2 please let me know.

justintaddei avatar Sep 29 '22 06:09 justintaddei

@justintaddei It's better you create another git repo for NuxT 3+ versions.

RejownAhmed avatar May 21 '23 17:05 RejownAhmed

After some research, it seems impossible to support both Nuxt 2 and 3 in the same package.

Going forward:

  • I will migrate to Nuxt 3 for @latest releases. This will be a breaking change and bump the version to v2.0.0
  • Nuxt 2 support will continue in a separate branch and will continue to be released under v1.x version numbers and tagged with @nuxt2 to allow for easy installation in Nuxt 2 projects ($ npm install v-wave@nuxt2).
  • Nuxt 2 and 3 versions will maintain feature parody.
  • v-wave has always maintained backwards compatibility in the past. For future changes, this will be a requirement due to the use of v1.x for Nuxt 2 and v2.x for Nuxt 3. The v-wave API has been stable for a long time now, so I don't see this causing any issues.

Migration to Nuxt 3 will take place sometime in the next few weeks, depending on my schedule.

justintaddei avatar Jun 07 '23 17:06 justintaddei

Nice ! I am impatient to see that, your plugin is really usefull for me ! Thx for your work ❤️

NtchPlayer avatar Jun 24 '23 15:06 NtchPlayer

@razorness Hey, do you have a working workaround for this project (https://github.com/justintaddei/v-shared-element/issues/244) as well (Should be the same issue)? Unfortunately, I can't get it to work myself :( It would be really awesome if that's possible. Many thanks in advance and best regards.

yldshv avatar Aug 16 '23 11:08 yldshv

@yldshv I am not using Nuxt. Sorry.

But take a short look into the example. You can access the Vue app instance via app.vueApp. Take another look into the install method of your wanted Vue 3 extension:

https://github.com/justintaddei/v-shared-element/blob/5ab337b02b669bcbbd029f842d41651df7a6356d/src/index.ts#L151-L156

Since v-shared-element is a little stingy with exports, I think you need to trick the install method by mocking an object which looks like a Vue 3 app instance to catch illusory, $createIllusoryElement and the result of insertedMounted(). Then add this by yourself like the example above.

SharedElementRouteGuard could be bound via defineNuxtRouteMiddleware. Dont apply this guard in SSR context.

razorness avatar Aug 17 '23 10:08 razorness

@yldshv I am not using Nuxt. Sorry.

But take a short look into the example. You can access the Vue app instance via app.vueApp. Take another look into the install method of your wanted Vue 3 extension:

https://github.com/justintaddei/v-shared-element/blob/5ab337b02b669bcbbd029f842d41651df7a6356d/src/index.ts#L151-L156

Since v-shared-element is a little stingy with exports, I think you need to trick the install method by mocking an object which looks like a Vue 3 app instance to catch illusory, $createIllusoryElement and the result of insertedMounted(). Then add this by yourself like the example above.

SharedElementRouteGuard could be bound via defineNuxtRouteMiddleware. Dont apply this guard in SSR context.

Thank you @razorness. I will give it a shot :D

yldshv avatar Aug 17 '23 13:08 yldshv

Hey everyone! I just wanted to leave an update here. I haven't forgotten about this :)

Nuxt 3 support is still planned but I cannot give an ETA at this time. As soon as my schedule clears up, I will begin working on it.

justintaddei avatar Sep 06 '23 22:09 justintaddei

Hi @justintaddei ! Did you have any news about a potential planification for Nuxt 3 support ? I'm a little impatient to implement it into my web site :3

NtchPlayer avatar Oct 21 '23 18:10 NtchPlayer

@NtchPlayer tentatively planned for the first week of November!

justintaddei avatar Oct 23 '23 05:10 justintaddei

Hi everyone!

I've had an idea that would allow for nuxt2 and nuxt3 installs with the same version of v-wave. This removes the necessity of the breaking change detailed in this comment.

I came up with this approach after not having much luck creating a nuxt module that can exist alongside a vanilla vue plugin. That is, I don't want to use nuxt's module builder because this isn't a nuxt module... it's a vue plugin with nuxt support. If anyone has more experience working with modules in nuxt 3 and knows how to achieve the same behavior that exists for nuxt 2, please enlighten me :)

!!! I'm not sure if this is a good solution. Please provide feedback if you don't like this approach !!!

You can test this locally by installing v-wave@beta: $ npm i v-wave@beta

nuxt@^2.x.x installation steps remain the same and still use the @latest release.

When installing v-wave into a nuxt3 project, a postinstall script is run that will create the necessary plugin files (this is all that is needed for v-wave to work inside of nuxt because auto-import will pick these up):

The file that registers the plugin (this will also be where global v-wave options are set):

// v-wave.client.ts
import vWave, { type IVWavePluginOptions } from 'v-wave'

export const options: Partial<IVWavePluginOptions> = {
    // Place any global v-wave options here
}

export default defineNuxtPlugin((nuxtApp) => {
    nuxtApp.vueApp.use(vWave, options)
})

And a stub that is needed when registering directives:

(https://nuxt.com/docs/guide/directory-structure/plugins#vue-directives) If you register a Vue directive, you must register it on both client and server side unless you are only using it when rendering one side. If the directive only makes sense from a client side, you can always move it to ~/plugins/my-directive.client.ts and provide a 'stub' directive for the server in ~/plugins/my-directive.server.ts.

// v-wave.server.ts
import { options } from './v-wave.client';

export default defineNuxtPlugin(({ vueApp }) => {
    vueApp.directive(options.directive ?? 'wave', {});
    vueApp.directive(`${options.directive ?? 'wave'}-trigger`, {});
});

A fresh nuxt 3 project with v-wave installed: image

So far the install script is as follows (this will need to be more robust before it's ready for a stable release, but it gets the point across at least):

const fs = require('fs')
const path = require('path')

const pkg = require(path.join(process.env.INIT_CWD, 'package.json'))

const nuxtVersion = pkg.dependencies?.nuxt ?? pkg.devDependencies?.nuxt

if (!nuxtVersion || /2\.\d+\.\d+/.test(nuxtVersion)) {
  process.exit(0)
}

if (!fs.existsSync(path.join(process.env.INIT_CWD, 'plugins'))) {
  fs.mkdirSync(path.join(process.env.INIT_CWD, 'plugins'))
}

try {
  fs.copyFileSync(
    path.join(__dirname, 'v-wave.client.ts'),
    path.join(process.env.INIT_CWD, 'plugins', 'v-wave.client.ts'),
    fs.constants.COPYFILE_EXCL
  )
  fs.copyFileSync(
    path.join(__dirname, 'v-wave.server.ts'),
    path.join(process.env.INIT_CWD, 'plugins', 'v-wave.server.ts'),
    fs.constants.COPYFILE_EXCL
  )
} catch (e) {
  process.exit(0)
}

justintaddei avatar Nov 07 '23 10:11 justintaddei

However, on second thought, the better approach might just be to provide the boilerplate for nuxt in the readme instead of dealing with the complexity of auto-generating the file.

What do you guys think?

justintaddei avatar Nov 07 '23 21:11 justintaddei

Hum, I have any experience with Nuxt module creation :'( A create some directive for me (image lazy loading as exemple). I never take time to try to create my own plugin. I don't know if you can get more help on the [nuxt official discord server] ? (https://discord.com/invite/nuxt) (oh, I just see that you already join it today ^^)

I can say that, I use vue masonry on my project, and I have two configuration (one for the server side and one for client side like you suggest) because vue masonry works only on client side.

// @/plugins/vue-masonry.js
export default defineNuxtPlugin(async (nuxtApp) => {
  if (process.server) {
    nuxtApp.vueApp.directive('masonry', {})
    nuxtApp.vueApp.directive('masonry-tile', {})
  }
  if (process.client) {
    const { VueMasonryPlugin } = await import('vue-masonry')
    nuxtApp.vueApp.use(VueMasonryPlugin)
  }
})

NtchPlayer avatar Nov 07 '23 22:11 NtchPlayer

Thanks @NtchPlayer. Yeah, I joined the discord and asked around but nothing useful has come of that yet.

justintaddei avatar Nov 08 '23 07:11 justintaddei

Currently, what works for me perfectly fine is the following plugin:

import VWave from "v-wave";

const directiveName = "ripple";

export default defineNuxtPlugin((app) => {
    const { vWave, vWaveTrigger } = VWave.createLocalWaveDirective(
        {},
        app.vueApp
    );

    app.vueApp.directive(directiveName, {
        ...vWave,
        getSSRProps() {
            return {};
        }
    });

    app.vueApp.directive(`${directiveName}-trigger`, {
        ...vWaveTrigger,
        getSSRProps() {
            return {};
        }
    });
});

What about creating a Nuxt module which would inject a plugin file with the above content?

import { defineNuxtModule, addPlugin, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  setup (options, nuxt) {
    const { resolve } = createResolver(import.meta.url)

    addPlugin(resolve('<path-to-plugin>'))
  }
})

DamianGlowala avatar Nov 08 '23 12:11 DamianGlowala

Hi everyone!

I've had an idea that would allow for nuxt2 and nuxt3 installs with the same version of v-wave. This removes the necessity of the breaking change detailed in this comment.

I came up with this approach after not having much luck creating a nuxt module that can exist alongside a vanilla vue plugin. That is, I don't want to use nuxt's module builder because this isn't a nuxt module... it's a vue plugin with nuxt support. If anyone has more experience working with modules in nuxt 3 and knows how to achieve the same behavior that exists for nuxt 2, please enlighten me :)

!!! I'm not sure if this is a good solution. Please provide feedback if you don't like this approach !!!

You can test this locally by installing v-wave@beta: $ npm i v-wave@beta

nuxt@^2.x.x installation steps remain the same and still use the @latest release.

When installing v-wave into a nuxt3 project, a postinstall script is run that will create the necessary plugin files (this is all that is needed for v-wave to work inside of nuxt because auto-import will pick these up):

The file that registers the plugin (this will also be where global v-wave options are set):

// v-wave.client.ts
import vWave, { type IVWavePluginOptions } from 'v-wave'

export const options: Partial<IVWavePluginOptions> = {
    // Place any global v-wave options here
}

export default defineNuxtPlugin((nuxtApp) => {
    nuxtApp.vueApp.use(vWave, options)
})

And a stub that is needed when registering directives:

(https://nuxt.com/docs/guide/directory-structure/plugins#vue-directives) If you register a Vue directive, you must register it on both client and server side unless you are only using it when rendering one side. If the directive only makes sense from a client side, you can always move it to ~/plugins/my-directive.client.ts and provide a 'stub' directive for the server in ~/plugins/my-directive.server.ts.

// v-wave.server.ts
import { options } from './v-wave.client';

export default defineNuxtPlugin(({ vueApp }) => {
    vueApp.directive(options.directive ?? 'wave', {});
    vueApp.directive(`${options.directive ?? 'wave'}-trigger`, {});
});

A fresh nuxt 3 project with v-wave installed: image

So far the install script is as follows (this will need to be more robust before it's ready for a stable release, but it gets the point across at least):

const fs = require('fs')
const path = require('path')

const pkg = require(path.join(process.env.INIT_CWD, 'package.json'))

const nuxtVersion = pkg.dependencies?.nuxt ?? pkg.devDependencies?.nuxt

if (!nuxtVersion || /2\.\d+\.\d+/.test(nuxtVersion)) {
  process.exit(0)
}

if (!fs.existsSync(path.join(process.env.INIT_CWD, 'plugins'))) {
  fs.mkdirSync(path.join(process.env.INIT_CWD, 'plugins'))
}

try {
  fs.copyFileSync(
    path.join(__dirname, 'v-wave.client.ts'),
    path.join(process.env.INIT_CWD, 'plugins', 'v-wave.client.ts'),
    fs.constants.COPYFILE_EXCL
  )
  fs.copyFileSync(
    path.join(__dirname, 'v-wave.server.ts'),
    path.join(process.env.INIT_CWD, 'plugins', 'v-wave.server.ts'),
    fs.constants.COPYFILE_EXCL
  )
} catch (e) {
  process.exit(0)
}

is this a guide on how to setup v-wave in Nuxt 3 ? I dont get the last code that is in your reply, If you could add some instructions for nuxt 3 to the document would be a very big help :) I really appriciate it

amirsafaricg avatar Dec 03 '23 12:12 amirsafaricg

@amirsafaricg it's not a guide... just an idea for how I might move forward with the upgrade. I have a working solution for Nuxt 3 that I finished today. It should be backwards compatible with Nuxt 2 as well but I need to wait until tomorrow before I can test that. Either way, expect a release with Nuxt 3 support tomorrow or Wednesday!

justintaddei avatar Dec 05 '23 09:12 justintaddei

@amirsafaricg in the mean time this will get you up and running with v-wave in Nuxt 3:
npm install v-wave@beta && rm -rf ./node_modules/v-wave/dist/cjs

All other steps are the same as is described in the current docs

justintaddei avatar Dec 05 '23 09:12 justintaddei

That's really great to hear ! I'm really happy to hear that ! Ill wait until Wednesday its definitely worth the wait. The v-wave directive is too useful to be rushed. Ill wait until you finish it ;)

Thanks really !

amirsafaricg avatar Dec 05 '23 17:12 amirsafaricg

Nuxt 3 support added in #593.

Release v2.0.0 is live on npm. Please use npm i v-wave@latest to update your projects.

The breaking change is due v-wave@^2.0.0 not being backward compatible with Nuxt 2. Installation and usage of v-wave@^2.0.0 in a Nuxt 3 project is identical to v-wave@^1.0.0 in a Nuxt 2 project.

If you have any issues getting it to work in your project, please feel free to open another issue!

justintaddei avatar Dec 07 '23 00:12 justintaddei

I just install version 2.0.0 and it's work perfectly ! Thx you for your work 😄

NtchPlayer avatar Dec 07 '23 19:12 NtchPlayer