Просмотр исходного кода

fix(packages): ship web and theme assets

imccyu 2 месяцев назад
Родитель
Сommit
7557de1131

+ 3 - 0
apps/web/package.json

@@ -8,6 +8,9 @@
     "./dist/*": "./dist/*",
     "./package.json": "./package.json"
   },
+  "files": [
+    "dist"
+  ],
   "scripts": {
     "build": "vite build",
     "dev": "vite",

+ 2 - 1
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"

+ 9 - 1
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]

+ 11 - 3
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<string, string>; 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 `<package>/styles/<file>` 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 `<package>/styles/<file>` 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) {

+ 16 - 1
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<Record<string, readonly string[]>> = {
+  '@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<Record<string, readonly string[]>> = {
+  '@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