-
Notifications
You must be signed in to change notification settings - Fork 710
Description
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_metaaware of builtin plugins (e.g. via the existing"builtin:"name prefix convention) so that builtinPrehooks sort before userPre, and builtinPosthooks sort after userPost, 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.