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

chore(): #77 export types, interfaces, and enums #90

Merged
merged 2 commits into from Dec 7, 2022

Conversation

over-engineer
Copy link
Contributor

Closes #77.

Exports everything from ./modules/interfaces, including the Rules enum, which was mentioned in #77 (and it was my use case as well).

I've also set the output.exports rollup option to 'named' (through the build.rollupOptions in the Vite config file) to disable this warning:

Entry module "src/main.ts" is using named and default exports together. Consumers of your bundle will have to use JustValidate["default"] to access the default export, which may not be what you want. Use output.exports: "named" to disable this warning

If you take a look at the currently released version on npm, dist/just-validate.es.js ends with:

export { JustValidate as default };

Building the modified version of this PR, generates a dist/just-validate.es.js ending with:

export { CustomStyleTagIds, GroupRules, Rules, JustValidate as default };

So, I think this change won't break anything (feel free to correct me if I'm wrong).

I've built it via yarn install && yarn build and tested it on my TypeScript project ⁠— everything seems to be working fine.

I'm using it like this:

import JustValidate, { Rules } from 'just-validate';

const validate = new JustValidate('#my-form');

validate.addField('#email', [
  {
    rule: Rules.required,
    errorMessage: 'Email is required',
  },
  {
    rule: Rules.Email,
    errorMessage: 'Email is not valid',
  },
]);

// …

@horprogs
Copy link
Owner

horprogs commented Dec 6, 2022

Thanks for the PR! The problem is we cannot actually use this approach as a lot of users use it in the browser as new window.JustValidate(), the warning was about this case and they will have to use it as window.JustValidate['default']. I couldn't figure out the way how to export everything but keep using it in the browser how it works now

@over-engineer
Copy link
Contributor Author

@horprogs Oh, I see! I hadn't realized you could just include the .js and use it without a bundler.

I see that there are already two files:

  • dist/just-validate.es.js (es format) the ES module that can be imported with import JustValidate from 'just-validate'
  • dist/just-validate.production.min.js (umd format) this is the one that users include from the CDN and use it in the browser as new window.JustValidate()

In that case, I think you could just use different entry points to build each file and support both formats.

Disclaimer: I'm not really experienced with Vite, but I managed to make it work without too many changes (feel free to ignore the changes I'm proposing if you think they're too intrusive and/or they complicate the configuration a bit much 😇)


Exporting everything from src/main.ts:

export default JustValidate;
export * from './modules/interfaces';

would allow people that import the ES module to use it like this:

import JustValidate, { Rules } from 'just-validate';

Then, we could create another file (e.g. main.umd.ts) that will simply export default only the JustValidate class.

// `src/main.umd.ts`

import JustValidate from './main';

export default JustValidate;

and change the vite.config.js to use:

  • src/main.ts to build the dist/just-validate.es.js
  • src/main.umd.ts to build the dist/just-validate.production.min.js

Since this project is still using Vite 2.x, we cannot directly set multiple entries, but we can work around that using an environment variable and calling vite build twice.

So, the current configuration looks like this:

entry: path.resolve(__dirname, 'src/main.ts'),
fileName: (format) =>
  `just-validate.${format === 'umd' ? 'production.min' : format}.js`,

And we can use process.env.OUTPUT_FORMAT (where OUTPUT_FORMAT is an arbitrary name) to set different entry and fileName options for each format (i.e. es and umd).

const config = {
  es: {
    entry: resolve(__dirname, 'src/main.ts'),
    fileName: () => 'just-validate.es.js',
  },
  umd: {
    entry: resolve(__dirname, 'src/main.umd.ts'),
    fileName: () => 'just-validate.production.min.js',
  },
};

const currentConfig = config[process.env.OUTPUT_FORMAT];

Then, in defineConfig() we can return something like this:

return {
  build: {
    outDir: 'dist',
    lib: {
      ...currentConfig,                     // <-- this is the object we built previously
      formats: [process.env.OUTPUT_FORMAT], // by default this has a value of `['es', 'umd']`
      name: 'JustValidate',
    },
    minify: 'terser',
    rollupOptions: {
      output: {
        // `default` export for UMD modules, `named` exports for ES modules
        exports: process.env.OUTPUT_FORMAT === 'es' ? 'named' : 'default',
      },
    },
};

Since we're going to run vite build twice, we also need to keep the contents of the dist directory between runs.

return {
  build: {
    outDir: 'dist',
    emptyOutDir: false, // do not empty the `dist` directory, we'll handle it manually in `package.json`
    // …

Finally, we have to tweak a few things in our package.json.

Introduce a couple of scripts to run vite build with a different value for the OUTPUT_FORMAT environment variable.

{
  "scripts": {
    "build:es": "OUTPUT_FORMAT=es vite build",
    "build:umd": "OUTPUT_FORMAT=umd vite build",

Update the build:vite to clear the dist directory (since we set emptyOutDir to false in our Vite config) and then run both build:umd and build:es.

This looks like that:

    "build:vite": "rm -rf ./dist && tsc && yarn run build:umd && yarn run build:es"

That's it! Now running yarn build is going to build just-validate.production.min.js using the src/main.umd.ts entry with default exports and just-validate.es.js using the src/main.ts entry with named exports.

I've committed the changes I described in this PR and tested both:

  • importing the ES module

  • including the just-validate.production.min.js script directly in the browser like this:

    <body>
        <form action="" id="my-form"></form>
        <script src="../dist/just-validate.production.min.js"></script>
        <script>
            console.log(window.JustValidate);
            console.log(new window.JustValidate('#my-form'));
        </script>
    </body>

Both cases seem to be working fine.


Thanks for developing the library and taking the time to consider my PR 🙂

@horprogs
Copy link
Owner

horprogs commented Dec 7, 2022

Great solution! Actually I just tried to upgrade to Vite 3 to use multiple entries to avoid running it twice with different env variables, but it seems it's impossible to use umd with multiple entries (they have a quite recent PR but it has not been merged yet vitejs/vite#10609). I'll try your way, test it and we'll see!

@horprogs horprogs merged commit 117aa68 into horprogs:master Dec 7, 2022
@horprogs
Copy link
Owner

horprogs commented Dec 7, 2022

Good job! Thanks! I merged, but forgot that chore() doesn't trigger a release, I'll trigger it a bit later today

@over-engineer
Copy link
Contributor Author

Thanks for looking into this so quickly. I really appreciate it! 😄

@github-actions
Copy link

github-actions bot commented Dec 7, 2022

🎉 This PR is included in version 3.9.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Successfully merging this pull request may close these issues.

Use with Typescript and esbuild
2 participants