class-transformer-validator icon indicating copy to clipboard operation
class-transformer-validator copied to clipboard

feat: Update the library to export ESM and CJS at the same time

Open Pouja opened this issue 8 months ago • 1 comments

It required some hoops to make it work with mocha/chai due to chai only working with ESM. But I could not set the package type to module, due to still requiring tsc to output cjs. The only way was to use .mts file extension and have 2 separate tsconfig files.

To test this, I created three files:

// bundle-me.ts
import { IsEmail } from "class-validator";
import { transformAndValidate } from "class-transformer-validator";

// declare the class using class-validator decorators
class User {
  @IsEmail()
  public email: string;

  public hello(): string {
    return "World!";
  }
}

// then load the JSON string from any part of your app
const userJson: string = JSON.stringify({email: '[email protected]'});

// transform the JSON to class instance and validate it correctness
transformAndValidate(User, userJson)
  .then((userObject: User) => {
    // now you can access all your class prototype method
    console.log(`Hello ${userObject.hello()}`); // prints "Hello World!" on console
  })
  .catch(err => {
    // here you can handle error on transformation (invalid JSON)
    // or validation error (e.g. invalid email property)
    console.error(err);
  });
// esbuild.config.cjs.js
import { build } from "esbuild";
import { writeFileSync } from 'node:fs';

try {
    const { metafile } = await build({
        bundle: true,
        entryPoints: ['bundle-me.ts'],
        mainFields: ["main"],
        platform: "node",
        format: "cjs",
        metafile: true,
        outdir: "dist",
        color: true,
        logLevel: 'info',
        tsconfig: 'tsconfig.json'
    });
    writeFileSync('./dist/metafile.json', JSON.stringify(metafile, null, 2), 'utf-8');
} catch (e) {
    console.error(e);
    process.exit(1);
}
// esbuild.config.esm.js
import { build } from "esbuild";
import { writeFileSync } from 'node:fs';

try {
    const { metafile } = await build({
        bundle: true,
        entryPoints: ['bundle-me.ts'],
        mainFields: ["module", "main"],
        platform: "node",
        format: "esm",
        metafile: true,
        outdir: "dist",
        color: true,
        logLevel: 'info',
        tsconfig: 'tsconfig.json'
    });
    writeFileSync('./dist/metafile.json', JSON.stringify(metafile, null, 2), 'utf-8');
} catch (e) {
    console.error(e);
    process.exit(1);
}

Then you can bundle and see the result between ESM and CJS:

~/d/n/bundle-class-transformer-validator ❯❯❯ node esbuild.config.cjs.js

  dist/bundle-me.js  944.6kb

⚡ Done in 61ms
~/d/n/bundle-class-transformer-validator ❯❯❯ node esbuild.config.esm.js

  dist/bundle-me.js  88.9kb

⚡ Done in 48ms

It did require some manual copying to verify this.

This should resolve #30

Pouja avatar Apr 21 '25 10:04 Pouja

This should not break for anyone already using CJS. The output is exactly the same.

Pouja avatar Apr 21 '25 10:04 Pouja