evanw/esbuild

node's `module.register` + bundling

Opened this issue · 2 comments

esbuild understandably does not realise the target of module.register is a dependency, which needs to be bundled and then referenced (possibly inlined). Is there a way to explicitly tell esbuild to do this?

For instance

module.register('@nodejs-loaders/alias');

would be updated to something like

module.register(`data:text/javascript,${aZ2.toString()}`);
  1. esbuild only bundles analyzable imports so if you must bundle something in you have to import that directly:
import loaderJS from '@nodejs-loaders/alias'
  1. You can use plugins to tell esbuild to import the bundled javascript of a module, rough implementation:
// source.js
import loaderJS from '@nodejs-loaders/alias' with { loader: 'bundle-inline' }
import module from 'node:module'

module.register(loaderJS)

// build.js
import {build} from 'esbuild'

build({
  entryPoints: ['source.js'],
  platform: 'node',
  bundle: true,
  format: 'esm',
  outdir: 'dist',
  plugins: [{
    name: 'bundle-inline',
    setup({ onResolve, onLoad }) {
      onResolve({ filter: /(?:)/ }, args => {
        if (args.with.loader == 'bundle-inline') {
          // Use '.js' extension so that the 'dataurl' loader will prepend correct mime type.
          let path = args.path + '.js'
          // TODO: pluginData.path = resolve(args.path, args.args.resolveDir)
          return { namespace: 'bundle-inline', path: path, pluginData: args }
        }
      })
      onLoad({ namespace: 'bundle-inline', filter: /(?:)/ }, async args => {
        let {outputFiles: [{contents}]} = await build({
          entryPoints: [args.pluginData.path],
          platform: 'node',
          bundle: true,
          format: 'esm',
          minify: true,
          write: false,
        })
        return { contents, loader: 'dataurl' }
      })
    }
  }]
}).catch(() => process.exit())

Note that I'm using import attributes for plugins to pick up as the hint, you can use other ways like query strings in import paths.

Excellent, thank you! Just what I was looking for 🙂