Skip to content

feat: add virtualModules option to deduplicate macro results - #160

Merged
sxzz merged 6 commits into
unplugin:mainfrom
cany748:main
Aug 7, 2026
Merged

feat: add virtualModules option to deduplicate macro results#160
sxzz merged 6 commits into
unplugin:mainfrom
cany748:main

Conversation

@cany748

@cany748 cany748 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Description

Currently the macro result is serialized and inlined at every usage site. When a macro returns a large payload (e.g. data fetched at build time) that is used in multiple modules, the same data ends up duplicated in the bundle once per usage.

This PR adds an opt-in virtualModules option (default: false). When enabled, each macro result is extracted into a shared virtual module and usage sites import it instead of inlining the value, so the same data is emitted only once in the bundle.

// macro.ts
export async function getData() {
  return (await fetch('https://example.com/data.json')).json()
}
// a.ts / b.ts — both use the macro
import { getData } from './macro' with { type: 'macro' }
export const data = await getData()

Before (both a.ts and b.ts contain a full copy of the data):

const data = {
  /* huge payload */
}

After, with virtualModules: true:

import _macro_831c446d122a4b37 from 'virtual:unplugin-macros/831c446d122a4b37'
const data = _macro_831c446d122a4b37

The virtual module is emitted once and shared by all importers.

Linked Issues

Closes #130

Additional context

How it works

  • Each serialized result is registered as a virtual module virtual:unplugin-macros/<hash> containing export default <data>. The key is a content hash (sha256, truncated to 16 hex chars), so identical values collapse into a single module regardless of which file uses them.
  • The usage site is replaced with an imported identifier (_macro_<hash>); the import statement is prepended once per module, even if the value is used multiple times.
  • The resolveId / load hooks are only registered when the option is enabled — with the option off, the plugin output is byte-for-byte identical to the current behavior.
  • Function results are supported: the $macros$wrap helper is emitted inside the self-contained virtual module instead of the host module.
  • Nested macros inside macro arguments are still inlined, since they are evaluated in a new Function context.
  • Macro re-exports (export { x } from './macro' with { type: 'macro' }) are still inlined; extending deduplication to them could be a follow-up.

Notes

  • All usage sites share a single value instance at runtime (documented in the option's JSDoc). This is usually desirable for read-only data, but it is a behavioral difference from inlining, hence opt-in.
  • Virtual module contents live in memory, so a persistent bundler cache from a previous build (webpack/rspack filesystem cache) may reference a module that no longer exists in the registry; load throws a clear error suggesting to clear the cache in that case.

Extract macro results into shared virtual modules instead of inlining
the serialized value at every usage site, so the same data is emitted
only once in the bundle.

Closes #130
@bolt-new-by-stackblitz

Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@pkg-pr-new

pkg-pr-new Bot commented Jul 8, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/unplugin-macros@160

commit: 493faf4

renovate Bot and others added 5 commits August 7, 2026 14:19
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
@sxzz sxzz changed the title feat: add virtualModules option to deduplicate macro results feat: add virtualModules option to deduplicate macro results Aug 7, 2026
@sxzz
sxzz merged commit e5092e5 into unplugin:main Aug 7, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Avoid data duplication

2 participants