Skip to content

perf(ci): build only the frontend projects the WAR actually contains (#36945) - #36946

Open
wezell wants to merge 3 commits into
mainfrom
issue-36944-build-only-what-war-needs
Open

perf(ci): build only the frontend projects the WAR actually contains (#36945)#36946
wezell wants to merge 3 commits into
mainfrom
issue-36944-build-only-what-war-needs

Conversation

@wezell

@wezell wezell commented Aug 7, 2026

Copy link
Copy Markdown
Member

Fixes #36945 (frontend half; the Maven reactor trim is still open on that issue).

The artifact build ran nx run-many -t build over the whole workspace. The WAR contains four of those projects:

core-web/pom.xml webResources
  dist/apps/dotcms-ui                    -> dotAdmin
  dist/libs/dotcms-webcomponents/dist
  dist/apps/dotcms-binary-field-builder
  dist/apps/dotcms-block-editor
  dist/libs/sdk/analytics-standalone     <- built by its own `build-analytics` execution

Everything else it built — sdk-*, ai-evals, dotcdn — is never packaged and never reused. Both SDK publishers (deploy-javascript-sdk, and publish-sdk-next on trunk) start from a clean checkout and rebuild sdk-* themselves; deploy-javascript-sdk even passes --skip-nx-cache. That work was thrown away every single build.

Why this lands twice

The execution is bound to the compile phase, so it runs in more than the build job:

before
Initial Artifact Build ~2.85m of nx build, on the serial prefix that gates every test job
Frontend Unit Tests 33m — mvn test -pl :dotcms-core-web runs compile first, so a full workspace build ran before nx affected -t test did anything

The second one is the surprise: that job's cost is mostly the build, not the tests. unit-test is already nx affected.

Why narrowing is safe

  • nx.json targetDefaults.build has dependsOn: ["^build"], so each leaf project still builds its dependency libs. Listing the four leaves is sufficient.
  • targetDefaults.test has no ^build dependency and runs against source, so unit tests are unaffected.
  • The four names were read from their project.json files, and the list mirrors the webResources block directly above it in the same pom.

The list is a <nx.build.projects> property so a profile can widen it, with a comment tying it to webResources so the two stay in sync.

Verification

pom.xml parses; the four project names confirmed against apps/*/project.json and libs/dotcms-webcomponents/project.json. Not run locally (the worktree has no node_modules) — CI is the check, and the signal to watch is that dotAdmin and the three sibling apps are still present in the built WAR.

Note

I originally expected nx caching to be the bigger win here. It is not something to reach for blindly: .nx/cache is 2.0 GB on a working machine, and the GitHub Actions cache is 10 GB per repo with LRU eviction — a naive actions/cache would compete with the Maven repo cache and could make builds slower. Doing that properly needs a real remote cache, which is a separate decision. This PR is the part that needs no new infrastructure.

The artifact build ran `nx run-many -t build` across the whole workspace, which
builds the sdk-* packages, ai-evals and dotcdn alongside the four apps the WAR
ships. Those outputs are never packaged and never reused:

  core-web/pom.xml webResources lists exactly
    dist/apps/dotcms-ui                    -> dotAdmin
    dist/libs/dotcms-webcomponents/dist    -> dotcms-webcomponents
    dist/apps/dotcms-binary-field-builder
    dist/apps/dotcms-block-editor
    dist/libs/sdk/analytics-standalone     -> built by its own execution

and both SDK publishers (deploy-javascript-sdk, and publish-sdk-next on trunk)
start from a clean checkout and rebuild sdk-* themselves - deploy-javascript-sdk
even passes --skip-nx-cache. So every SDK build in the artifact phase was thrown
away.

Narrowing to the four leaf projects is safe: nx targetDefaults gives `build` a
`dependsOn: ["^build"]`, so their dependency libs still build. `test` has no
such dependency and runs against source, so unit tests are unaffected.

This lands in two places, because the execution is bound to the `compile` phase:

  Initial Artifact Build   ~2.85m of nx build, on the SERIAL prefix that gates
                           every test job
  Frontend Unit Tests      `mvn test -pl :dotcms-core-web` runs compile first,
                           so this 33m job was dominated by a full workspace
                           build before `nx affected -t test` ran at all

The project list is a property so a profile can widen it, and it sits next to a
comment pointing at the webResources block it mirrors.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NH4Pes5S9d1AQorJBNeFJU
@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Claude finished @wezell's task in 1m 58s —— View job


Code Review

  • Read PR diff (core-web/pom.xml)
  • Verify the four/five leaf names against project.json files
  • Cross-check nx.build.projects vs the webResources block
  • Review the validate-phase drift guard

New Issues

  • 🟡 Medium: core-web/pom.xml:135-168 — The drift guard is a third hardcoded list that must itself be kept in sync with webResources. It only fails when one of its five hardcoded dotcms-ui / dotcms-webcomponents / dotcms-binary-field-builder / dotcms-block-editor / edit-content-bridge names is missing from nx.build.projects. If a developer later adds a new <resource> to webResources (a 6th packaged app), nothing forces them to add a matching <condition>/<fail> pair here — so the exact drift this guard exists to prevent (a packaged asset that nx.build.projects never builds) can still happen silently for any newly added resource. The comment claims it "fails the build if they drift," but it only guards drift for the five entries someone remembered to enumerate. A data-driven check that reads the webResources directories would be robust; short of that, a comment at the webResources block itself ("if you add a resource here, add a guard condition in validate-nx-build-projects-sync") would at least point the next editor at the guard. Non-blocking.

  • 🟡 Medium: core-web/pom.xml:143-166 — The guard uses Ant <contains substring=...>, which is a loose substring match, not an exact project-name match. If nx.build.projects were ever edited to e.g. dotcms-ui-preview while dropping dotcms-ui, the substring="dotcms-ui" condition still passes (false negative) even though -p dotcms-ui-preview would no longer build the real dotcms-ui and the WAR would ship a stale dotAdmin. Low likelihood, but the substring approach weakens the guarantee the guard is meant to provide. Non-blocking.

Notes (not blocking)

  • The new command drops --exclude=tag:skip:build (previously on run-many). That's correct here — with an explicit -p project list the exclude is moot, and none of the five listed leaves carry a skip:build tag (confirmed in their project.json files).
  • dependsOn: ["^build"] reasoning checks out: dotcms-ui has implicitDependencies: ["dotcms-webcomponents"], so its libs still build; and dotcms-webcomponents is explicitly listed regardless.
  • All five names resolve to real project.json entries; the edit-content-bridge output path (dist/libs/edit-content-bridge) matches its webResources directory. The analytics-standalone exclusion is correct — it's built by the separate build-analytics execution.
  • The property value is a single comma-joined line with no whitespace, which is what -p ${nx.build.projects} needs.

Solid, well-reasoned change — the two Medium items are about the durability of the guard, not correctness of this build. Nothing blocking.

· issue-36944-build-only-what-war-needs

@wezell wezell changed the title perf(build): build only the frontend projects the WAR actually contains (#36945) perf(ci): build only the frontend projects the WAR actually contains (#36945) Aug 7, 2026

@sfreudenthaler sfreudenthaler left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change is good and welcome, just one improvement i want to add in

Comment thread core-web/pom.xml Outdated
nx.build.projects is hand-maintained to mirror the webResources block below
it, per the comment added in this PR. Add a validate-phase check that fails
the build if a webResources project isn't covered, and fix the drift it
immediately catches: edit-content-bridge is packaged into the WAR but wasn't
in nx.build.projects, so it would have silently stopped building once the
`-p ${nx.build.projects}` narrowing landed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KDuKM6fQzm3hR1oShY3EPY
@sfreudenthaler

Copy link
Copy Markdown
Member

Pushed a follow-up commit adding the drift guard we discussed: a validate-phase Ant check that fails the build if a webResources project isn't covered by nx.build.projects (or has its own dedicated execution, like analytics-standalone).

It immediately caught a real gap: edit-content-bridge is packaged into the WAR (html/js/legacy_custom_field_bridge) but wasn't in nx.build.projects, and nothing else in the four leaf projects appears to import it — so it would have silently stopped building once -p ${nx.build.projects} landed. Added it to the property alongside the guard.

@wezell wezell added the CI : No Fail Fast Run every test suite to completion instead of cancelling the matrix on first failure label Aug 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area : Frontend PR changes Angular/TypeScript frontend code CI : No Fail Fast Run every test suite to completion instead of cancelling the matrix on first failure

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

CI: artifact build compiles frontend and backend modules the WAR never contains

2 participants