esbuild icon indicating copy to clipboard operation
esbuild copied to clipboard

Add metadata for import assertions to plugin interfaces

Open calebdwilliams opened this issue 2 years ago • 3 comments

I would love for esbuild to provide metadata for plugin authors about import assertions on files. Currently the onResolve arguments for imports take the following shape:

export type ImportKind =
  | 'entry-point'

  // JS
  | 'import-statement'
  | 'require-call'
  | 'dynamic-import'
  | 'require-resolve'

  // CSS
  | 'import-rule'
  | 'url-token'

interface OnResolveArgs {
  path: string;
  importer: string;
  namespace: string;
  resolveDir: string;
  kind: ImportKind;
  pluginData: any;
}

I would love to see ImportKind include an additional option 'import-assertion' and an additional property on the OnResolveArgs (importAssertion):

interface ImportAssertionKind {
  type: string;
}

Resulting in

interface OnResolveArgs {
  path: string;
  importer: string;
  namespace: string;
  resolveDir: string;
  kind: ImportKind;
  pluginData: any;
  importAssertion: ImportAssertionKind;
}

Furthermore it would be helpful for plugin authors to surface a hook for non-bundling plugins for when an import assertion is hit. Many times we will want to actually generate a separate file or run a process based on these assertions but might not want that content necessarily bundled with the source file. For shadow DOM, for example, we might want to re-use the same stylesheet in several files rather than having multiple built instances.

calebdwilliams avatar Aug 01 '22 17:08 calebdwilliams

I have considered this. However, this goes against the design of import assertions. From the import assertion specification:

moduleRequest.[[Assertions]] must not influence the interpretation of the module or the module specifier; instead, it may be used to determine whether the algorithm completes normally or with an abrupt completion.

So the specification itself says they must not be used for something such as specifying the loader. If it is to be used by esbuild, it's purpose could be only to cause a build error if the loader ended up being different than the one determined by esbuild's path resolution process. But that seems pretty useless, so I haven't introduced something like that.

evanw avatar Aug 01 '22 17:08 evanw

I can definitely respect that decision. The goal here is to hopefully be able to use something like esbuild alone instead of also needing Rollup to build out libraries, but if that's not the goal (and it's perfectly fine if that's not your vision for esbuild as a tool) then it makes sense to just close this as wontfix and I'll keep using esbuild and Rollup together.

Awesome work you've done, really appreciate it either way.

calebdwilliams avatar Aug 04 '22 14:08 calebdwilliams

I've been thinking about this a bit more and wouldn't the section you referenced seem to imply the need to distinguishing the difference between modules with type assertions and modules without them? It would be really easy to write a plugin that enables some CSS-in-JS behavior, for instance, but using assert { type: 'css' } would imply that behavior should be ignored.

Or perhaps based on these rules any import statements with a type assertion shouldn't be surfaced to the user?

calebdwilliams avatar Aug 19 '22 13:08 calebdwilliams

Since this issue was created, import assertions have been demoted from stage 3 (candidate for implementation) back to stage 2 (draft work in progress): https://github.com/tc39/proposal-import-attributes. So I’m closing ties issue as I don’t think esbuild should implement this anymore given that new development.

For what it’s worth I fully support their decision, and I’m happy they are reconsidering it. It was a shame to see them burn valuable syntax space for such a limited purpose. Hopefully their next iteration gives us something more powerful and flexible that’s intended for bundlers like esbuild to make better use of!

evanw avatar Mar 24 '23 23:03 evanw

FYI the latest release of esbuild now supports bundling with import assertions (using with keyword, with different semantics than the assert keyword): https://github.com/evanw/esbuild/releases/tag/v0.19.7. These import attributes are currently passed to on-load plugins, although they are not yet passed to on-resolve plugins. It still remains to be seen how import assertions will behave when they are eventually standardized.

evanw avatar Nov 21 '23 01:11 evanw