Search code examples
javascriptnode.jstypescriptrollup

Import ES Modules from CommonJS dynamically


Is it possible to import ES Modules from CommonJS dynamically without having to change the file extension to mjs and if possible using old Node versions (older than V13)? I'm creating a CLI library which will dynamically import files from users project to auto-generate some code based on those files.

// bin.ts
// This file will be transpiled to CommonJS
const loadResourceFile = async (url: string) => {
  const resource = await import(url);
  return resource.default;
}
...
// rollup.config.js
import typescript from 'rollup-plugin-typescript2';
import pkg from './package.json';

const commonOutputOptions = {
  banner: '#!/usr/bin/env node',
  preferConst: true,
  sourcemap: true,
};

export default {
  input: 'src/bin.ts',
  output: [
    {
      ...commonOutputOptions,
      file: pkg.main,
      format: 'cjs',
    },
    {
      ...commonOutputOptions,
      file: pkg.module,
      format: 'esm',
    },
  ],
  external: [...Object.keys(pkg.dependencies || {})],
  plugins: [typescript()],
  inlineDynamicImports: true,
};

// resource.js
// This file will be a ES module
import a from './a';

export default {
   a,
   b: 'y',
}

Thank you in advance!


Solution

  • It is possible, with the use of vm (Specifically this) and fs although I would suggest not going this route since it quickly grows into an unmaintainable mess if you aren't careful.

    Since your aim is to also support older nodejs versions, I would suggest you make two separate bundles, this way you do not mix CommonJS and ES modules.