Skip to content

feat: download ADK Web assets dynamically and serve from shared folder#427

Open
kalenkevich wants to merge 2 commits into
mainfrom
feat/update-adk-web-ui
Open

feat: download ADK Web assets dynamically and serve from shared folder#427
kalenkevich wants to merge 2 commits into
mainfrom
feat/update-adk-web-ui

Conversation

@kalenkevich

Copy link
Copy Markdown
Collaborator

Please ensure you have read the contribution guide before creating a pull request.

Link to Issue or Description of Change

Problem:

  • Keeping pre-compiled browser assets tracked in the repository source tree (dev/src/browser) bloats the codebase, clutters git history, and is error-prone to maintain.
  • Furthermore, copying these assets into both the dist/esm/browser and dist/cjs/browser targets duplicates the assets (~5MB each), resulting in unnecessary package bloat for @google/adk-devtools.

Solution:

  • Automated Asset Downloader & Cache: Added an automated downloader (downloadFile) and extractor (ensureBrowserAssets) in dev/build.js to dynamically fetch the ADK Web UI release v1.0.0 from GitHub and cache the zip locally in dev/.cache/.
  • Shared Output Folder: Extracted the zip assets exactly once to dist/browser inside the build output. Modified AdkApiServer (dev/src/server/adk_api_server.ts) to serve /dev-ui from ../../browser relative to the compiled server files, allowing both ESM and CommonJS targets to share dist/browser and saving 50% of package asset space.
  • Untrack Source Assets: Completely deleted the local dev/src/browser directory and added dev/.cache/ to .gitignore.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

Summary of passed npm test results:
Ran the full devtools unit test suite: npx vitest run dev/test

 RUN  v3.2.4 /Users/kalenkevich/projects/adk-js

 Test Files  14 passed (14)
      Tests  177 passed (177)
   Start at  16:34:58
   Duration  8.45s

Manual End-to-End (E2E) Tests:

Tested by running a clean build setup from scratch:

  1. Ran npm run clean:all to delete node_modules and all dist/ folders.
  2. Ran npm install.
  3. Ran npm run build.
    • The build output correctly showed:
      [ADK Build] ADK Web zip not cached. Fetching v1.0.0 from GitHub...
      [ADK Build] Downloaded and cached ADK Web v1.0.0.
      [ADK Build] Extracting ADK Web assets to dist/browser...
      [ADK Build] ADK Web assets successfully populated.
      
  4. Verified that dist/browser/ contains all Web UI files, and that no dev/src/browser/ folder was created in the source tree.
  5. Ran npm run build again. Output correctly skipped the download/extraction (runs instantly) because dist/browser/.version matches.
  6. Verified by running WebUI integration tests (npx vitest run tests/integration/adk_web/webui_test.ts) which verify /dev-ui serves the correct html containing <app-root>: Passed (2/2 tests).

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

Additional context

This is a follow-up optimization of the ADK Web UI serving architecture. It keeps binary-compiled assets out of source control and reduces the published npm package size by sharing a single output directory.

- Remove pre-compiled `dev/src/browser` assets from git tracking to keep the repository source tree clean.
- Update `dev/build.js` to automatically download and cache `v1.0.0` release assets from GitHub, and extract them directly into `dist/browser`.
- Modify the static path in `AdkApiServer` (`dev/src/server/adk_api_server.ts`) to serve `/dev-ui` from `../../browser` relative to target compiled outputs, enabling both ESM and CommonJS distributions to share a single `dist/browser` directory.
- Update `.gitignore` to ignore the local `dev/.cache/` folder and untrack the old `dev/src/browser/` folder.

@AmaadMartin AmaadMartin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Couple comments

Comment thread dev/build.js
) {
// Follow redirect
downloadFile(response.headers.location, dest)
.then(resolve)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Call response.resume() before recursing/returning here to ensure the redirected response stream is fully consumed and socket resources are released.

Comment thread dev/build.js
);
} else {
execSync(`unzip -o "${zipPath}" -d "${destDir}"`);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Since adm-zip was recently added to the core workspace dependencies, we can use it here as a platform-independent JS library for unzipping, instead of spawning child processes for unzip (which might be missing on minimal Linux environments) or powershell (which can have execution policies block it):

import AdmZip from 'adm-zip';

function unzipFile(zipPath, destDir) {
  const zip = new AdmZip(zipPath);
  zip.extractAllTo(destDir, true);
}

Make sure to add adm-zip to the dev package dependencies/devDependencies too.

Comment thread dev/build.js
}
const url = `https://github.com/google/adk-web/releases/download/${ADK_WEB_VERSION}/adk-web-browser.zip`;
await downloadFile(url, zipCachePath);
console.log(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

To prevent corrupt cache files if the download gets interrupted mid-way (which would skip downloads and fail during unzipping on subsequent runs), consider downloading to a temporary file (e.g. zipCachePath + '.tmp') and renaming it to zipCachePath only after completion.

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.

3 participants