hapijs / joi

The most powerful data validation library for JS
Other
20.87k stars 1.51k forks source link

Change browser module export #2299

Open dmackenz opened 4 years ago

dmackenz commented 4 years ago

Context

What are you trying to achieve or the steps to reproduce ?

The documentation does not make it clear how @hapi/joi/dist/joi-browser.min.js can be imported and used like regular @hapi/joi. I am trying to use Joi in Karma.

// --- What I've tried:
import Joi from '@hapi/joi/dist/joi-browser.min.js';
import * as Joi from '@hapi/joi/dist/joi-browser.min.js';
import '@hapi/joi/dist/joi-browser.min.js';
import { Joi } from '@hapi/joi/dist/joi-browser.min.js';
// ---

export const createSchema = () => {
    return {
        scoresStore: {
            scores: Joi.array().length(4).items(Joi.number().equal(0)).required()
        },
        overallScoreStore: {
            root: Joi.object().required(),
            overallScore: Joi.number().equal(0),
            overallScoreTwo: Joi.number().equal(0)
        }
    };
};

Could someone tell me what the issue is here?

Marsup commented 4 years ago

Why are you doing deep imports? import Joi from '@hapi/joi' should be enough.

dmackenz commented 4 years ago

@Marsup

import Joi from '@hapi/joi' throws an error when ran with karma and I'm not sure why. It works fine with standalone mocha. This is what led me to try to import joi-browser.min.js because I figured that the fact that I am running in a headless browser was causing the error.

the code I am running:

import Joi from '@hapi/joi';
import RootStore from '../../components/stores/root';

export const createSchema = () => {
    return {
        scoresStore: {
            scores: Joi.array().length(4).items(Joi.number().equal(0)).required()
        }
    };
};

export const validate = (schema, store) => {
    const { error } = Joi.object(schema).validate(store);
    if (error) throw error;
};

describe('Root tests', () => {
    it('test initial schema', (done) => {
        const rootStore = new RootStore();
        const schema = createSchema();
        validate(schema, rootStore);
        done();
    });
});

Here is the error from karma:

START:
13 02 2020 09:43:12.128:INFO [karma-server]: Karma v4.4.1 server started at http://0.0.0.0:9876/
13 02 2020 09:43:12.129:INFO [launcher]: Launching browsers ChromeHeadlessNoSandbox with concurrency unlimited
13 02 2020 09:43:12.137:INFO [launcher]: Starting browser ChromeHeadless
13 02 2020 09:43:12.728:INFO [HeadlessChrome 79.0.3945 (Windows 10.0.0)]: Connected on socket O79s7etaUu6t9GkgAAAA with id 13936121
HeadlessChrome 79.0.3945 (Windows 10.0.0) ERROR
  Uncaught SyntaxError: The requested module '../../node_modules/@hapi/joi/lib/index.js' does not provide an export named 'default'
  at http://localhost:9876/context.html:0:0

  SyntaxError: The requested module '../../node_modules/@hapi/joi/lib/index.js' does not provide an export named 'default'

Finished in 0.881 secs / 0 secs @ 09:43:13 GMT-0500 (Eastern Standard Time)

SUMMARY:
√ 0 tests completed
Marsup commented 4 years ago

Oh you're right, we use require for our testing. Hopefully import Joi = require('@hapi/joi') works. This is probably something we should change in the next breaking version.

dmackenz commented 4 years ago

So I ended up figuring it out. I ended up doing import '@hapi/joi/dist/joi-browser.min.js' then used joi with a lowercase j every time that I referenced it.

import '@hapi/joi/dist/joi-browser.min.js';
// const joi = require('@hapi/joi');
import RootStore from '../../components/stores/root';

export const createSchema = () => {
    return {
        scoresStore: {
            scores: joi.array().length(4).items(joi.number().equal(0)).required()
        }
    };
};

export const validate = (schema, store) => {
    const { error } = joi.object(schema).validate(store);
    if (error) throw error;
};

describe('Root tests', () => {
    it('test initial schema', (done) => {
        console.log(JSON.stringify(joi));
        const rootStore = new RootStore();
        const schema = createSchema();
        validate(schema, rootStore);
        done();
    });
});
hueniverse commented 4 years ago

@Marsup how should this be fixed?

Marsup commented 4 years ago

By exporting an ES6 compatible module. Basically either set a default property and __esModule to true, or export it as a Joi property dropping the default export. Or both.

Marsup commented 4 years ago

You can find an example output of that in https://babeljs.io/docs/en/babel-plugin-transform-modules-commonjs.

BolajiOlajide commented 4 years ago

Hey @hueniverse ,

I can help with this. Let me know if this is okay, so you can assign this issue to me.

mathieutu commented 3 years ago

I think this lead to others problems too.

In fact, const Tlds = require('@hapi/address/lib/tlds'); doesn't work at all in browser (return an empty object), so we have error thrown for standard documented code (a basic string().email()).

braebo commented 3 years ago

Are there really no plans to support modern JS? Svelte and Vue (vite/rollup) don't support CommonJS.

hueniverse commented 3 years ago

If someone wants to open a PR that fixes it, ideally by offering a separate export so it is not a breaking change (at least initially to allow people to migrate over time), I'll review.