tsdown.config.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import { createRequire } from 'node:module'
  2. import { dirname, join } from 'node:path'
  3. import { fileURLToPath } from 'node:url'
  4. import { defineConfig } from 'tsdown'
  5. import { MODULE_PROXIES, MODULE_PROXY_PREFIXES } from './src/module-proxies.ts'
  6. const here = (relative: string): string => fileURLToPath(new URL(relative, import.meta.url))
  7. const resolveFrom = createRequire(import.meta.url)
  8. /**
  9. * `@yarnpkg/parsers`' shell face, reached at its own file rather than through the
  10. * package root. The root barrel also re-exports the Syml parser, which pulls in
  11. * that grammar and js-yaml — around 175 kB of this bundle for a format the worker
  12. * never parses, plus their module bodies at worker start. The shell entry holds
  13. * `parseShell` and the stringifiers, requiring only its own grammar.
  14. *
  15. * This pins a path inside the package, which its `exports` field does not
  16. * publish: upgrading `@yarnpkg/parsers` must re-check that `lib/shell.js` is still
  17. * where the shell parser lives and still exports `parseShell`. The path is
  18. * derived from the package manifest, the one subpath the package does publish, so
  19. * a move fails the build here rather than silently reinstating the barrel.
  20. */
  21. const SHELL_PARSER_ENTRY = join(dirname(resolveFrom.resolve('@yarnpkg/parsers/package.json')), 'lib/shell.js')
  22. /** Redirects the parsers root specifier onto {@link SHELL_PARSER_ENTRY}. */
  23. const shellParserOnlyPlugin = {
  24. name: 'dsh-shell-parser-only',
  25. resolveId(source: string): string | null {
  26. return source === '@yarnpkg/parsers' ? SHELL_PARSER_ENTRY : null
  27. },
  28. }
  29. /**
  30. * Resolve the module proxy table at bundle time: every Node builtin or
  31. * replaced external the worker graph imports lands on its `./node/` proxy,
  32. * so `lib/worker.js` is one self-contained ES module a deployment serves and
  33. * loads with `new Worker(url, { type: 'module' })`.
  34. */
  35. const moduleProxyPlugin = {
  36. name: 'dsh-module-proxies',
  37. resolveId(source: string): string | null {
  38. const exact = MODULE_PROXIES[source]
  39. if (exact !== undefined) return here(`./src/${exact.replace('./', '')}`)
  40. for (const [prefix, replacement] of Object.entries(MODULE_PROXY_PREFIXES)) {
  41. if (source.startsWith(prefix)) return here(`./src/${replacement.replace('./', '')}`)
  42. }
  43. return null
  44. },
  45. }
  46. /**
  47. * Three artifacts from one pipeline: the runtime library the worker bundle is
  48. * built from (neutral), the worker bundle itself (browser, single file), and
  49. * the page half a deployment's shell imports (browser).
  50. */
  51. export default defineConfig([{
  52. entry: ['src/index.ts'],
  53. outDir: 'lib',
  54. format: ['esm'],
  55. platform: 'neutral',
  56. target: 'es2024',
  57. fixedExtension: false,
  58. dts: false,
  59. clean: false,
  60. }, {
  61. // The invariant companion ships as its own bundle, like every package,
  62. // from the tsc-emitted artifact plane the root build also consumes.
  63. entry: ['lib/types/invariant.js'],
  64. outDir: 'lib',
  65. format: ['esm'],
  66. platform: 'neutral',
  67. target: 'es2024',
  68. fixedExtension: false,
  69. dts: false,
  70. clean: false,
  71. }, {
  72. // The worker artifact: the host tree's Node-compatibility layer plus the
  73. // assembly, bundled whole — a worker served from a static URL can fetch no
  74. // sibling chunk.
  75. entry: ['src/worker.ts'],
  76. outDir: 'lib',
  77. format: ['esm'],
  78. platform: 'browser',
  79. target: 'es2022',
  80. sourcemap: true,
  81. fixedExtension: false,
  82. dts: false,
  83. clean: false,
  84. noExternal: [/.*/],
  85. plugins: [moduleProxyPlugin, shellParserOnlyPlugin],
  86. outputOptions: { inlineDynamicImports: true },
  87. }, {
  88. // Page half: an ordinary browser ES module the deployment's page imports. It
  89. // is not a `dsh.client` graph row — it installs the module loader the graph is
  90. // loaded through, so it cannot be loaded by it. Workspace peers stay external
  91. // so the page keeps one instance of each.
  92. entry: ['src/client/index.ts'],
  93. outDir: 'lib',
  94. format: ['esm'],
  95. platform: 'browser',
  96. target: 'es2022',
  97. fixedExtension: false,
  98. dts: false,
  99. clean: false,
  100. outputOptions: { entryFileNames: 'client.js' },
  101. }])