feat(experimental-extractor): pluggable bundler interface + rolldown support#2572
feat(experimental-extractor): pluggable bundler interface + rolldown support#2572timofei-iatsenko wants to merge 22 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
size-limit report 📦
|
There was a problem hiding this comment.
Pull request overview
This PR makes the extract-experimental pipeline bundler-pluggable by introducing a minimal bundler interface and shipping built-in bundlers for esbuild (default) and rolldown, plus updates the macro extraction mark to a JSDoc-style comment so it survives rolldown output.
Changes:
- Add
ExperimentalExtractorBundler/BundleResulttypes and a newexperimental.extractor.bundlerconfig field (with deprecations for esbuild-specific options on the extractor config). - Replace the hardcoded esbuild bundling with a bundler abstraction and add
createEsbuildBundler()andcreateRolldownBundler()implementations. - Update macro extraction marks and extraction logic to support both
/*i18n*/and/** i18n */, plus add an E2E rolldown extractor test.
Reviewed changes
Copilot reviewed 31 out of 32 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| yarn.lock | Adds/updates lock entries for rolldown + plugin-babel and bumps esbuild version. |
| packages/conf/src/types.ts | Introduces BundleResult + ExperimentalExtractorBundler types; adds bundler option and deprecations on extractor config. |
| packages/conf/src/makeConfig.ts | Extends example/validation shape to allow experimental.extractor.bundler. |
| packages/cli/test/index.test.ts | Adds E2E test coverage for experimental extractor using rolldown. |
| packages/cli/test/extractor-experimental/lingui.config.rolldown.ts | Adds test config exercising createRolldownBundler(). |
| packages/cli/src/lingui-extract-experimental.ts | Switches extractor to use configured bundler, defaulting to esbuild bundler factory. |
| packages/cli/src/extract-experimental/linguiEsbuildPlugin.ts | Uses a config-aware content filter regex for macro detection. |
| packages/cli/src/extract-experimental/constants.ts | Centralizes the default excluded extensions list. |
| packages/cli/src/extract-experimental/bundleSource.ts | Removes old esbuild-only bundling implementation (superseded by bundlers). |
| packages/cli/src/extract-experimental/bundlers/rolldown.ts | Adds rolldown bundler implementation. |
| packages/cli/src/extract-experimental/bundlers/esbuild.ts | Adds esbuild bundler implementation replacing the old bundling code. |
| packages/cli/src/extract-experimental/buildContentFilter.ts | Adds helper to build macro import detection regex from linguiConfig.macro. |
| packages/cli/package.json | Exposes new bundler entrypoints and changes bundler-related dependency declarations. |
| packages/babel-plugin-lingui-macro/test/fixtures/jsx-plural-select-nested.expected.js | Updates expected output to JSDoc-style extraction mark. |
| packages/babel-plugin-lingui-macro/test/fixtures/jsx-keep-forced-newlines.expected.js | Updates expected output to JSDoc-style extraction mark. |
| packages/babel-plugin-lingui-macro/test/fixtures/js-t-var/js-t-var.expected.js | Updates expected output to JSDoc-style extraction mark. |
| packages/babel-plugin-lingui-macro/test/fixtures/js-t-continuation-character.expected.js | Updates expected output to JSDoc-style extraction mark. |
| packages/babel-plugin-lingui-macro/test/snapshots/lingui-directive.test.ts.snap | Snapshot updates for JSDoc-style extraction mark. |
| packages/babel-plugin-lingui-macro/test/snapshots/jsx-trans.test.ts.snap | Snapshot updates for JSDoc-style extraction mark. |
| packages/babel-plugin-lingui-macro/test/snapshots/jsx-selectOrdinal.test.ts.snap | Snapshot updates for JSDoc-style extraction mark. |
| packages/babel-plugin-lingui-macro/test/snapshots/jsx-select.test.ts.snap | Snapshot updates for JSDoc-style extraction mark. |
| packages/babel-plugin-lingui-macro/test/snapshots/jsx-plural.test.ts.snap | Snapshot updates for JSDoc-style extraction mark. |
| packages/babel-plugin-lingui-macro/test/snapshots/jsx-placeholder.test.ts.snap | Snapshot updates for JSDoc-style extraction mark. |
| packages/babel-plugin-lingui-macro/test/snapshots/js-useLingui.test.ts.snap | Snapshot updates for JSDoc-style extraction mark. |
| packages/babel-plugin-lingui-macro/test/snapshots/js-t.test.ts.snap | Snapshot updates for JSDoc-style extraction mark. |
| packages/babel-plugin-lingui-macro/test/snapshots/js-selectOrdinal.test.ts.snap | Snapshot updates for JSDoc-style extraction mark. |
| packages/babel-plugin-lingui-macro/test/snapshots/js-select.test.ts.snap | Snapshot updates for JSDoc-style extraction mark. |
| packages/babel-plugin-lingui-macro/test/snapshots/js-plural.test.ts.snap | Snapshot updates for JSDoc-style extraction mark. |
| packages/babel-plugin-lingui-macro/test/snapshots/js-defineMessage.test.ts.snap | Snapshot updates for JSDoc-style extraction mark. |
| packages/babel-plugin-lingui-macro/src/constants.ts | Changes the extraction mark value to produce /** i18n */ output. |
| packages/babel-plugin-extract-messages/test/extract-messages.test.ts | Adds test ensuring both old and new extraction mark formats are supported. |
| packages/babel-plugin-extract-messages/src/index.ts | Updates detection logic to accept both i18n and * i18n comment bodies. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This comment was marked as resolved.
This comment was marked as resolved.
678b0e9 to
fe7df78
Compare
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as outdated.
This comment was marked as outdated.
|
I explored one uncovered case which was ok on esbuild and not ok with rolldown. Both esbuild and rolldown support code splitting. For example if you have However esbuild allow to switch this codesplitting even when multiple entrypoints are passed. In this case it creates 1 bundle for 1 entrypoint. Previous implementation was based on this, and extracted from bundles with 1-1 mapping to catalogs. Rolldown doesn't allow to switch off code splitting when you pass multiple entry points. It will always produce 3 chunks. So the extractor code should be able to also scan this common chunk and put extracted messages into corresponding catalog. I added an implementation for this and actually enabled code-splitting for esbuild as well. This actually should also give a performance speed up. Previously both bundles Now common code extracted in the separate file and would be scanned only once, so the amount of work would grew linearly with the size of the project, not the amount of entrypoints and reusability multiplier. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 31 out of 40 changed files in this pull request and generated 5 comments.
Files not reviewed (8)
- packages/cli/test/extractor-experimental/expected-rolldown/about.page.en.js: Generated file
- packages/cli/test/extractor-experimental/expected-rolldown/about.page.pl.js: Generated file
- packages/cli/test/extractor-experimental/expected-rolldown/index.page.en.js: Generated file
- packages/cli/test/extractor-experimental/expected-rolldown/index.page.pl.js: Generated file
- packages/cli/test/extractor-experimental/expected/about.page.en.js: Generated file
- packages/cli/test/extractor-experimental/expected/about.page.pl.js: Generated file
- packages/cli/test/extractor-experimental/expected/index.page.en.js: Generated file
- packages/cli/test/extractor-experimental/expected/index.page.pl.js: Generated file
Comments suppressed due to low confidence (1)
packages/cli/src/extract-experimental/linguiEsbuildPlugin.ts:27
buildContentFilterRe(options.linguiConfig)is recomputed for every loaded file. Since it only depends on the config, it can be computed once insetupand reused, reducing per-file overhead during bundling.
setup(build) {
build.onLoad({ filter: babelRe, namespace: "" }, async (args) => {
const filename = path.relative(process.cwd(), args.path)
const contents = await fs.promises.readFile(args.path, "utf8")
const hasMacroRe = buildContentFilterRe(options.linguiConfig)
if (!hasMacroRe.test(contents)) {
// let esbuild process file as usual
return undefined
}
Description
This one is made on top of #2571
Summary
extract-experimentalconfigurable via thebundlerfield inexperimental.extractorconfigcreateEsbuildBundler()andcreateRolldownBundler()factory functions as separate entrypoints (@lingui/cli/bundlers/esbuild,@lingui/cli/bundlers/rolldown)includeDeps,excludeExtensions, andresolveEsbuildOptionon the extractor config in favor of passing them to the bundler factoryMotivation
The experimental extractor was hardcoded to esbuild. Users who prefer rolldown (or another bundler) had no way to swap it. The new
ExperimentalExtractorBundlerinterface is minimal —bundle(entryPoints, outDir, linguiConfig) => BundleResult— so custom implementations are straightforward.Usage
Types of changes
Fixes # (issue)
Checklist