Repository navigation
Tracking Issue for enhancements to Nx from Analog v2 -> v3 upgrade lessons learned #37195
benpsnyder
started this conversation in
Feature Requests
Replies: 2 comments
|
The issue description has been refreshed (2026-08-18) so the status matches current Short version of what changed:
The Analog v2 → v3 context is unchanged; this was a status accuracy pass, not a new proposal. |
0 replies
|
I'm going to convert this to a discussion. It's too many things to be actionable in a single PR. |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Summary
The OXC ecosystem (oxlint, oxfmt, oxc-parser, oxc-transform, oxc-resolver), Rolldown, and AnalogJS have moved faster than this issue’s April 2026 write-up. Several of those tools are already production-ready — Vite 8 ships Rolldown as its default bundler,
@angular/builddepends on@oxc-project/runtime, and@vitejs/plugin-reactv6 uses OXC for transforms.AnalogJS is still the practical Angular + Vite + Rolldown bridge.
@angular/builduses Vite as a dev server with esbuild for production bundling. Analog’s@analogjs/vite-plugin-angularis what puts Angular compilation into a normal Vite pipeline, so Vite 8’s Rolldown bundler, plugins, androlldownOptionsapply to Angular components.This is a tracking issue, not a single-PR bug. None of the remaining benpsnyder PRs should close it.
Refresh date: 2026-08-18, against
origin/master44b3072207(Nx23.2.0-beta.7). The four benpsnyder PRs were rebased onto that master today and are GitHub-MERGEABLE, but they are not merged and should not be described as implemented.Current status
mastertoday@nx/oxlintlanded in #36491 + inferred targets in #36671.nx add @nx/oxlint, init, optional configuration (plugins only), CreateNodesV2, experimental@nx/oxlint/boundaries-plugin. Docs at Nx with Oxlint.oxlint.config.ts;@nx/oxlint:initwrites.oxlintrc.json.master. Formatter option is stillnone|prettier.oxfmtVersion(^0.60.0; npm latest is0.63.0).master.@nx/js:librarybundlers areswc,tsc,rollup,vite,esbuild,none../src/...(published@nx/jsshipsdist/).tsdownVersionis^0.21.0(npm latest0.22.14). VitepreserveModulesis checked onbuild.rolldownOptions, notoutput. The PR also addsrolldownOptionsto@nx/vite:build, which is deprecated and scheduled for removal in Nx 24 — the durable surface isvite.config.ts+@nx/vite/plugin.master.useOxcDeclarations. Vite side is adeclarationsgenerator option plusnxOxcDeclarationsPlugin(), whose wrapper stillrequires@nx/js/src/plugins/rollup/oxc-declarations(not exported on this branch).@nx/vitestpins@analogjs/*at~2.6.0(npm 2.x latest is2.7.0). No 3.x channel.@nx/vitedoes not pin Analog.@nx/vitestonly despite thefeat(vite)title~2.6.0/3.0.0-alpha.70. Import migration +packageJsonUpdates; no@nx/vitechanges..d.mtscasts@nx/devkit→nodenext).TODO(jack)casts remain in@nx/vite,@nx/cypress,@nx/react,@nx/remix,@nx/angular.@nx/vitestno longer has those comments.@nx/angular:library --bundler=vitebundleroption. Library generator can already chooselinter: oxlintandunitTestRunner: vitest-analog|vitest-angular.setup-tailwindgenerators are gone from packages.NX_PREFER_NODE_STRIP_TYPES=false.Closed without merge (do not treat as in-progress):
@nx/oxlintonmasterformatter: none|prettieris already onmaster, oxfmt is 35089Context: what Analog alpha is doing today
AnalogJS 3.x-alpha has replaced the traditional Angular toolchain in that repo:
isolatedDeclarationSync.d.tsgenerationpreserveModules.d.tsbundlingThat stack is what this issue is trying to make first-class in Nx. Analog 2.x remains the stable channel (
@analogjs/vitest-angular@2.7.0); Analog 3 is still prerelease (3.0.0-alpha.70).1.
@nx/oxlint— landed experimental; coexistence still openThe original ask: a first-party
@nx/oxlintpackage.On
master: that package exists and is documented as experimental.What shipped:
oxlint(^1.75.0, floor1.70.0), registers the plugin, writes root.oxlintrc.json(typescript,unicorn,oxc)--pluginsis passed. A barenx g @nx/oxlint:configuration --project=foodoes not write a per-project file..oxlintrc.json(c)/oxlint.config.ts(mts)and registers a lint target (lint, oroxlintif ESLint already ownslint)@nx/oxlint/boundaries-pluginwrapping@nx/enforce-module-boundariesas an Oxlint JS plugin@nx/js/@nx/angularlibrary generators already accept--linter=oxlintWhat did not ship, and is still the Analog-shaped gap:
@nx/oxlint:lintexecutor (deliberately inference-only)eslint-plugin-oxlintbridge onmaster^9.8.0;versions()has a v9 map only, with an explicit “v10 entry will be added alongside full v10 support” comment--type-aware/--type-checkon an executor (there is no executor)Coexistence during migration — open in #35114
Analog still runs three passes: oxlint, oxlint
--type-aware, then ESLint only for leftover rules. #35114 addsnx g @nx/eslint:setup-oxlint-bridgeon the ESLint side: installeslint-plugin-oxlint@^1.78.0+jiti@^2.6.1, injectbuildFromOxlintConfig(), setreportUnusedDisableDirectives: 'off'.That still belongs in
@nx/eslint(it rewrites ESLint config). It is not replaced by@nx/oxlint.Caveat after the rebase: the bridge defaults to
./oxlint.config.ts, while@nx/oxlint:initwrites.oxlintrc.json. A merge-ready version should detect the config@nx/oxlintactually created.The JITI pattern Analog uses:
2. oxfmt — still #35089
The ask: first-class oxfmt next to Prettier.
#35089 is the vehicle. It is open, mergeable against GitHub’s conflict check, and changes-requested by @FrozenPandaz. It is much further along than the April text: detection,
nx format:write/format:check, generatorformatFiles(),create-nx-workspace --formatter=oxfmt, and anoxfmtVersionconstant (^0.60.0).Still complementary, and still not on
master:.prettierrc→.oxfmtrc.json,.prettierignore→.oxfmtignore)master#35020is closed without merge.formatter: none|prettieralready exists onmaster; the missing value isoxfmt, which is 35089’s job.3. Rolldown / tsdown library builds — open in #35112
Not implemented on
master. #35112 proposes:@nx/js:tsdownexecutor--bundler=tsdownon@nx/js:libraryrolldownOptions.preserveModules/preserveModulesRooton the deprecated@nx/vite:buildexecutor schemarolldownPluginDtsVersion(^0.22.0; npm latest is0.28.2)After today’s rebase it is
MERGEABLE, but it is not merge-ready as-is:packages/js/executors.jsonpoints at./src/executors/tsdown/.... Published@nx/jsonly shipsdist/.require.resolve('tsdown/dist/cli.mjs')is pinned againsttsdownVersion ^0.21.0. Current tsdown0.22.14publishestsdown/run→dist/run.mjs; do not assume the 0.21 line matches that export without checking that tag.build.rolldownOptions.preserveModulesas buildable; Rolldown keeps that flag onoutput.@nx/vite:buildwill disappear in Nx 24. Analog-style Rolldown options belong in generatedvite.config.tsand inferred-plugin buildability, not on the dying executor.Until those are fixed, this row stays “open PR”, not “done”.
4. Vite 8 Environment API and
.d.mtstypesThe ask: finish Vite 8 Environment API support.
Still open:
environmentNameonly to@nx/vite:dev-server— that executor is deprecated and goes away in Nx 24. This belongs on inferred serve targets / Vite config.environments(per-environment build options, not only top-levelbuild.rolldownOptions.input)TODO(jack)Record<string, any>casts because Vite 8.d.mtstypes are not resolvable undermoduleResolution: "node"#34946 merged and moved
@nx/devkittonodenext. That unblocked the rest; it did not finish it. RemainingTODO(jack)casts onmaster(the April@nx/vitestpair is gone):@nx/vitesrc/plugins/plugin.ts@nx/cypresssrc/plugins/preprocessor-vite.ts,plugins/cypress-preset.ts@nx/reactplugins/component-testing/index.ts@nx/remixsrc/utils/executor-utils.ts,plugins/component-testing/index.ts@nx/angularsrc/plugins/utils/vitest.ts5. Vite + Rolldown Angular libraries (via
@nx/vite:build, not a new executor)The ask:
@nx/angular:library --bundler=vitethat scaffolds Analog + Rolldown, plus a discoverabledeclarationsoption.Still not started.
@nx/angular:libraryhas nobundlerfield. It already has--linter=oxlintand--unitTestRunner=vitest-analog(Analog) vsvitest-angular(first-party Angular unit-test). That last split is new since April and is the right package boundary: Analog stays a Vite-plugin choice, not a new Angular executor.Do not hang this on
@nx/vite:build. That executor (and@nx/vite:dev-server) are deprecated and will be removed in Nx 24 in favor ofnx g @nx/vite:convert-to-inferred. A declarations option on the executor schema would die with it. The Analog path is a generatedvite.config.tsplus inferred-plugin buildability.A generated
vite.config.tswould look like:#35113 is the declaration half of this story. It is not on
master. The shared emitter lives in@nx/js. RollupwithNx({ useOxcDeclarations })and esbuilduseOxcDeclarationsare the executor/plugin flags. Vite uses adeclarations: 'tsc' | 'oxc' | 'rolldown-plugin-dts' | 'none'generator option andnxOxcDeclarationsPlugin(). That Vite wrapper currently imports a@nx/jssubpath the PR does not export, so this is also “open PR”, not “implemented”.ng-packagr
ng-packagr is on a similar path, but the April “open” table is stale:
Nx should still support both APF-via-ng-packagr and Vite+Analog libraries. Do not treat 3267 as in-flight.
6. Analog 3.x version tracking — open in #35115
Not implemented on
master. Current pin is@nx/vitestonly,analogVitestAngular = '~2.6.0', covering@analogjs/vitest-angularand@analogjs/vite-plugin-angular.#35115 after today’s rebase:
analogVitestAngularV3 = '3.0.0-alpha.70'next to~2.6.0getAnalogMajorVersion(tree)+ensureDependencies()choose the channelupdate-analog-v3rewrites@analogjs/vite-plugin-angular/setup-vitest→@analogjs/vitest-angularpackageJsonUpdates23.2.0-analog-v3owns the version bump (requires: >=3.0.0-0)@nx/vite. The April text and the PR title over-claim that.Remaining even after a merge: e2e for both Analog 2.x and 3.x; bump the 2.x pin to
~2.7.0if that is the intended stable channel; catalog-aware version detection (getDependencyVersionFromPackageJson) socatalog:specifiers are not misread as Analog 2.7. Tailwind CSS v4 for Angular — generators gone; docs still missing
#35049 merged. There is no
@nx/angular:setup-tailwindto update. Tailwind v4 + Analog remains a docs/AI-instruction gap:npm install tailwindcss @tailwindcss/vitetailwindcss()invite.config.ts@import "tailwindcss"instyles.csstailwindCss.rootStylesheetso@applyworks in component styles8. Node 24 — already supported (section kept for the record)
Merged work: #31934, #33401, #33441, #33542, #34261.
Correction to the April text: native TypeScript stripping is no longer opt-in. It is the default; set
NX_PREFER_NODE_STRIP_TYPES=falseto force SWC/ts-node.Related PRs
Open
@nx/oxlint; does not replace it.Merged since this issue was filed
@nx/oxlintplugin@nx/oxlintplugin.d.mtscleanupClosed without merge
formatteralready onmaster; oxfmt is #35089Environment
origin/master@44b3072207)26.x / 24.x / ^22.12.0as the current range; this is not a Node-24-only tree.@analogjs/vitest-angular/@analogjs/vite-plugin-angular2.7.0 (latest 2.x) / 3.0.0-alpha.70 (latest 3.x prerelease). Nxmasterstill pins both at~2.6.0.^9.8.0(v10 not in the compat map yet). Analog alpha uses ESLint 10.@nx/oxlintpin^1.75.0(floor 1.70.0). npm latest1.78.0.1.78.0(proposed in feat(linter): add setup-oxlint-bridge generator for ESLint/Oxlint coexistence #35114)master; feat(core): add built-in support for oxfmt formatter alongside prettier #35089 pins^0.60.0, npm latest0.63.0master; feat(js): add tsdown executor and bundler option for library generator #35112 pins^0.21.0, npm latest0.22.14master; feat(bundling): integrate oxc-transform for TypeScript declaration generation #35113 pins^0.144.0(matches npm latest)All reactions