unbuild icon indicating copy to clipboard operation
unbuild copied to clipboard

How to ship in CJS format when my package has pure ESM package dependencies?

Open holazz opened this issue 3 years ago • 8 comments

index.ts:

import ora from 'ora'
 
const spinner = ora('Starting...').start()
spinner.succeed('Done!')

build.config.ts:

export default defineBuildConfig({
  entries: [
    'index',
  ],
  rollup: {
    emitCJS: true,
  },
})

run unbuild && node dist/index.cjs and get error:

const ora = require('ora');
            ^

Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/zhangjiawei/Desktop/git-download/node_modules/.pnpm/[email protected]/node_modules/ora/index.js from /Users/zhangjiawei/Desktop/git-download/dist/index.cjs not supported.
Instead change the require of index.js in /Users/zhangjiawei/Desktop/git-download/dist/index.cjs to a dynamic import() which is available in all CommonJS modules.
    at Object.<anonymous> (/Users/zhangjiawei/Desktop/git-download/dist/index.cjs:3:13) {
  code: 'ERR_REQUIRE_ESM'
}

holazz avatar May 17 '22 10:05 holazz

Hey, same question. My case was with execa, which is now pure ESM as well. I was using tsup previously and it has a noExternal option which solved the issue: https://github.com/egoist/tsup/blob/b9cd8d5f0973f94d494b8b0d0e65121e5712ee49/src/esbuild/external.ts#L7

innocenzi avatar Jun 01 '22 09:06 innocenzi

Hey, same question. My case was with execa, which is now pure ESM as well. I was using tsup previously and it has a noExternal option which solved the issue: egoist/tsup@b9cd8d5/src/esbuild/external.ts#L7

Thanks for the idea, I want to ship both cjs and esm format, I tried setting noExternal , cjs works well, but esm doesn't work.

holazz avatar Jun 01 '22 10:06 holazz

When possible, using dynamic imports is the best way to load such libraries for CJS build support:

const execa = await import('execa')

Unbuild has rollup.inlineDependencies option that inlines all deps but i would avoid that. But i would go with dynamic import as possible.

Some alternatives:

  • Find an alternative dep or use a version that is still supporting CJS
  • Drop CJS support from your library as well to keep such deps

pi0 avatar Jun 01 '22 16:06 pi0

In my context I can't not ship CJS unfortunately. I could downgrade execa but I think it's nice to be able to inline the dependency. I found tsup's noExternal option to be quite useful.

That being said @pi0, I was using the following config which did not inline execa:

export default defineBuildConfig({
    entries: [
        'src/index',
        'src/inertia',
    ],
    clean: true,
    declaration: true,
    externals: [
        'rollup',
        'vite',
        'esbuild',
        'tailwindcss',
        'autoprefixer',
    ],
    rollup: {
        emitCJS: true,
        inlineDependencies: true,
    },
})

I use import { execaSync } from 'execa' somewhere in my code, and the generated index.cjs has a require('execa') still. Did I do something wrong here?

innocenzi avatar Jun 01 '22 19:06 innocenzi

Do you mind to share a repo @innocenzi? Also certainly you cannot use dynamic import approach? Being able to inline is for sure a valid case but it is not always the best idea...

pi0 avatar Jun 01 '22 22:06 pi0

Sure @pi0: https://github.com/innocenzi/unbuild-issue-79

Run npx unbuild and see that there is still a const execa = require('execa') instead of that dependency to be inlined.

In my case the dynamic import is not an option, but I can downgrade execa (v5 is CJS). Maybe it's not the best option to inline the dependency but I prefer to stay up to date and it's a package that is consumed on the Node side, not on the browser, so I don't mind the extra bit of size.

innocenzi avatar Jun 02 '22 08:06 innocenzi

Anthony Fu helped me, I just needed to make execa a development dependency instead of a normal one, which completely makes sense!

So @holazz to solve the issue, use rollup.inlineDependencies and make your ESM-only dependency a development dependency.

Alternatively, as @pi0 said, find the same lib exported as CJS (ora v5.x), or finally, use dynamic imports.

Hopefully this solves the issue for anyone stumbling upon it.

innocenzi avatar Jun 03 '22 12:06 innocenzi

Anthony Fu helped me, I just needed to make execa a development dependency instead of a normal one, which completely makes sense!

So @holazz to solve the issue, use rollup.inlineDependencies and make your ESM-only dependency a development dependency.

Alternatively, as @pi0 said, find the same lib exported as CJS (ora v5.x), or finally, use dynamic imports.

Hopefully this solves the issue for anyone stumbling upon it.

Thank You Kindly! rollup.inlineDependencies should not be what I want, I am currently using the 5.x version of ora.

holazz avatar Jun 03 '22 12:06 holazz