tsdown.config.ts 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. import { readFileSync, readdirSync } from 'node:fs'
  2. import { createRequire } from 'node:module'
  3. import { dirname, join } from 'node:path'
  4. import type { UserConfig } from 'tsdown'
  5. import { clientBundle } from '../tsdown.client.ts'
  6. const bundle = clientBundle('@deepseek-ai/dsh-client-ui-sidebar-documentpreview', ['lib/types/index.js'])
  7. const require = createRequire(import.meta.url)
  8. const workerSpecifier = 'pdfjs-dist/build/pdf.worker.min.mjs?raw'
  9. const workerModule = '\0dsh-pdf-worker.mjs'
  10. /** License files for PDF.js and the data embedded beside its runtime. */
  11. function pdfLicenseFiles(root: string): string[] {
  12. return ['LICENSE', ...['cmaps', 'standard_fonts', 'wasm'].flatMap(directory =>
  13. readdirSync(join(root, directory)).filter(name => name.startsWith('LICENSE')).sort()
  14. .map(name => `${directory}/${name}`),
  15. )]
  16. }
  17. /** Keep every bundled PDF.js license visible in the published client artifact. */
  18. function pdfLicenseBanner(): string {
  19. const root = dirname(require.resolve('pdfjs-dist/package.json'))
  20. const notice = pdfLicenseFiles(root).map(name =>
  21. `${name}\n\n${readFileSync(join(root, name), 'utf8').trimEnd()}`,
  22. ).join('\n\n')
  23. return ['//! Bundled PDF.js license notices', ...notice.split('\n').map(line => `// ${line}`)].join('\n')
  24. }
  25. /** Keep font mappings and image decoders in the same artifact as their PDF.js runtime. */
  26. function pdfAssets(): string {
  27. const root = dirname(require.resolve('pdfjs-dist/package.json'))
  28. return JSON.stringify(Object.fromEntries([
  29. ['cMapUrl', 'cmaps'], ['standardFontDataUrl', 'standard_fonts'], ['wasmUrl', 'wasm'],
  30. ].map(([kind, directory]) => [kind, Object.fromEntries(
  31. readdirSync(join(root, directory!)).filter(name => !name.startsWith('LICENSE')).sort()
  32. .map(name => [name, readFileSync(join(root, directory!, name)).toString('base64')]),
  33. )])))
  34. }
  35. /** The dynamic client factory has no module URL from which to resolve a Worker file. */
  36. const pdfWorker: NonNullable<UserConfig['plugins']> = [{
  37. name: 'dsh-pdf-worker-source',
  38. resolveId(source) {
  39. return source === workerSpecifier ? workerModule : null
  40. },
  41. load(id) {
  42. if (id !== workerModule) return null
  43. const path = require.resolve('pdfjs-dist/build/pdf.worker.min.mjs')
  44. this.addWatchFile(path)
  45. return `export default ${JSON.stringify(readFileSync(path, 'utf8'))};`
  46. },
  47. }]
  48. export default (options: Parameters<typeof bundle>[0]): UserConfig[] => bundle(options).map(config =>
  49. config.name?.endsWith('/client') === true ? {
  50. ...config,
  51. banner: pdfLicenseBanner(),
  52. plugins: [config.plugins, pdfWorker],
  53. define: { ...config.define, __DSH_PDFJS_ASSETS__: pdfAssets() },
  54. } : config,
  55. )