From 7557de11314766d4b0fa0df10f96a196d3c80b5a Mon Sep 17 00:00:00 2001 From: imccyu Date: Tue, 4 Aug 2026 23:37:57 +0800 Subject: [PATCH] fix(packages): ship web and theme assets --- apps/web/package.json | 3 +++ packages/client/ui-theme/package.json | 3 ++- packages/client/ui-theme/tsdown.config.ts | 10 +++++++++- packages/client/web/tests/base-styles.spec.ts | 14 +++++++++++--- scripts/check-workspace-constraints.ts | 17 ++++++++++++++++- 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index 3c8f90b6a0..39862701b3 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -8,6 +8,9 @@ "./dist/*": "./dist/*", "./package.json": "./package.json" }, + "files": [ + "dist" + ], "scripts": { "build": "vite build", "dev": "vite", diff --git a/packages/client/ui-theme/package.json b/packages/client/ui-theme/package.json index 7046f3391b..6f89c84735 100644 --- a/packages/client/ui-theme/package.json +++ b/packages/client/ui-theme/package.json @@ -19,7 +19,7 @@ "types": "./lib/types/client/index.d.ts", "default": "./lib/client.js" }, - "./styles/*": "./src/styles/*", + "./styles/*": "./lib/styles/*", "./src/*": "./src/*", "./package.json": "./package.json" }, @@ -56,6 +56,7 @@ "lib/index.js", "lib/invariant.js", "lib/client.js", + "lib/styles", "lib/types/**/*.d.ts", "lib/types/**/*.d.ts.map", "src" diff --git a/packages/client/ui-theme/tsdown.config.ts b/packages/client/ui-theme/tsdown.config.ts index 1bc83af0e9..08616753ce 100644 --- a/packages/client/ui-theme/tsdown.config.ts +++ b/packages/client/ui-theme/tsdown.config.ts @@ -1,3 +1,11 @@ import { clientBundle } from '../tsdown.client.ts' -export default clientBundle('@deepseek-ai/dsh-client-ui-theme', ['lib/types/index.js', 'lib/types/invariant.js']) +const [lib, client] = clientBundle( + '@deepseek-ai/dsh-client-ui-theme', + ['lib/types/index.js', 'lib/types/invariant.js'], +) + +export default [{ + ...lib, + copy: [{ from: 'src/styles/*', to: 'lib/styles' }], +}, client] diff --git a/packages/client/web/tests/base-styles.spec.ts b/packages/client/web/tests/base-styles.spec.ts index d87921cede..ecea9e9f2c 100644 --- a/packages/client/web/tests/base-styles.spec.ts +++ b/packages/client/web/tests/base-styles.spec.ts @@ -10,6 +10,9 @@ import { describe, expect, it } from 'vitest' const THEME_PACKAGE = '@deepseek-ai/dsh-client-ui-theme' const baseCss = readFileSync(fileURLToPath(new URL('../src/base.css', import.meta.url)), 'utf8') +const themeManifest = JSON.parse( + readFileSync(fileURLToPath(new URL('../../ui-theme/package.json', import.meta.url)), 'utf8'), +) as { exports: Record; files: string[] } /** * Import specifiers of the sheet, in source order. Quote style and surrounding @@ -24,9 +27,9 @@ function importOrder(css: string): string[] { } /** - * Resolve a `/styles/` specifier to its path in the workspace. - * The theme package maps `./styles/*` to `./src/styles/*`, so the sheets stay - * on the source plane rather than needing a build. + * Resolve a `/styles/` specifier to its source path for a + * clean-tree test. The package build copies these sheets to their public + * `lib/styles` export. * @param specifier - import specifier from base.css. * @returns absolute path of the file the specifier names. */ @@ -38,6 +41,11 @@ function resolveThemeSheet(specifier: string): string { const imports = importOrder(baseCss) describe('web shell base.css', () => { + it('publishes theme sheets from the built artifact plane', () => { + expect(themeManifest.exports['./styles/*']).toBe('./lib/styles/*') + expect(themeManifest.files).toContain('lib/styles') + }) + it('imports every sheet from the theme package and each one exists', () => { expect(imports.length).toBeGreaterThan(0) for (const specifier of imports) { diff --git a/scripts/check-workspace-constraints.ts b/scripts/check-workspace-constraints.ts index 91a70576bb..6fc99c6304 100644 --- a/scripts/check-workspace-constraints.ts +++ b/scripts/check-workspace-constraints.ts @@ -14,6 +14,7 @@ const root = resolve(import.meta.dirname, '..') const workspaceGlobs = [ { dir: 'vendor', depth: 1 }, { dir: 'packages', depth: 2 }, + { dir: 'apps', depth: 1 }, ] as const const vendoredPackages = new Set([ 'cordis', @@ -28,6 +29,10 @@ const vendoredPackages = new Set([ ]) const localArtifactDirs = new Set(['node_modules']) +const appPackageFiles: Readonly> = { + '@deepseek-ai/dsh': ['lib/*.js', 'config', 'src'], + '@deepseek-ai/dsh-frontend': ['dist'], +} /** The subset of package.json fields this constraint check cares about. */ interface PackageManifest { @@ -96,6 +101,7 @@ function workspaceManifests(): WorkspaceManifest[] { } const packageFileExtras: Readonly> = { + '@deepseek-ai/dsh-client-ui-theme': ['lib/styles'], '@deepseek-ai/dsh-helper': ['lib/assets'], '@deepseek-ai/dsh-pty-local': ['scripts/ensure-spawn-helper.mjs'], '@deepseek-ai/dsh-scripts': [ @@ -165,7 +171,16 @@ function checkWorkspace({ dir, manifest }: WorkspaceManifest): string[] { return errors } - if (manifest.name?.startsWith('@deepseek-ai/dsh-') && manifest.name !== '@deepseek-ai/dsh-root') { + if (dir.startsWith('apps/') && manifest.name?.startsWith('@deepseek-ai/')) { + const expectedFiles = appPackageFiles[manifest.name] + if (expectedFiles === undefined) { + errors.push(`${label}: app package has no publication files policy`) + } else if (!sameStringList(manifest.files, expectedFiles)) { + errors.push(`${label}: package.json files must be ${JSON.stringify(expectedFiles)}`) + } + } + + if (dir.startsWith('packages/') && manifest.name?.startsWith('@deepseek-ai/dsh-')) { const peer = manifest.peerDependencies?.cordis const dev = manifest.devDependencies?.cordis