logaretm / vee-validate

✅ Painless Vue forms
https://vee-validate.logaretm.com/v4
MIT License
10.79k stars 1.26k forks source link

Zod integration does not work when used with nuxt layers #4491

Closed abdul-alhasany closed 11 months ago

abdul-alhasany commented 1 year ago

What happened?

Hi I am trying to integrate vee-validate and zod into my project. Everything is working fine in development. However, in production, the validation in the top layer is not working.

I have two folders: 📂 ├── 📂 main └── 📂 project-1

project-1 extends main using nuxt layers. I have installed these packages in both projects:

@vee-validate/nuxt: ^4.11.7
@vee-validate/zod: ^4.11.7
vee-validate: ^4.11.7
zod: ^3.22.3

When running nuxt generate then preview in project-1, I found out that pages from project-1 loads vee-validate.esm while pages from main loads vee-validate-zod.esm file.

I checked the code at https://github.com/logaretm/vee-validate/blob/main/packages/nuxt/src/module.ts and it seems it does not handle multi-layer. But this is just a guess.

I don't think I can provide a demo because: 1- The issue only happens in production and online demo show development environment 2- The issue happens with separate projects and I can't extend another project in an online demo

My code looks something like this:

<template>
    <VeeForm
        :validation-schema="validationSchema"
        class="flex flex-col gap-4 w-full md:w-auto"
        @submit="onContactUsSubmit"
    >
        <div class="flex md:flex-row flex-col gap-4">
            <FieldInput
                placeholder="e.g. John Doe"
                label="Full name"
                name="name"
            />

            <FieldInput
                placeholder="e.g. email@domain.com"
                label="Email Address"
                name="email"
            />
        </div>

        <TextAreaInput
            label="Your question"
            name="message"
            placeholder="Message"
            :classes="{input: 'resize-none h-48'}"
        />

        <div class="col-span-2 flex justify-center">
            <ButtonA
                :is-loading="isSubmitting"
                color="primary"
                type="submit"
                class="px-4 sm:px-24 rounded-sm w-full md:w-auto"
            >
                Send Message
            </ButtonA>
        </div>
    </VeeForm>
</template>

<script setup lang="ts">
import { toTypedSchema } from '@vee-validate/zod';
import { string, object } from 'zod';

const isSubmitting = ref(false);

const validationSchema = toTypedSchema(
    object({
        name: string().nonempty(),
        email: string().nonempty()
            .email(),
        message: string().nonempty(),
    })
);

const onContactUsSubmit = async (values: any) => {
    console.log('Submitted Values', values);
    isSubmitting.value = true;
    const { data } = await useBackendFetch('contact-us', {
        body: JSON.stringify(values),
    });

    const { status } = data.value;

    if (status !== 'success') {
        useErrorToast('Something went wrong');
        isSubmitting.value = false;
        return;
    }

    useSuccessToast('Message sent successfully');
    isSubmitting.value = false;
};
</script>

Reproduction steps

  1. Create a nuxt application with vee-validate and zode
  2. Create another nuxt application that extends the first application
  3. Create a page with a form in the second application.
  4. From second project, run pnpx nuxi generate then pnpx nuxi preview

Version

Vue.js 3.x and vee-validate 4.x

What browsers are you seeing the problem on?

Relevant log output

No response

Demo link

Unable to provide a demo link

Code of Conduct

logaretm commented 11 months ago

Sorry for the delay but I'm having a hard time reproducing this. I don't think layers need special handling at the vee-validate module level but I could be wrong as I never used this feature.

I will close this for now since I cannot investigate it. But, feel free to provide a mono repo with this setup on GitHub and I will check it out once you do.

abdul-alhasany commented 5 months ago

I finally was able to resolve it thanks to this comment.

adding this to nuxt.config file solved the issue:

vite: {
  resolve: {
    dedupe: ['vee-validate'],
  },
},
BlueBazze commented 5 days ago

Using a remote nuxt layer (private/public github repo) where vee-validate is installed with causes this.

Since nuxt downloads the remote layer into node_modules/.c12/*. The remote layer gets all of its dependencies installed in the same folder seperately from the app project. So when the layer is extended the app project will run the vee-validate/nuxt module code. When the function from local-pkg is called, it tries to resolve that from the root, but cant find any packages because it is located in node_modules/.c12/my-layer/node_modules/vee-validate https://github.com/logaretm/vee-validate/blob/main/packages/nuxt/src/module.ts#L136

Is my theory. I tried installing vee-validate in my app project aswell as the layer which made the error go away. Further i found out i also had to install the nuxt module in the app project otherwise i was getting no named export of Field and ErrorMessage

logaretm commented 4 days ago

@BlueBazze That makes sense, but I would expect dependencies to be linked to avoid this issue. Otherwise any library with similar setup would break, no?

Do you have suggestions in mind of something we can do on vee-validate side?

BlueBazze commented 3 days ago

Im not denying i could be very wrong. But it is my working theory. It seems to install all of the layer dependencies in $projectRoot/node_modules/.c12/myLayer/node_modules

One solution could be for the user (developer using vee-validate) to add node_modules/.c12/* to the workspaces. Letting the package manager handle it as a monorepo.

For vee-validates module, a manual setting allowing us to define which schema validation package we are using. A string literal module config option that can override the automatic check.

For an automatic check, could you simply import the package in a try catch statement, if it fails then it is not installed.