Killy.MXI
Killy.MXI

Reputation: 372

Configure Rollup to add file extensions into import/require statements

I have a hybrid cjs/esm Node package written in Typescript.

It consists of, let's say, two files - core.ts and extra.ts and I want to keep them separate. extra.ts imports core.ts (literally import { ... } from './core';) and they are separate entry points of the package. Clients import either only core.ts or both.

Rollup makes it easy to have build steps for multiple entry points, for multiple output formats, and all seemed fine.

But now I ran into an issue:

Let's say I have example.mjs or example.cjs where I import or require my-package and my-package/extra entry points.

That doesn't work. Error messages are slightly different but meaning is the same - ./core module can not be found when reading extra.mjs/cjs.

By default, Node 12 does not guess file extensions (I'm not questioning this).

I have to call it as node --experimental-modules --es-module-specifier-resolution=node ./example.mjs to make it work. This is unsatisfactory solution. I need example.mjs to be runnable without additional flags.

It appears to me that file extensions can and should be added to import/require statements in compiled cjs/mjs files to make it work according to the spec.

Although, since I have different build steps in Rollup config for both files and external: ['./core'] in the options for extra.ts, for Rollup they are totally unrelated. And Rollup will just bundle them into a single file otherwise, which is not what I need either.

So the question:

Upvotes: 4

Views: 5272

Answers (1)

Killy.MXI
Killy.MXI

Reputation: 372

Got a satisfactory solution.

output.preserveModules option keeps all files separate while building them in one pass (can be limiting in some aspects though).

output.entryFileNames option allows to specify file extensions. (It won't work with modules considered external, can't use it without preserveModules.)

I can build only extra.ts as it imports every other file. But I have to be mindful of tree shaking when building like this - need to retain all exports of core.ts.

export default [
  {
    external: [],
    input: 'src/extra.ts',
    treeshake: false,
    plugins: [
      typescript(),
      cleanup({ extensions: ['ts'] })
    ],
    output: [
      {
        dir: 'lib',
        format: 'es',
        preserveModules: true,
        entryFileNames: '[name].mjs',
      },
      {
        dir: 'lib',
        format: 'cjs',
        preserveModules: true,
        entryFileNames: '[name].cjs',
      },
    ],
  },
];

One step back is that I get another output file for another ts file imported by core.ts and extra.ts. I think I can live with that.

Ideal solution would require to monkey-patch output files with sed-like tool after the build in my initial configuration.

Upvotes: 3

Related Questions