Part of #607.
Describe the bug
import { LlmAgent } from '@google/adk' in a browser bundle resolves to the Node build (dist/esm), which pulls fs, path, http, zlib and fails.
core/package.json does declare a top-level browser field:
"browser": "./dist/web/index_web.js",
but it is never consulted, because the exports map takes precedence over the legacy browser field in every modern bundler, and exports has no browser condition:
"exports": {
".": {
"types": "./dist/types/index.d.ts",
"import": "./dist/esm/index.js",
"require": "./dist/cjs/index.js",
"default": "./dist/esm/index.js"
}
}
Second problem: "." is the only declared subpath, so a consumer cannot opt in by hand either — @google/adk/dist/web/index_web.js is rejected by the exports map:
✘ [ERROR] Could not resolve "@google/adk/dist/web/index_web.js"
The path "./dist/web/index_web.js" is not exported by package "@google/adk"
The web build is therefore unreachable by name. The only way to reach it today is a relative path into node_modules, or a bundler alias.
To Reproduce
echo "import {LlmAgent} from '@google/adk';" > t.ts
npx esbuild t.ts --bundle --platform=browser --target=chrome138
# 625 errors: Could not resolve "fs" / "path" / "http" / "zlib" / ...
# (i.e. it resolved dist/esm, the Node build)
echo "import {LlmAgent} from '@google/adk/dist/web/index_web.js';" > t2.ts
npx esbuild t2.ts --bundle --platform=browser
# ✘ [ERROR] ... is not exported by package "@google/adk"
Expected behavior
import from '@google/adk' with --platform=browser (or Vite/webpack/Rollup browser targets) should resolve dist/web.
Proposed fix
core/package.json — add a browser condition, and expose the web subpath:
"exports": {
".": {
"types": "./dist/types/index.d.ts",
+ "browser": "./dist/web/index_web.js",
"import": "./dist/esm/index.js",
"require": "./dist/cjs/index.js",
"default": "./dist/esm/index.js"
- }
+ },
+ "./dist/web/*": "./dist/web/*",
+ "./package.json": "./package.json"
},
Two ordering notes that matter:
"browser" must come before "import"/"require". Conditions are matched in declaration order, and import would otherwise win for ESM browser bundles.
"types" stays first so TypeScript keeps resolving declarations.
Consider a "worker" condition too, pointing at the same web entry — relevant for Cloudflare Workers and similar, though note the Chrome Prompt API is unavailable in Web Workers so it is not needed for that use case.
Related: dist/web ships no type declarations
Once the subpath is reachable, deep imports are implicitly any, because declarations live in dist/types with nothing beside dist/web/*.js. In my project I worked around this by pointing tsc at dist/types and esbuild at dist/web for the same specifier, via paths + an alias.
A types condition on the subpath export would remove the need:
"./dist/web/*": { "types": "./dist/types/*", "default": "./dist/web/*" }
Happy to split that into its own issue if preferred.
Verification
# should resolve dist/web, not dist/esm
npx esbuild t.ts --bundle --platform=browser --target=chrome138
Note this fix alone does not produce a clean bundle — it correctly routes to dist/web, which still has the defects in #608 (unparseable apigee_llm.js), #609 (createRequire banner) and the remaining Node leakage. #608 in particular must land or this change simply surfaces a different error.
Environment
@google/adk main @ 8944bfb, core v1.5.0 (also reproduced on published 1.4.0)
Part of #607.
Describe the bug
import { LlmAgent } from '@google/adk'in a browser bundle resolves to the Node build (dist/esm), which pullsfs,path,http,zliband fails.core/package.jsondoes declare a top-levelbrowserfield:but it is never consulted, because the
exportsmap takes precedence over the legacybrowserfield in every modern bundler, andexportshas nobrowsercondition:Second problem:
"."is the only declared subpath, so a consumer cannot opt in by hand either —@google/adk/dist/web/index_web.jsis rejected by the exports map:The web build is therefore unreachable by name. The only way to reach it today is a relative path into
node_modules, or a bundler alias.To Reproduce
Expected behavior
import from '@google/adk'with--platform=browser(or Vite/webpack/Rollup browser targets) should resolvedist/web.Proposed fix
core/package.json— add abrowsercondition, and expose the web subpath:"exports": { ".": { "types": "./dist/types/index.d.ts", + "browser": "./dist/web/index_web.js", "import": "./dist/esm/index.js", "require": "./dist/cjs/index.js", "default": "./dist/esm/index.js" - } + }, + "./dist/web/*": "./dist/web/*", + "./package.json": "./package.json" },Two ordering notes that matter:
"browser"must come before"import"/"require". Conditions are matched in declaration order, andimportwould otherwise win for ESM browser bundles."types"stays first so TypeScript keeps resolving declarations.Consider a
"worker"condition too, pointing at the same web entry — relevant for Cloudflare Workers and similar, though note the Chrome Prompt API is unavailable in Web Workers so it is not needed for that use case.Related:
dist/webships no type declarationsOnce the subpath is reachable, deep imports are implicitly
any, because declarations live indist/typeswith nothing besidedist/web/*.js. In my project I worked around this by pointingtscatdist/typesand esbuild atdist/webfor the same specifier, viapaths+ an alias.A
typescondition on the subpath export would remove the need:Happy to split that into its own issue if preferred.
Verification
# should resolve dist/web, not dist/esm npx esbuild t.ts --bundle --platform=browser --target=chrome138Note this fix alone does not produce a clean bundle — it correctly routes to
dist/web, which still has the defects in #608 (unparseableapigee_llm.js), #609 (createRequirebanner) and the remaining Node leakage. #608 in particular must land or this change simply surfaces a different error.Environment
@google/adkmain@8944bfb,corev1.5.0 (also reproduced on published 1.4.0)