Skip to content

Deisgn: a plugin cannot have hooks that run both before and after other plugins #8416

@hyf0

Description

@hyf0

Problem

A single plugin cannot have one hook run before all other plugins and another hook run after all other plugins.

Both Rollup and rolldown sort plugin hooks into three buckets per hook via the order property (pre, normal, post). Within each bucket, array position is preserved (stable sort). This means a plugin's position in the array acts as a tiebreaker within the same order bucket.

If a plugin needs resolveId to run first (before other pre hooks) and transform to run last (after other post hooks), it must be both first and last in the plugin array — which is impossible. The only workaround today is splitting it into two separate plugins: one placed at the front, one at the back.

Rollup context

Rollup has the same per-hook order: 'pre' | 'post' mechanism with the same stable-sort behavior (getSortedValidatedPlugins in PluginDriver.ts). Rollup doesn't face this problem in practice because it doesn't inject its own builtin plugins — it delegates plugin ordering to consumers like Vite, which uses hardcoded array interleaving in resolvePlugins().

Impact on rolldown internals

Rolldown implements several internal features as builtin plugins (e.g. OxcRuntimePlugin, HmrPlugin, DataUriPlugin, ChunkImportMapPlugin). These are inserted into the user plugin array via apply_inner_plugins, which prepends some and appends others.

This works for plugins whose hooks all need the same ordering direction. But ChunkImportMapPlugin has generate_bundle with order: Pre (needs to run early) and render_chunk with order: Post (needs to run late). Since it's prepended, its render_chunk(Post) runs before user Post render_chunk hooks — the opposite of intent.

Today this doesn't cause bugs because no user plugins conflict on the same hooks, but the ordering guarantee is incorrect and will become fragile as more builtin plugins are added.

Possible directions

  • Internal-aware sort: Make sort_plugins_by_hook_meta aware of builtin plugins (e.g. via the existing "builtin:" name prefix convention) so that builtin Pre hooks sort before user Pre, and builtin Post hooks sort after user Post, regardless of array position.
  • Split plugins: Split plugins with mixed ordering needs into separate plugin instances. Works but increases plugin count and couples related logic across files.
  • Accept the limitation: Document it and rely on the fact that conflicts are rare in practice.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions