8000 perf(ui): pre-compile Angular UI on host and package via single-stage static container by VLukiantsev · Pull Request #740 · google/xmc · GitHub
[go: up one dir, main page]

Skip to content

perf(ui): pre-compile Angular UI on host and package via single-stage static container - #740

Merged
VLukiantsev merged 18 commits into
mainfrom
perf/e2e-ui-packaging-optimization
Sep 3, 2026
Merged

VLukiantsev merged 18 commits into
mainfrom
perf/e2e-ui-packaging-optimization

Conversation

@VLukiantsev
@VLukiantsev VLukiantsev commented Sep 2, 2026 •
Copy link
Copy Markdown
Collaborator

Overview (Layer 2 of Stack #742)

Part 2 of 3 in Stack #742:

Summary & Rationale

Optimizes Angular UI compilation and container packaging via a two-tier build strategy:

  1. Fast Path (Single-Stage OCI Packaging):
    • When pre-compiled assets exist (dist/browser/index.html), packages immediately into a minimal nginx:alpine container in 2–3 seconds in cmd/ui/build_ui_oci.py.
  2. Fallback Path (Containerized Build):
    • If pre-compiled assets do not exist, falls back to standard containerized multi-stage Docker build (node:22-alpine -> nginx:alpine) with package.json layer caching.
  3. Host Pre-compilation & Caching in E2E Test Suite:
    • Adds host-level Angular compilation in test/e2e/lib/image_builder.py when Node.js/npm are available.
    • Checks bundle staleness against source file modification times and wipes stale dist before fallback.
    • Caches npm dependencies via .install-success sentinel inside node_modules, skipping npm ci when only application sources change.
  4. Documentation & Comprehensive Unit Test Coverage:
    • Documents the UI container packaging architecture, build targets, and pre-compilation flow in cmd/ui/README.md.
    • Adds thorough unit tests in cmd/ui/build_ui_oci_test.py covering import rewriting, flat directory copying, symlink cycle and traversal protection, and container build/save execution.
  5. Bazel Hermeticity:
    • Exposes dist/**/* in Bazel genrule (cmd/ui/BUILD.bazel) with allow_empty = True.
    • Exposes build_ui_oci_lib and build_ui_oci_test Bazel targets.

Diff Sizing

  • Production Code: ~348 net lines across 3 files
  • Test Code: ~578 lines across 2 files
  • Documentation: ~42 lines across 1 file
  • Total Diff: ~968 lines (Threshold: <= 400 prod / <= 1000 total / <= 1000 doc)

Touchpoint Files

  • cmd/ui/BUILD.bazel
  • cmd/ui/README.md
  • cmd/ui/build_ui_oci.py
  • cmd/ui/build_ui_oci_test.py
  • test/e2e/lib/image_builder.py
  • test/e2e/lib/image_builder_test.py

Verification Evidence

  • bazel test //cmd/ui:build_ui_oci_test (14/14 passed in 1.1s).
  • bazel test //cmd/ui:server_test (12/12 passed in 1.0s).
  • bazel test //test/e2e/lib:image_builder_test (14/14 passed in 0.8s).
  • PYTHONPATH=cmd/ui python3 -m unittest discover -s cmd/ui -p "*_test.py" (26/26 passed).
  • Verified pre-commit hooks (./.githooks/pre-commit) passed cleanly.

Mandatory Assumptions Disclosure

  • Host Toolchain: Assumes that when Node.js, npm, and npx are available on the host runner, they are compatible with Angular CLI v19; otherwise, the pipeline safely falls back to containerized Docker builds.
  • Pre-compiled Assets: Assumes that when dist/browser/index.html is fresher than all UI source files, it represents a valid build of the current working tree.

Stack created with GitHub Stacks CLI • Give Feedback 💬

TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f

@gemini-code-assist gemini-code-assist Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request optimizes the Angular UI container build process by allowing the host to pre-compile the UI bundle when Node.js and npm are available, enabling a faster single-stage Nginx container build. It also updates the Bazel build rules and directory filtering to support this workflow. Feedback on this PR highlights a potential caching bug where modifying UI source files will not trigger a recompilation because the build script only checks for the existence of the index.html file. It is recommended to compare the modification times of the source files against the compiled bundle to ensure the cache is not stale.

Comment thread test/e2e/lib/image_builder.py Resolved
@VLukiantsev
Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request optimizes the Angular UI container build process by utilizing a pre-compiled UI bundle on the host when available, falling back to a containerized build otherwise. It also introduces host-side pre-compilation during E2E test setup if Node.js and npm are present. The reviewer feedback focuses on further build optimizations: ignoring irrelevant files (such as Python and Bazel files) when preparing the Docker build context and checking for stale UI builds, and avoiding redundant 'npm ci' executions by checking the status of 'node_modules' and 'package-lock.json'.

Comment thread cmd/ui/build_ui_oci.py Resolved
Comment thread test/e2e/lib/image_builder.py Resolved
Comment thread test/e2e/lib/image_builder.py Resolved
@VLukiantsev
Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request optimizes the Angular UI build process by introducing host-side pre-compilation when Node.js and npm are available, and utilizing a fast single-stage Nginx container build when a pre-compiled bundle is detected. It also refactors directory copying and cleanup using temporary directories. Feedback was provided to ensure that _is_ui_dist_stale uses followlinks=True during directory traversal to maintain consistency with copy_flat and correctly detect changes in symlinked directories.

Comment thread test/e2e/lib/image_builder.py Resolved
@VLukiantsev
Copy link
Copy Markdown
Collaborator Author

/gemini review

8000
@gemini-code-assist gemini-code-assist Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request optimizes the Angular UI container build process by introducing host-side pre-compilation when Node.js and npm are available, falling back to a containerized build if needed. It adds staleness checks to prevent redundant builds and refactors the build script to use a temporary directory. The review feedback recommends creating the temporary directory within the workspace to avoid Docker path-sharing issues in environments like macOS/Windows, and explicitly verifying the availability of npx alongside node and npm to prevent runtime failures.

Comment thread cmd/ui/build_ui_oci.py Resolved
Comment thread test/e2e/lib/image_builder.py Resolved
@VLukiantsev
Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request optimizes the Angular UI container build process by supporting a fast single-stage Nginx container build when a pre-compiled UI bundle is present, and introduces host-side pre-compilation during E2E test setup to speed up builds. Feedback on these changes suggests refactoring a verbose package file modification check using a cleaner generator expression, reducing test code duplication by moving the common E2EConfig setup into a setUp method, and removing a redundant assertion loop in the tests.

Comment thread test/e2e/lib/image_builder.py Resolved
Comment thread test/e2e/lib/image_builder_test.py Resolved
Comment thread test/e2e/lib/image_builder_test.py Resolved
@VLukiantsev
Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request optimizes the UI container build process by supporting fast single-stage Nginx builds when a pre-compiled Angular UI bundle is present, and introduces host-side pre-compilation during E2E tests if Node.js is available. The review feedback highlights two issues in cmd/ui/build_ui_oci.py: a critical bug where creating the temporary directory inside the UI source directory causes infinite recursion during file copying and potential Bazel sandbox write violations, and an unprotected os.makedirs call that could crash the build on permission or path conflicts.

Comment thread cmd/ui/build_ui_oci.py Resolved
Comment thread cmd/ui/build_ui_oci.py Resolved
@VLukiantsev
Copy link
Copy Markdown
Collaborator Author

/gemini review

10000
@gemini-code-assist gemini-code-assist Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request optimizes the Angular UI build process by introducing host-based pre-compilation when Node.js is available, allowing the OCI image build to bypass the heavy multi-stage Node container build in favor of a fast, single-stage Nginx container. It also updates the Bazel configuration, refactors the build script to use temporary directories, and adds comprehensive E2E test coverage. The review feedback highlights three key areas for improvement: implementing a staleness check in the Bazel build script to prevent packaging outdated prebuilt assets, avoiding silently swallowing OSError during file copying to prevent silent build failures, and using a reliable sentinel file instead of directory modification times to detect stale node_modules dependencies.

Comment thread cmd/ui/build_ui_oci.py Resolved
Comment thread cmd/ui/build_ui_oci.py Resolved
Comment thread test/e2e/lib/image_builder.py Resolved
@VLukiantsev
Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces host-side pre-compilation of the Angular UI during E2E testing to speed up builds. If Node.js and npm are available on the host, the UI is compiled locally, allowing the OCI image builder (build_ui_oci.py) to perform a fast single-stage Nginx build instead of a multi-stage container build. Feedback on this PR highlights that comparing file modification times (getmtime) inside a Bazel genrule sandbox is unreliable due to Bazel zeroing out mtimes for build reproducibility. It is recommended to simplify the check in build_ui_oci.py to only verify the existence of the prebuilt directory and index.html file.

Comment thread cmd/ui/build_ui_oci.py Resolved
@VLukiantsev
Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a host-side pre-compilation mechanism for the Angular UI to speed up OCI image builds during E2E testing. If Node.js is available on the host, the UI is compiled locally and packaged into a fast, single-stage Nginx container; otherwise, it falls back to a multi-stage Docker build. The review feedback suggests optimizing the fallback Dockerfile's layer caching by copying package files before the rest of the source code, and ensuring that any corrupted host dependency installations are invalidated by deleting the package-lock marker on compilation failure.

Comment thread cmd/ui/build_ui_oci.py Resolved
Comment thread test/e2e/lib/image_builder.py Resolved
@VLukiantsev
Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request optimizes the Angular UI container build process by supporting host-side pre-compilation and fast single-stage Nginx builds when a pre-compiled bundle is available. It also updates the Bazel build configuration, uses temporary directories for builds, and adds comprehensive unit tests. The review feedback suggests tracking visited directories during directory traversal to prevent infinite loops from circular symlinks, and avoiding the deletion of the package lock file on compilation failures to preserve the developer inner loop.

Comment thread cmd/ui/build_ui_oci.py Resolved
Comment thread test/e2e/lib/image_builder.py Resolved
Comment thread test/e2e/lib/image_builder.py Resolved
Comment thread test/e2e/lib/image_builder_test.py Resolved
@VLukiantsev
Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces host-side pre-compilation of the Angular UI to speed up E2E test image builds, allowing a fast single-stage Nginx container build when a pre-compiled bundle is present. Feedback on these changes highlights a potential path traversal vulnerability in build_ui_oci.py when traversing symlinks with followlinks=True. Additionally, the reviewer suggests replacing the fragile check on node_modules/.package-lock.json with a robust custom sentinel file to track successful npm installations, along with corresponding updates to the unit tests.

Comment thread cmd/ui/build_ui_oci.py Resolved
Comment thread test/e2e/lib/image_builder.py Resolved
Comment thread test/e2e/lib/image_builder_test.py Resolved
@VLukiantsev
Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request optimizes the Angular UI container image build process by allowing host-based pre-compilation when Node.js and npm are available, falling back to a containerized build otherwise. It also introduces staleness checks to avoid redundant builds and adds comprehensive unit tests. The review feedback suggests improving error handling during the cleanup of the dist directory on host compilation failure by catching FileNotFoundError explicitly instead of ignoring all errors, which could otherwise lead to silent build failures.

Comment thread test/e2e/lib/image_builder.py Resolved
Comment thread test/e2e/lib/image_builder_test.py Resolved
@VLukiantsev
Copy link
Copy Markdown
Collaborator Author

/gemini review

10BC8
@gemini-code-assist
Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@VLukiantsev
VLukiantsev force-pushed the perf/e2e-ui-packaging-optimization branch from fdbec2e to e636d04 Compare September 2, 2026 15:33
@VLukiantsev
Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a two-tier container build strategy for the Angular UI, enabling a fast path that packages pre-compiled host assets directly into Nginx, and a fallback path for containerized multi-stage compilation. Feedback on these changes suggests resolving real paths of subdirectories during directory traversal to prevent symlinks from bypassing ignored directories, and catching OSError instead of only FileNotFoundError when cleaning up directories to prevent potential crashes.

Comment thread cmd/ui/build_ui_oci.py Resolved
Comment thread test/e2e/lib/image_builder.py Resolved
Comment thread test/e2e/lib/image_builder.py Resolved
Comment thread test/e2e/lib/image_builder.py Resolved
… static container

Accelerate UI container creation by supporting single-stage Nginx packaging
when pre-compiled assets are present in dist/browser. Update Bazel genrule
to include dist assets and add host-level pre-compilation check in E2E
ImageBuilder with graceful fallback to containerized multi-stage build.

TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
Add _is_ui_dist_stale to check modification times of UI source files
against dist/browser/index.html to prevent stale bundles in local runs.
Remove corrupt dist directory on compilation failure before fallback.

Comment link: #740 (comment)
TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
…uilds

- Exclude Python (.py) and Bazel (BUILD.bazel) files from Docker build context
  and UI staleness check.
- Conditionally run npm ci only when node_modules is missing or package-lock.json
  is newer.
- Add unit tests in image_builder_test.

Comment links:
- #740 (comment)
- #740 (comment)
- #740 (comment)
TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
- Exclude __pycache__ and BUILD files from Docker context and stale detection.
- Add OSError exception handling to copy_flat to safely skip unreadable files.
- Evaluate both package.json and package-lock.json mtime for npm dependencies.

TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
…stale

Add followlinks=True to os.walk in _is_ui_dist_stale to maintain
consistency with copy_flat and detect modifications in symlinked dirs.

Comment link: #740 (comment)
TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
- Create temporary directory within ui_src_dir in build_ui_oci.py to prevent
  Docker Desktop path sharing issues on macOS/Windows.
- Explicitly check for npx in _maybe_precompile_ui to prevent runtime failures.
- Add unit test for missing npx in image_builder_test.

Comment links:
- #740 (comment)
- #740 (comment)
TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
- Use any() generator expression for package file mtime check in image_builder.py.
- Deduplicate E2EConfig initialization using setUp in image_builder_test.py.
- Remove redundant assertNotIn loop in test_maybe_precompile_ui_skips_npm_ci_when_node_modules_fresh.

Comment links:
- #740 (comment)
- #740 (comment)
- #740 (comment)
TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
- Use system temporary directory instead of ui_src_dir to eliminate infinite
  recursion in copy_flat when has_prebuilt_dist is False and prevent sandbox violations.
- Protect os.makedirs with try-except OSError in copy_flat.

Comment links:
- #740 (comment)
- #740 (comment)
TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
…ck sentinel

- Verify dist freshness against UI source files in build_ui_oci.py before using fast container build.
- Raise and log on OSError during file copying in copy_flat.
- Use node_modules/.package-lock.json sentinel file mtime in image_builder.py.

Comment links:
- #740 (comment)
- #740 (comment)
- #740 (comment)
TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
- Remove mtime-based staleness check in build_ui_oci.py as Bazel normalizes
  timestamps inside sandboxes for reproducibility.
- Rely on image_builder.py's host-side staleness detection and compilation.

Comment link: #740 (comment)
TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
…ules lock on failure

- Copy package.json and package-lock.json first in fallback Dockerfile for layer caching.
- Invalidate node_modules/.package-lock.json when host compilation fails to force clean install on subsequent runs.
- Update failure cleanup test to assert removal of the lockfile.

Comment links:
- #740 (comment)
- #740 (comment)
TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
…lock

- Track visited directory real paths in copy_flat and _is_ui_dist_stale to prevent
  infinite loops from circular symlinks.
- Retain node_modules lock file on compilation failure to preserve developer inner loop.

Comment links:
- #740 (comment)
- #740 (comment)
- #740 (comment)
- #740 (comment)
TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
…ss sentinel

- Skip files resolving outside src_dir in copy_flat to prevent path traversal vulnerabilities.
- Use explicit .install-success sentinel file in node_modules to reliably detect completed npm installations.
- Update fresh node_modules unit test to verify .install-success sentinel.

Comment links:
- #740 (comment)
- #740 (comment)
- #740 (comment)
TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
- Catch FileNotFoundError explicitly instead of silently ignoring all errors during
  shutil.rmtree of dist on compilation failure.
- Update failure cleanup unit test to assert rmtree called without ignore_errors.

Comment links:
- #740 (comment)
- #740 (comment)
TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
…ing strategy

- Add module docstring and section comments in build_ui_oci.py detailing
  the fast single-stage Nginx path vs containerized fallback path.
- Add comprehensive docstrings and comments in image_builder.py explaining
  UI staleness checks, host pre-compilation, and the build_all lifecycle.

TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
…oubles

- Check bundle staleness and wipe stale dist before returning on missing
  Node toolchain, preventing obsolete assets from bypassing container fallback.
- Log warning on failure to write .install-success sentinel.
- Hermetically mock getmtime and verify sentinel creation with mock_open.
- Remove phantom @patch("os.path.isdir") double from image_builder_test.py.
- Add unit tests verifying stale dist is wiped when Node is missing.

TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
- Filter subdirectories whose real paths contain ignored directories in copy_flat
  and _is_ui_dist_stale to prevent traversing symlinked node_modules/dist.
- Catch OSError and log warnings on rmtree failures in _maybe_precompile_ui.
- Add unit tests verifying symlink directory filtering and rmtree error handling.

Comment links:
- #740 (comment)
- #740 (comment)
- #740 (comment)
- #740 (comment)
TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
@VLukiantsev
VLukiantsev force-pushed the perf/e2e-ui-packaging-optimization branch from 0132227 to 256f539 Compare September 3, 2026 09:44
…g in README

- Add comprehensive unit tests in cmd/ui/build_ui_oci_test.py covering
  get_sha256, translate_imports, copy_flat, and main fast/fallback paths.
- Add py_library and py_test targets for build_ui_oci in cmd/ui/BUILD.bazel.
- Add minimal cmd/ui/README.md documenting UI container packaging architecture,
  build commands, and E2E test runner host pre-compilation.

TAG=agy
CONV=bb2cc767-c0e5-4adc-a341-a2d0b23e2f4f
@VLukiantsev
VLukiantsev marked this pull request as ready for review September 3, 2026 10:07
@github-actions
github-actions Bot requested a review from janzak-dev September 3, 2026 10:08
@VLukiantsev
VLukiantsev added this pull request to the merge queue Sep 3, 2026
Merged via the queue into main with commit c14600f Sep 3, 2026
12 checks passed
@VLukiantsev
VLukiantsev deleted the perf/e2e-ui-packaging-optimization branch September 3, 2026 12:43
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.

2 participants

0