From 43a80da55c2bf2a6879382df097bb25dde7b088d Mon Sep 17 00:00:00 2001 From: imccyu <276526105+imccyu@users.noreply.github.com> Date: Tue, 20 Oct 2026 01:16:51 +0800 Subject: [PATCH] Revert "feat(webworker-packer): serve package assets beside the preview page" This reverts commit 6e28e787d564ee4933f7a560808fb05ed635e776. --- ...-19-client-plugin-package-assets.i18n.yaml | 12 ++-- ...2026-10-19-client-plugin-package-assets.md | 6 +- ...6-10-19-client-plugin-package-assets.zh.md | 6 +- apps/web/package.json | 2 +- apps/web/tests/preview-boot.e2e.ts | 15 ----- packages/client/modules/README.i18n.yaml | 12 ++-- packages/client/modules/README.md | 4 +- packages/client/modules/README.zh.md | 4 +- .../webworker-packer/README.i18n.yaml | 4 +- .../experimental/webworker-packer/README.md | 5 +- .../webworker-packer/README.zh.md | 5 +- .../experimental/webworker-packer/src/bin.ts | 13 +--- .../experimental/webworker-packer/src/pack.ts | 45 ------------- .../webworker-packer/src/repository.ts | 1 - .../tests/page-assets.spec.ts | 65 ------------------- scripts/client-build-environment.ts | 1 - 16 files changed, 31 insertions(+), 169 deletions(-) delete mode 100644 packages/experimental/webworker-packer/tests/page-assets.spec.ts diff --git a/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.i18n.yaml b/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.i18n.yaml index 044616cbdd..2112efbc14 100644 --- a/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.i18n.yaml @@ -18,8 +18,8 @@ en: 1751930093d55cea zh: 8e92e2de062edb96 /agent-note-client-plugin-package-assets-served-by-url/decision/host-route: - en: ecb36e3f8e05580d - zh: 606207fcc87b7d3b + en: 151b7300f5b27a9f + zh: fae9adff942c2ce8 /agent-note-client-plugin-package-assets-served-by-url/decision/changes-and-package-manifests: en: eedff52d04763c50 zh: 203bfcf81242b8fe @@ -30,8 +30,8 @@ en: 23cca9b55c4252bd zh: a7afb8d1dd943a8b /agent-note-client-plugin-package-assets-served-by-url/consequences: - en: 90f279d7f488d323 - zh: df07115c3fa546d5 + en: f2ec2d1773c3c57c + zh: cec2c0455ff26064 /agent-note-client-plugin-package-assets-served-by-url/testing: - en: 82b3ce0e29724804 - zh: c27c103fb2feb8f8 + en: b1b95226919615c6 + zh: c928aedf738d2b40 diff --git a/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.md b/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.md index 7e2a69c079..3a3b2733be 100644 --- a/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.md +++ b/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.md @@ -36,7 +36,7 @@ The `dsh-package-asset` plugin of the dynamic browser face resolves an import ag `bundleResource` matches `/plugins//assets/` before the bundle tables, and such a path is answered by the asset route alone. For an active client row, the path is percent-decoded once and `createRequire().resolve('/assets/')` applies the package's own exports, so unexported paths, `.` and `..` segments, missing files, and directories do not resolve. The media type comes from the resolved file's extension, because Node reads `#` and `?` in the subpath as URL syntax. Any resolution failure, an inactive package, and an unsupported type answer 404; the query selects nothing. -A served asset streams from disk on every request; the Host keeps neither its bytes nor a hash, and a request the browser cancels mid-stream ends without a warning. It carries the media type, the bundle `cache-control: public, max-age=31536000, immutable`, `etag` equal to the requested path, `x-content-type-options: nosniff`, and, for SVG, `content-security-policy: script-src 'none'`. An `If-None-Match` equal to the tag answers 304 without opening the file; `HEAD` answers without a body. `fetchBundle()` returns the same responses with a streamed body that closes the file when cancelled. The WebWorker preview runs its Host in a Worker that the page's `` and CSS requests never reach, so its [packer](../../../../packages/experimental/webworker-packer/README.md) moves package assets out of the VFS image and the static deployment serves them at `plugins//assets/` beside the preview page. +A served asset streams from disk on every request; the Host keeps neither its bytes nor a hash, and a request the browser cancels mid-stream ends without a warning. It carries the media type, the bundle `cache-control: public, max-age=31536000, immutable`, `etag` equal to the requested path, `x-content-type-options: nosniff`, and, for SVG, `content-security-policy: script-src 'none'`. An `If-None-Match` equal to the tag answers 304 without opening the file; `HEAD` answers without a body. `fetchBundle()` returns the same responses with a streamed body that closes the file when cancelled. ### Changes and package manifests @@ -71,7 +71,7 @@ Images that third-party libraries load themselves (PDF.js fonts, cmaps, wasm, an ## Consequences - The ui-settings-account `client.js` is 214 KB, and the account and ui-chat bundles contain no image data URLs; an image costs one same-origin request when shown and may appear after layout. -- The WebWorker preview serves every package asset in its image from the static deployment, whether or not the package is enabled in the preview, and its VFS image no longer carries them. +- The WebWorker preview reaches `/plugins` only through its tunnel, so `` and CSS requests do not reach the Host running in the Worker; the WebWorker runtime owns serving them. - The Desktop forwarder rewrites `/plugins/` cache headers to `no-store`, so Desktop reads an asset again on each display. - The Host does not compare file contents with the revision in the name: a file under `lib/assets/` edited in place keeps its immutable cache entries. Only the build writes that directory. - `require.resolve` runs synchronously on each request; a local measurement took about 43 µs for an existing file and 170 µs for a missing one. It reads exports through Node's package configuration cache, so an `./assets/*` export edited in place takes effect after boot HMR expires that package or the Host restarts. The route does not check the resolved file's real path, so a symbolic link under `lib/assets/` that leads outside the package is served. @@ -85,4 +85,4 @@ Images that third-party libraries load themselves (PDF.js fonts, cmaps, wasm, an - [assets.client.spec.ts](../../../../packages/client/modules/tests/assets.client.spec.ts) covers media types, the revision, emitted names, and references; [client-asset-types.spec.ts](../../../../scripts/client-asset-types.spec.ts) keeps the type root equal to the table. - [client-bundle-css.spec.ts](../../../../scripts/client-bundle-css.spec.ts) covers emitted names and URLs, CSS rewriting and preserved forms, each build rejection, the Node face guard, one-shot pruning, and watch rebuilds that keep earlier files. - The gate specs reject each invalid manifest or reference form, and [node-half.client.spec.ts](../../../../packages/client/modules/tests/node-half.client.spec.ts) covers declarations, moved exports, and added or removed client declarations after an entry restart, an unchanged restart that publishes nothing and reads no bundle, and a chunk of a package named `@scope/assets`. -- [desktop-onboarding.e2e.ts](../../../../apps/web/tests/desktop-onboarding.e2e.ts) and [reasoning-preview.e2e.ts](../../../../apps/web/tests/reasoning-preview.e2e.ts) assert the package-asset URLs and decode the images in a browser; [preview-boot.e2e.ts](../../../../apps/web/tests/preview-boot.e2e.ts) decodes the ui-chat mask image the WebWorker deployment serves statically, and the packer's [page-assets.spec.ts](../../../../packages/experimental/webworker-packer/tests/page-assets.spec.ts) covers which files leave the image. +- [desktop-onboarding.e2e.ts](../../../../apps/web/tests/desktop-onboarding.e2e.ts) and [reasoning-preview.e2e.ts](../../../../apps/web/tests/reasoning-preview.e2e.ts) assert the package-asset URLs and decode the images in a browser. diff --git a/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.zh.md b/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.zh.md index 6d3a1ffc30..2d296dcd88 100644 --- a/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.zh.md +++ b/.agents/notes/implemented/architecture/2026-10-19-client-plugin-package-assets.zh.md @@ -36,7 +36,7 @@ plugins/@deepseek-ai/dsh-client-ui-chat/assets/running-whale%402x-06738fa29b2f.p `bundleResource` 先于 bundle 表匹配 `/plugins/<包名>/assets/<路径>`,这类路径只由资源路由回答。对启用中的 client 行,路径解码一次后,`createRequire(<包的 manifest>).resolve('<包名>/assets/<路径>')` 套用包自己的 exports,未导出路径、`.` 和 `..` 段、不存在的文件和目录都解析不出来。媒体类型按解析出的文件扩展名判断,因为 Node 会把子路径中的 `#` 和 `?` 当作 URL 语法。任何解析失败、未启用的包和不支持的类型都返回 404;查询串不参与选择。 -被提供的资源每次请求都从磁盘流式读取,Host 既不保存字节也不保存 hash;浏览器中途取消的请求直接结束,不记 warning。响应带媒体类型、与 bundle 相同的 `cache-control: public, max-age=31536000, immutable`、等于请求路径的 `etag`、`x-content-type-options: nosniff`;SVG 另带 `content-security-policy: script-src 'none'`。`If-None-Match` 等于该 tag 时返回 304,且不打开文件;`HEAD` 不带 body。`fetchBundle()` 返回同样的响应,body 为流,取消时关闭文件。WebWorker 预览的 Host 运行在 Worker 中,页面的 `` 和 CSS 请求到达不了它,因此由它的 [packer](../../../../packages/experimental/webworker-packer/README.zh.md) 把包资源移出 VFS 镜像,由静态部署在预览页旁的 `plugins/<包名>/assets/` 提供。 +被提供的资源每次请求都从磁盘流式读取,Host 既不保存字节也不保存 hash;浏览器中途取消的请求直接结束,不记 warning。响应带媒体类型、与 bundle 相同的 `cache-control: public, max-age=31536000, immutable`、等于请求路径的 `etag`、`x-content-type-options: nosniff`;SVG 另带 `content-security-policy: script-src 'none'`。`If-None-Match` 等于该 tag 时返回 304,且不打开文件;`HEAD` 不带 body。`fetchBundle()` 返回同样的响应,body 为流,取消时关闭文件。 ### 变化与包 manifest @@ -71,7 +71,7 @@ plugins/@deepseek-ai/dsh-client-ui-chat/assets/running-whale%402x-06738fa29b2f.p ## Consequences - ui-settings-account 的 `client.js` 为 214 KB,账户和 ui-chat 的 bundle 都不再含图片 data URL;图片显示时多一次同源请求,可能晚于布局出现。 -- WebWorker 预览由静态部署提供镜像中所有包的资源,不论该包在预览中是否启用;VFS 镜像不再携带这些文件。 +- WebWorker 预览只经隧道到达 `/plugins`,`` 和 CSS 请求到不了 Worker 内的 Host;由 WebWorker runtime 负责提供。 - Desktop 转发层把 `/plugins/` 的缓存头改写为 `no-store`,Desktop 每次显示都会重新读取资源。 - Host 不比对文件内容与文件名中的 revision:原地修改 `lib/assets/` 下的文件会保留它的 immutable 缓存。这个目录只由构建写入。 - `require.resolve` 在每次请求时同步执行;本机实测文件存在约 43 µs,不存在约 170 µs。它经 Node 的包配置缓存读取 exports,因此原地修改的 `./assets/*` 导出要等 boot HMR 让该包失效或 Host 重启后才生效。路由不检查解析结果的真实路径,所以 `lib/assets/` 下指向包外的符号链接会被提供。 @@ -85,4 +85,4 @@ plugins/@deepseek-ai/dsh-client-ui-chat/assets/running-whale%402x-06738fa29b2f.p - [assets.client.spec.ts](../../../../packages/client/modules/tests/assets.client.spec.ts) 覆盖媒体类型、revision、产出文件名和引用;[client-asset-types.spec.ts](../../../../scripts/client-asset-types.spec.ts) 保证类型根与类型表一致。 - [client-bundle-css.spec.ts](../../../../scripts/client-bundle-css.spec.ts) 覆盖产出文件名和 URL、CSS 改写与保留形式、每种构建拒绝、Node face 守卫、一次性构建的清理,以及 watch 重建保留旧文件。 - 各门禁的 spec 拒绝每种无效的 manifest 或引用形式;[node-half.client.spec.ts](../../../../packages/client/modules/tests/node-half.client.spec.ts) 覆盖条目重启后的声明更新、导出移动、client 声明的增减、未变化的重启既不发布也不读取 bundle,以及名为 `@scope/assets` 的包的分片。 -- [desktop-onboarding.e2e.ts](../../../../apps/web/tests/desktop-onboarding.e2e.ts) 和 [reasoning-preview.e2e.ts](../../../../apps/web/tests/reasoning-preview.e2e.ts) 断言包资源 URL,并在浏览器中解码这些图片;[preview-boot.e2e.ts](../../../../apps/web/tests/preview-boot.e2e.ts) 解码 WebWorker 部署以静态方式提供的 ui-chat 遮罩图,packer 的 [page-assets.spec.ts](../../../../packages/experimental/webworker-packer/tests/page-assets.spec.ts) 覆盖哪些文件移出镜像。 +- [desktop-onboarding.e2e.ts](../../../../apps/web/tests/desktop-onboarding.e2e.ts) 和 [reasoning-preview.e2e.ts](../../../../apps/web/tests/reasoning-preview.e2e.ts) 断言包资源 URL,并在浏览器中解码这些图片。 diff --git a/apps/web/package.json b/apps/web/package.json index 11a2e75c7c..6e90bc5d2c 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -25,7 +25,7 @@ "build": "vite build", "dev": "vite", "watch": "vite build --watch --no-emptyOutDir", - "build:preview": "pnpm --filter @deepseek-ai/dsh-experimental-webworker-runtime exec tsdown && pnpm --filter @deepseek-ai/dsh-experimental-webworker-packer exec tsdown && vite build && dsh-pack-vfs-image --out dist/preview/vfs-image.tar.gz --page-root dist", + "build:preview": "pnpm --filter @deepseek-ai/dsh-experimental-webworker-runtime exec tsdown && pnpm --filter @deepseek-ai/dsh-experimental-webworker-packer exec tsdown && vite build && dsh-pack-vfs-image --out dist/preview/vfs-image.tar.gz", "serve:preview": "http-server dist -a 0.0.0.0 -p 4173 -c-1" }, "license": "MIT", diff --git a/apps/web/tests/preview-boot.e2e.ts b/apps/web/tests/preview-boot.e2e.ts index b5757973da..157d7b97c6 100644 --- a/apps/web/tests/preview-boot.e2e.ts +++ b/apps/web/tests/preview-boot.e2e.ts @@ -173,8 +173,6 @@ function requireVfsAssets(): PreviewAssets { image = packed.image writeAsset(`preview/${IMAGE_FILE_NAME}`, packed.image) for (const archive of packed.lazyArchives) writeAsset(`preview/${archive.name}`, archive.image) - // `build:preview` writes these beside the page in `dist/`; the static site serves them from the same paths. - for (const [path, bytes] of Object.entries(packed.pageFiles)) writeAsset(path, bytes) } const manifestEntry = parseTar(gunzipSync(image)).find(entry => entry.name === IMAGE_MANIFEST_PATH) if (manifestEntry === undefined) throw new Error('preview boot: the base image carries no manifest') @@ -613,19 +611,6 @@ async function toggleOptionalBundles(page: Page): Promise { await cards.first().waitFor({ timeout: 30_000 }) const listed = await cards.evaluateAll(nodes => nodes.map(node => node.getAttribute('data-plugin-package'))) expect(listed.filter(name => name !== null && OPTIONAL_BUNDLES.includes(name)).length).toBeGreaterThan(0) - // A Client package asset loads from the static deployment beside the page: the mask image ui-chat's - // injected stylesheet references decodes from its document-relative URL. - const mask = await page.evaluate(async () => { - const styles = [...document.querySelectorAll('style')].map(style => style.textContent).join('\n') - const reference = /url\(["']?(plugins\/[^"')]+\/assets\/running-whale[^"')]+)["']?\)/u.exec(styles)?.[1] - if (reference === undefined) return { reference: null, width: 0 } - const image = new Image() - image.src = new URL(reference, document.baseURI).href - await image.decode() - return { reference, width: image.naturalWidth } - }) - expect(mask.reference).toMatch(/^plugins\/@deepseek-ai\/dsh-client-ui-chat\/assets\/running-whale%402x-[0-9a-f]{12}\.png$/u) - expect(mask.width).toBeGreaterThan(0) const result = await page.evaluate(async () => { type Result = { result: { ok: true; value: T } | { ok: false; error: { message: string } } } const transport = (globalThis as typeof globalThis & { diff --git a/packages/client/modules/README.i18n.yaml b/packages/client/modules/README.i18n.yaml index a43bd0a6cd..6d9f4261fd 100644 --- a/packages/client/modules/README.i18n.yaml +++ b/packages/client/modules/README.i18n.yaml @@ -18,11 +18,11 @@ en: 25f536f156ec0bcc zh: a522355b3e0edeae /deepseek-ai-dsh-client-modules/use-this-package/declaring-a-client-plugin: - en: cc0eb2c35a7a0998 - zh: 0e1df23869410c7a + en: d4a7f865f4593724 + zh: 4313eb8fe9cd5c98 /deepseek-ai-dsh-client-modules/use-this-package/package-assets: - en: 8968947995cc33ec - zh: 9487f9e757363fdc + en: 66e3e4425e8d0301 + zh: c844a530edd5ef0b /deepseek-ai-dsh-client-modules/use-this-package/what-the-browser-loads: en: 1383d68472b3c057 zh: 94dd7d9abbdbccf3 @@ -69,8 +69,8 @@ en: ca75c51c89c2c9b0 zh: de54f3467ef3b9be /deepseek-ai-dsh-client-modules/known-limitations-and-deferred-work: - en: 97127ddc35daf6d4 - zh: 1417b06046b01067 + en: 629b604d0fdacf6a + zh: 2b2e19077de3bd3e /deepseek-ai-dsh-client-modules/known-limitations-and-deferred-work/dev-note: en: e67f633dc6fe7773 zh: 3bb0c20c93f16f98 diff --git a/packages/client/modules/README.md b/packages/client/modules/README.md index de2528578c..7f5beda6df 100644 --- a/packages/client/modules/README.md +++ b/packages/client/modules/README.md @@ -33,10 +33,9 @@ Use it when you compose or build a browser client plugin: the package turns a pa A browser plugin package declares `dsh.client` in its `package.json` with `platform: 'web'`, exports a `./client` bundle, and lists any non-baseline module requests under `dsh.client.external`. The host half turns each declaration into a served bundle under `/plugins`, ordered so dynamic providers load before their consumers. - ### Package assets -The same `/plugins` route serves the images a client package publishes through its `"./assets/*": "./lib/assets/*"` export. The build emits each referenced asset with its content revision, the first 12 hexadecimal digits of the SHA-1 digest of its bytes, inserted before the extension, and turns the import into the document-relative reference `plugins//assets/`, so one URL always names one content. Any `/plugins//assets/` path is answered by the asset route alone: for an active client row, the Host percent-decodes the path once and resolves `/assets/` with Node's `require.resolve` from the package's own manifest, so the package's exports decide which files exist. A path that does not resolve, a resolved file whose extension is not `.svg`, `.png`, `.webp`, `.jpg`, or `.jpeg`, a malformed escape, and an inactive package answer 404; the query selects nothing. A served asset streams from disk on every request without caching and carries its media type, the bundle `cache-control: public, max-age=31536000, immutable`, `etag: ""`, and `x-content-type-options: nosniff`; an SVG additionally carries `content-security-policy: script-src 'none'`, so an SVG opened directly runs no script. An `If-None-Match` equal to that tag answers 304 without opening the file, and `HEAD` answers without a body. `fetchBundle()` returns the same responses, with a streamed body that closes the file when cancelled. The WebWorker preview, whose Host runs in a Worker the page's requests never reach, serves the same files from its static deployment: the [packer](../../experimental/webworker-packer/README.md) moves them out of the VFS image to `plugins//assets/` beside the preview page. +The same `/plugins` route serves the images a client package publishes through its `"./assets/*": "./lib/assets/*"` export. The build emits each referenced asset with its content revision, the first 12 hexadecimal digits of the SHA-1 digest of its bytes, inserted before the extension, and turns the import into the document-relative reference `plugins//assets/`, so one URL always names one content. Any `/plugins//assets/` path is answered by the asset route alone: for an active client row, the Host percent-decodes the path once and resolves `/assets/` with Node's `require.resolve` from the package's own manifest, so the package's exports decide which files exist. A path that does not resolve, a resolved file whose extension is not `.svg`, `.png`, `.webp`, `.jpg`, or `.jpeg`, a malformed escape, and an inactive package answer 404; the query selects nothing. A served asset streams from disk on every request without caching and carries its media type, the bundle `cache-control: public, max-age=31536000, immutable`, `etag: ""`, and `x-content-type-options: nosniff`; an SVG additionally carries `content-security-policy: script-src 'none'`, so an SVG opened directly runs no script. An `If-None-Match` equal to that tag answers 304 without opening the file, and `HEAD` answers without a body. `fetchBundle()` returns the same responses, with a streamed body that closes the file when cancelled. ### What the browser loads @@ -145,6 +144,7 @@ These limits define what the module system does not do. They are current package - **Lazy delivery retains requested bodies** — the Host holds each bundle and lazy response plan; a script or map body remains cached after its first `GET`, and HMR additionally retains one prior startup generation. Memory grows only for response bodies that clients request while preserving one-generation race tolerance. - **An unrequested prior-generation map reads the current map file** — combo revisions track executable bundles, not debug artifacts. If HMR rebuilds a map before the retained prior URL receives its first map `GET`, that response uses the current authored map with the prior bundle offsets; requesting the map before the rebuild fixes that URL's response. - **A manifest edit alone is not observed** — the Host reads a package manifest when its Loader entry starts or restarts; editing only `package.json` takes effect at the next entry restart or Host restart. The asset route resolves through Node's package configuration cache, so a `./assets/*` export edited in place takes effect only after boot HMR expires that package or the Host restarts. +- **WebWorker preview cannot load package assets** — the preview reaches `/plugins` only through its tunnel, so an `` or CSS `url()` request never reaches the Host running in the Worker; the WebWorker runtime owns serving them. - **Desktop re-reads package assets on every display** — the Desktop forwarder rewrites every `/plugins/` cache header to `no-store`, so the immutable asset headers do not reach its browser cache. diff --git a/packages/client/modules/README.zh.md b/packages/client/modules/README.zh.md index 5104b5d815..e06ffa9c17 100644 --- a/packages/client/modules/README.zh.md +++ b/packages/client/modules/README.zh.md @@ -33,10 +33,9 @@ kind: "package-reference" 浏览器插件包在其 `package.json` 中以 `platform: 'web'` 声明 `dsh.client`,导出 `./client` bundle,并在 `dsh.client.external` 下列出任何基座之外的模块请求。宿主半侧把每份声明变成 `/plugins` 下提供的 bundle,并让动态提供方先于其消费方加载。 - ### 包资源 -同一个 `/plugins` 路由也提供客户端包通过其 `"./assets/*": "./lib/assets/*"` 导出发布的图片。构建会产出每个被引用的资源,在扩展名之前插入其内容 revision(资源字节 SHA-1 摘要的前 12 位十六进制数字),并把 import 转换为文档相对引用 `plugins//assets/`,因此一个 URL 始终对应一份内容。任何 `/plugins//assets/` 路径都只由资源路由响应:对于活动的客户端 row,Host 对路径做一次百分号解码,并从该包自身的 manifest(元数据清单)出发,用 Node 的 `require.resolve` 解析 `/assets/`,因此由包的导出决定哪些文件存在。无法解析的路径、扩展名不是 `.svg`、`.png`、`.webp`、`.jpg` 或 `.jpeg` 的已解析文件、格式错误的转义以及未激活的包都返回 404;查询串不参与选择。提供的资源每次请求都从磁盘流式读取且不缓存,并携带其媒体类型、与 bundle 相同的 `cache-control: public, max-age=31536000, immutable`、`etag: ""` 和 `x-content-type-options: nosniff`;SVG 还额外携带 `content-security-policy: script-src 'none'`,因此直接打开的 SVG 不会运行脚本。`If-None-Match` 等于该 etag 时返回 304 且不打开文件,`HEAD` 的响应不带 body。`fetchBundle()` 返回相同的响应,其流式 body 在取消时关闭文件。WebWorker 预览的 Host 运行在 Worker 中,页面的请求到达不了它,因此由静态部署提供同样的文件:[packer](../../experimental/webworker-packer/README.zh.md) 把它们移出 VFS 镜像,放到预览页旁的 `plugins//assets/`。 +同一个 `/plugins` 路由也提供客户端包通过其 `"./assets/*": "./lib/assets/*"` 导出发布的图片。构建会产出每个被引用的资源,在扩展名之前插入其内容 revision(资源字节 SHA-1 摘要的前 12 位十六进制数字),并把 import 转换为文档相对引用 `plugins//assets/`,因此一个 URL 始终对应一份内容。任何 `/plugins//assets/` 路径都只由资源路由响应:对于活动的客户端 row,Host 对路径做一次百分号解码,并从该包自身的 manifest(元数据清单)出发,用 Node 的 `require.resolve` 解析 `/assets/`,因此由包的导出决定哪些文件存在。无法解析的路径、扩展名不是 `.svg`、`.png`、`.webp`、`.jpg` 或 `.jpeg` 的已解析文件、格式错误的转义以及未激活的包都返回 404;查询串不参与选择。提供的资源每次请求都从磁盘流式读取且不缓存,并携带其媒体类型、与 bundle 相同的 `cache-control: public, max-age=31536000, immutable`、`etag: ""` 和 `x-content-type-options: nosniff`;SVG 还额外携带 `content-security-policy: script-src 'none'`,因此直接打开的 SVG 不会运行脚本。`If-None-Match` 等于该 etag 时返回 304 且不打开文件,`HEAD` 的响应不带 body。`fetchBundle()` 返回相同的响应,其流式 body 在取消时关闭文件。 ### 浏览器加载什么 @@ -146,6 +145,7 @@ bundle 路由随注入的 `webServer` 生命周期注册:服务就绪时注册 - **惰性提供会保留已请求的 body**——Host 在内存中保留每个 bundle 与惰性响应计划;脚本或 map body 在首次 `GET` 后保留缓存,HMR 还会保留上一代启动响应。内存仅随客户端实际请求的响应 body 增长,同时保留一代竞态容忍。 - **从未请求的上一代 map 会读取当前 map 文件**——combo revision 跟踪可执行 bundle,而不跟踪调试产物。若 HMR 在保留的旧 URL 首次收到 map `GET` 前重建 map,该响应会把当前 authored map 与旧 bundle offset 组合;在重建前请求 map 会固定该 URL 的响应。 - **仅编辑 manifest 不会被察觉**——Host 在包的 Loader 条目启动或重启时读取包 manifest;只编辑 `package.json` 要到下一次条目重启或 Host 重启时才生效。资源路由经 Node 的包配置缓存解析,因此原地修改的 `./assets/*` 导出要等 boot HMR 让该包的缓存失效、或 Host 重启后才生效。 +- **WebWorker 预览无法加载包资源**——预览只能经由其隧道访问 `/plugins`,因此 `` 或 CSS `url()` 请求永远到达不了运行在 Worker 中的 Host;提供这些资源由 WebWorker 运行时负责。 - **Desktop 每次显示都重新读取包资源**——Desktop 转发器把每个 `/plugins/` 缓存头改写为 `no-store`,因此不可变的资源响应头到达不了其浏览器缓存。 diff --git a/packages/experimental/webworker-packer/README.i18n.yaml b/packages/experimental/webworker-packer/README.i18n.yaml index 82952946a5..3da8cc9559 100644 --- a/packages/experimental/webworker-packer/README.i18n.yaml +++ b/packages/experimental/webworker-packer/README.i18n.yaml @@ -15,8 +15,8 @@ en: 4e53164159b5ce41 zh: 89582dc0294d0776 /deepseek-ai-dsh-experimental-webworker-packer/use-this-package: - en: c38082744e670071 - zh: 622b29ee3b205be6 + en: 4b6067a6ffd4a33f + zh: 8790e1a070a7a0f3 /deepseek-ai-dsh-experimental-webworker-packer/model-experience: en: e16b355530dadc1c zh: 8488e03b253b7b33 diff --git a/packages/experimental/webworker-packer/README.md b/packages/experimental/webworker-packer/README.md index b17d11c503..32b93f978a 100644 --- a/packages/experimental/webworker-packer/README.md +++ b/packages/experimental/webworker-packer/README.md @@ -27,15 +27,14 @@ The public npm package exposes `packVfsImage` and `packVfsOverlay` through its l The packer owns the internal `dsh.configTrees` declaration, its validation, and source directory resolution in [`src/repository.ts`](src/repository.ts). This field is not part of the public plugin manifest API. -The pack is a layered standard stack: +The pack is a three-layer standard stack: 1. **Roster** — the shipped profile template's bundles and every bundle in app-boot's `OPTIONAL_BUNDLES`, each resolved from the CLI manifest as the launcher resolves it, plus every package their patch files name (insert lists and grouped rows included), plus the rows of every config tree the CLI declares in its `package.json` `dsh.configTrees`, materialized as a Node-style dependency closure. External peer edges never bind the worker; workspace peers stay on the chain. The CLI manifest itself enters the image alone at `node_modules/@deepseek-ai/dsh/package.json`, as the worker's bundle resolution anchor; the manifest records its name and the profile. 2. **Publish view** — each workspace or vendored package contributes its built npm slice (`files` through picomatch) without source or workspace `dist/`. External packages retain published JavaScript under both `src/` and `dist/` because their `main` or `exports` may point there; only generic test, map, declaration, and archive exclusions apply. 3. **Reachability sweep** — the runtime loader's own resolution walks from every non-wildcard workspace runtime export plus the worker assembly's seeds (`IMAGE_ENTRY_SEEDS`), lowering each reached module to the wrapper contract at pack time. Declaration-only condition trees do not seed the sweep; runtime requests for those exports still fail. The transform reports statically named imports, re-exports, and dynamic imports; calls through `require`; and module-scope direct calls of the form `createRequire(import.meta.url)('pkg')` through a named import from `node:module` or `module`, including an import alias. Page assets (`lib/client.js` behind `./client` exports) ship verbatim; an unresolvable request from our own code fails the pack, third-party ones are tolerated to fail loud at require time. 4. **Lazy chunks** — every page chunk a page asset requests as a literal `require.async("./client..js")`, the only form the dynamic Client build emits, leaves the base image unless a `./client` export names it. Each becomes its own deterministic archive named `lazy/.tar.gz` beside the base image, and the manifest registers its path, size, and archive for the worker's lazy filesystem. A request for a chunk the package does not publish fails the pack. -5. **Page assets** — every file under `lib/assets/` of a package whose `exports["./assets/*"]` is `./lib/assets/*` leaves the base image for `pageFiles`, keyed `plugins//assets/`. Client bundles reference these [package assets](../../client/modules/README.md#package-assets) as document-relative URLs that the page requests from its own origin, never through the Worker, so the static deployment serves them beside the preview page. -`repository.ts` owns the repo-shaped inputs (workspace scan of `vendor/`, `packages/`, `native/system/packages/`, and `apps/`; the profile roster through app-boot's shipped templates, optional-bundle list, and bundle patch readers; the CLI manifest as the installation; the home patch, which sets the runtime's `PLATFORM_ENTRY_CONFIG` fields over each named row's config composed from the template's bundle layers); `pack.ts` owns none of them, so the same library packs a different tree by being called differently. The native scan makes the Landlock entry package an ordinary published-view dependency while its executable remains a Worker platform implementation. The CLI is `dsh-pack-vfs-image --out --page-root [--profile web]`; it writes the lazy archives beside the base image and the page assets under `--page-root`, the directory that serves the preview page, and `apps/web`'s `build:preview` runs it after the preview shell build with `--page-root dist`. +`repository.ts` owns the repo-shaped inputs (workspace scan of `vendor/`, `packages/`, `native/system/packages/`, and `apps/`; the profile roster through app-boot's shipped templates, optional-bundle list, and bundle patch readers; the CLI manifest as the installation; the home patch, which sets the runtime's `PLATFORM_ENTRY_CONFIG` fields over each named row's config composed from the template's bundle layers); `pack.ts` owns none of them, so the same library packs a different tree by being called differently. The native scan makes the Landlock entry package an ordinary published-view dependency while its executable remains a Worker platform implementation. The CLI is `dsh-pack-vfs-image --out [--profile web]`; it writes the lazy archives beside the base image, and `apps/web`'s `build:preview` runs it after the preview shell build. The repository adapter also declares the preview-only fixture trees under `webworker-runtime/tests/fixtures/`. The CLI packs each named fixture into a separate deterministic overlay archive plus a browser-readable manifest. Overlay files bypass npm publish-view and module-reachability exclusions, so dot directories and example source files remain intact; their mounts are limited to `home/` and `workspace/`. `packVfsOverlay` treats all files as opaque bytes. diff --git a/packages/experimental/webworker-packer/README.zh.md b/packages/experimental/webworker-packer/README.zh.md index 6cca6f9919..33f4627d7c 100644 --- a/packages/experimental/webworker-packer/README.zh.md +++ b/packages/experimental/webworker-packer/README.zh.md @@ -27,15 +27,14 @@ VFS 镜像打包器:把一份随附 profile 的 bundle 和安装提供的 opti 打包器在 [`src/repository.ts`](src/repository.ts) 中拥有内部 `dsh.configTrees` 声明、校验和源目录解析。该字段不属于公共插件 manifest API。 -打包是分层标准栈: +打包是三层标准栈: 1. **Roster**——随附 profile 模板的 bundle 和 app-boot `OPTIONAL_BUNDLES` 中的每个 bundle(各自按启动器的方式从 CLI manifest 解析),加上它们 patch 文件点名的每个包(含 insert 列表与分组行),再加上 CLI(命令行界面)在 `package.json` `dsh.configTrees` 里声明的每棵配置树的行,按 Node 式依赖闭包物化。外部 peer 边绝不会绑定到 worker,workspace peer 保留在链上。CLI manifest 本身单独进入镜像,位于 `node_modules/@deepseek-ai/dsh/package.json`,作为 worker 解析 bundle 的锚点;manifest 记录它的名称和 profile。 2. **发布视图**——每个 workspace 或 vendored 包贡献其构建后的 npm 切片(`files` 走 picomatch),不带源码和 workspace `dist/`。外部包的 `main` 或 `exports` 可能指向 `src/` 或 `dist/`,因此两处发布 JavaScript 都会保留,只应用通用的测试、map、声明与归档排除规则。 3. **可达性 sweep**——用运行时加载器自己的解析, 从全部不含通配符的 workspace 运行时导出加 worker 装配种子 (`IMAGE_ENTRY_SEEDS`) 出发, 打包时把每个可达模块转换为符合包装层约定的形式. 仅含类型声明的条件树不作为扫描入口; 运行时代码请求这些导出仍会失败. 该转换会报告名称可静态确定的 import、re-export 与动态 import、经 `require` 发起的调用, 以及通过 `node:module` 或 `module` 具名导入 (含导入别名) 在模块作用域直接发起的 `createRequire(import.meta.url)('pkg')` 调用. 页面资产 (`./client` 导出背后的 `lib/client.js`) 原样直发; 自家代码的不可解析请求会让打包失败, 第三方不可解析请求则允许延后到 require 时明确失败. 4. **懒加载 chunk**——页面资产以字面量 `require.async("./client..js")`(动态 Client 构建产出的唯一形式)请求的每个页面 chunk,除非被 `./client` 导出点名,否则移出基础镜像。每个 chunk 成为基础镜像旁的一个独立确定性归档,命名为 `lazy/<归档的 sha256>.tar.gz`;manifest 为 worker 的懒加载文件系统登记其路径、大小和归档。请求包未发布的 chunk 会让打包失败。 -5. **页面资源**——`exports["./assets/*"]` 为 `./lib/assets/*` 的包,其 `lib/assets/` 下的每个文件都移出基础镜像,放入 `pageFiles`,键为 `plugins//assets/`。Client bundle 以文档相对 URL 引用这些[包资源](../../client/modules/README.zh.md#package-assets),页面从自己的源站请求它们,从不经过 Worker,因此由静态部署在预览页旁提供。 -`repository.ts` 拥有仓库形态输入(`vendor/`、`packages/`、`native/system/packages/` 与 `apps/` 的 workspace 扫描;经 app-boot 的随附模板、optional bundle 列表和 bundle patch 读取器得出 profile roster;以 CLI manifest 作为安装清单;home patch 在模板各 bundle 层合成出的行配置之上设置运行时 `PLATFORM_ENTRY_CONFIG` 字段);`pack.ts` 一概不拥有,同一库换参即可打另一棵树。Native 扫描使 Landlock 入口包成为普通发布视图依赖,其可执行文件仍由 Worker 平台实现。CLI 为 `dsh-pack-vfs-image --out --page-root [--profile web]`;它把懒加载归档写在基础镜像旁,把页面资源写到 `--page-root`(提供预览页的目录)下;`apps/web` 的 `build:preview` 在预览壳构建后以 `--page-root dist` 运行它。 +`repository.ts` 拥有仓库形态输入(`vendor/`、`packages/`、`native/system/packages/` 与 `apps/` 的 workspace 扫描;经 app-boot 的随附模板、optional bundle 列表和 bundle patch 读取器得出 profile roster;以 CLI manifest 作为安装清单;home patch 在模板各 bundle 层合成出的行配置之上设置运行时 `PLATFORM_ENTRY_CONFIG` 字段);`pack.ts` 一概不拥有,同一库换参即可打另一棵树。Native 扫描使 Landlock 入口包成为普通发布视图依赖,其可执行文件仍由 Worker 平台实现。CLI 为 `dsh-pack-vfs-image --out [--profile web]`;它把懒加载归档写在基础镜像旁,`apps/web` 的 `build:preview` 在预览壳构建后运行它。 仓库适配器还声明 `webworker-runtime/tests/fixtures/` 下仅用于 preview 的 fixture(测试前置数据) tree。CLI 会把每套具名 fixture 打成一份独立的确定性 overlay 归档,并写出浏览器可读的 manifest(元数据清单)。Overlay 文件绕过 npm 发布视图和模块可达性排除规则,因此点目录与示例源码会完整保留;其挂载位置仅限 `home/` 与 `workspace/`。`packVfsOverlay` 将所有文件视为不透明字节。 diff --git a/packages/experimental/webworker-packer/src/bin.ts b/packages/experimental/webworker-packer/src/bin.ts index 9a14c96b52..18bf398e59 100644 --- a/packages/experimental/webworker-packer/src/bin.ts +++ b/packages/experimental/webworker-packer/src/bin.ts @@ -2,11 +2,10 @@ /** * Pack a Preview deployment from this repository: materialize and lower the * base image for one shipped profile, write its lazy chunk archives beside it, - * write the package assets under the page root that serves the preview page, * then write each named fixture overlay and their manifest. * - * Usage: dsh-pack-vfs-image --out --page-root [--profile web] [--root /dsh] - * node --import tsx/esm src/bin.ts --out ../../apps/web/dist/preview/vfs-image.tar.gz --page-root ../../apps/web/dist + * Usage: dsh-pack-vfs-image --out [--profile web] [--root /dsh] + * node --import tsx/esm src/bin.ts --out ../../apps/web/dist/preview/vfs-image.tar.gz * @module @deepseek-ai/dsh-experimental-webworker-packer/src/bin */ import { mkdirSync, writeFileSync } from 'node:fs' @@ -45,8 +44,6 @@ const repoRoot = fileURLToPath(new URL('../../../../', import.meta.url)) const profile = flag('profile', 'web') const out = flag('out') const outputFile = isAbsolute(out) ? out : resolve(process.cwd(), out) -const pageRootFlag = flag('page-root') -const pageRoot = isAbsolute(pageRootFlag) ? pageRootFlag : resolve(process.cwd(), pageRootFlag) const result = packRepositoryImage(repoRoot, profile, flag('root', '/dsh')) @@ -62,12 +59,6 @@ for (const archive of result.lazyArchives) { mkdirSync(dirname(path), { recursive: true }) writeFileSync(path, archive.image) } -// Page asset paths are relative to the preview page, whose document resolves the bundles' asset URLs. -for (const [pagePath, bytes] of Object.entries(result.pageFiles)) { - const path = join(pageRoot, pagePath) - mkdirSync(dirname(path), { recursive: true }) - writeFileSync(path, bytes) -} const fixtureDefinitions = previewFixtures(repoRoot) const fixtureDirectory = join(dirname(outputFile), 'fixtures') diff --git a/packages/experimental/webworker-packer/src/pack.ts b/packages/experimental/webworker-packer/src/pack.ts index a464d67699..fd394d2d51 100644 --- a/packages/experimental/webworker-packer/src/pack.ts +++ b/packages/experimental/webworker-packer/src/pack.ts @@ -137,12 +137,6 @@ export interface PackResult { readonly executables: readonly string[] /** Page bundles left out of the transform; like every JavaScript entry they carry the trailing debugger name. */ readonly pageBundles: readonly string[] - /** - * Package assets moved out of the base image, keyed by the page-relative path - * `plugins//assets/` that Client bundles reference; the static - * deployment serves them beside the preview page. - */ - readonly pageFiles: ImageFiles /** JavaScript entries the image carries. */ readonly javascriptEntries: number /** JavaScript candidates no root reaches, dropped from the image. */ @@ -639,42 +633,6 @@ function lazyChunksOf(files: ImageFiles, eager: ReadonlySet): string[] { return [...lazy].sort() } -/** Image path of a file a package publishes through its `./assets/*` export. */ -const PACKAGE_ASSET_FILE = /^node_modules\/((?:@[^/]+\/)?[^/]+)\/lib\/assets\/(.+)$/ - -/** - * Move every package asset out of the image. Client bundles reference an asset - * as the document-relative URL `plugins//assets/`, which the - * Worker never answers: the page requests it from the static deployment, so - * the file belongs to the page tree, not to the Worker filesystem. - * @param files - Image entries after the sweep; asset entries are deleted. - * @returns Page-relative paths to bytes. - */ -function takePageAssets(files: ImageFiles): ImageFiles { - const decoder = new TextDecoder() - const publishes = new Map() - const exportsAssets = (name: string): boolean => { - let known = publishes.get(name) - if (known === undefined) { - const bytes = files[`node_modules/${name}/package.json`] - const manifest = bytes === undefined ? {} : JSON.parse(decoder.decode(bytes)) as { exports?: Record } - // The export target client-modules and the client build preset require. - known = manifest.exports?.['./assets/*'] === './lib/assets/*' - publishes.set(name, known) - } - return known - } - const pageFiles: ImageFiles = {} - for (const [path, bytes] of Object.entries(files)) { - const match = PACKAGE_ASSET_FILE.exec(path) - if (match === null || path.endsWith('/') || !exportsAssets(match[1] as string)) continue - pageFiles[`plugins/${match[1] as string}/assets/${match[2] as string}`] = bytes - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- the image is a plain path map - delete files[path] - } - return pageFiles -} - /** Gzip header byte that records the packing platform; RFC 1952 §2.3.1 spells 255 "unknown". */ const GZIP_OS_UNKNOWN = 255 @@ -708,7 +666,6 @@ function compressImage(archive: Uint8Array): Uint8Array { * rather than downgrading the image, because a mostly-transformed image boots into * errors far from their cause. Page chunks requested through `require.async` leave * the base image for deterministic archives named by their content digest, which the manifest registers. - * Package assets leave it for the page tree the static deployment serves. * @param options - Roster, installation, package index, and paths. * @returns The compressed image, its lazy archives, and what went into them. * @throws When a config tree or workspace directory named in the options is missing, @@ -748,7 +705,6 @@ export function packVfsImage(options: PackOptions): PackResult { const rootPackages = [...packages.keys()].filter(name => options.workspaces.has(name)) const { swept, transform, javascriptEntries, droppedJavascriptEntries, unresolvedExternalRequests } = sweepImage(files, options, rootPackages, root) - const pageFiles = takePageAssets(swept) const lazyArchives: PackedLazyArchive[] = [] const lazy: ImageLazyArchive[] = [] @@ -788,7 +744,6 @@ export function packVfsImage(options: PackOptions): PackResult { missing, executables, pageBundles: Object.keys(swept).filter(name => pageAsset(name)), - pageFiles, javascriptEntries: manifest.javascriptEntries, droppedJavascriptEntries, unresolvedExternalRequests, diff --git a/packages/experimental/webworker-packer/src/repository.ts b/packages/experimental/webworker-packer/src/repository.ts index f2b3a934a4..82d85dc491 100644 --- a/packages/experimental/webworker-packer/src/repository.ts +++ b/packages/experimental/webworker-packer/src/repository.ts @@ -279,7 +279,6 @@ export function describePack(result: PackResult, repoRoot: string, outputFile: s ` compressed ${megabytes(result.image.byteLength)}`, ` config + presets ${megabytes(sizeOf('config/'))}`, ` lazy archives ${String(result.lazyArchives.length)} (${megabytes(result.lazyArchives.reduce((sum, archive) => sum + archive.image.byteLength, 0))} compressed)`, - ` page assets ${String(Object.keys(result.pageFiles).length)} (${megabytes(Object.values(result.pageFiles).reduce((sum, bytes) => sum + bytes.byteLength, 0))})`, ...result.lazyArchives.map(archive => ` ${megabytes(archive.image.byteLength).padStart(9)} ${archive.name} ${archive.files.join(', ')}`), ` javascript entries ${String(result.javascriptEntries)} (dropped ${String(result.executables.length)} executable scripts, ${String(result.pageBundles.length)} page bundles verbatim)`, diff --git a/packages/experimental/webworker-packer/tests/page-assets.spec.ts b/packages/experimental/webworker-packer/tests/page-assets.spec.ts deleted file mode 100644 index 4bc9b30e45..0000000000 --- a/packages/experimental/webworker-packer/tests/page-assets.spec.ts +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Package assets published through `./assets/*` leave the base image for the - * page tree: Client bundles reference them as document-relative - * `plugins//assets/` URLs, which the static deployment answers - * beside the preview page while the Worker never sees them. - */ -import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' -import { tmpdir } from 'node:os' -import { dirname, join } from 'node:path' -import { gunzipSync } from 'node:zlib' -import { expect, it, type TestContext } from 'vitest' -import { parseTar } from '@deepseek-ai/dsh-experimental-webworker-runtime/src/storage/tar.ts' -import { packVfsImage, type PackOptions } from '../src/pack.ts' - -const PUBLISHER = '@fixture/asset-publisher' -const UNEXPORTED = 'asset-unexported' - -/** Write one workspace package and return its directory. */ -function writePackage(test: TestContext, name: string, exports: Record, files: Record): string { - const root = mkdtempSync(join(tmpdir(), 'dsh-image-assets-')) - test.onTestFinished(() => { rmSync(root, { recursive: true, force: true }) }) - writeFileSync(join(root, 'package.json'), JSON.stringify({ name, type: 'module', files: ['lib'], exports })) - for (const [path, body] of Object.entries(files)) { - mkdirSync(dirname(join(root, path)), { recursive: true }) - writeFileSync(join(root, path), body) - } - return root -} - -function fixture(test: TestContext): PackOptions { - const publisher = writePackage(test, PUBLISHER, { - '.': './lib/index.js', - './client': './lib/client.js', - './assets/*': './lib/assets/*', - }, { - 'lib/index.js': 'export const value = 1', - 'lib/client.js': 'module.exports = "plugins/@fixture/asset-publisher/assets/icons/mark-0123456789ab.svg"', - 'lib/assets/icons/mark-0123456789ab.svg': '', - 'lib/assets/whale@2x-0123456789ab.png': 'png', - }) - const unexported = writePackage(test, UNEXPORTED, { '.': './lib/index.js' }, { - 'lib/index.js': 'export const value = 2', - 'lib/assets/kept.svg': '', - }) - return { - profile: 'asset-check', - roster: [PUBLISHER, UNEXPORTED], - workspaces: new Map([[PUBLISHER, publisher], [UNEXPORTED, unexported]]), - resolveFrom: publisher, - entries: [], - } -} - -it('moves exported package assets to their page paths and keeps them out of the base image', (test) => { - const result = packVfsImage(fixture(test)) - - expect(Object.fromEntries(Object.entries(result.pageFiles).map(([path, bytes]) => [path, new TextDecoder().decode(bytes)]))) - .toEqual({ - 'plugins/@fixture/asset-publisher/assets/icons/mark-0123456789ab.svg': '', - 'plugins/@fixture/asset-publisher/assets/whale@2x-0123456789ab.png': 'png', - }) - const imaged = parseTar(gunzipSync(result.image)).map(entry => entry.name) - expect(imaged.filter(name => name.includes('/lib/assets/'))).toEqual([`node_modules/${UNEXPORTED}/lib/assets/kept.svg`]) - expect(imaged).toContain(`node_modules/${PUBLISHER}/lib/client.js`) -}) diff --git a/scripts/client-build-environment.ts b/scripts/client-build-environment.ts index 6eed371b08..74021edf22 100644 --- a/scripts/client-build-environment.ts +++ b/scripts/client-build-environment.ts @@ -38,7 +38,6 @@ const CLIENT_ARTIFACT_PATTERNS = [ 'packages/*/*/lib/client.js.map', 'packages/*/*/lib/client.*.js', 'packages/*/*/lib/client.*.js.map', - 'packages/*/*/lib/assets/**/*', ] as const /** Public values embedded in one set of client artifacts. */