build-iife.mjs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import { existsSync } from 'node:fs'
  2. import { cp, mkdir, rm, writeFile } from 'node:fs/promises'
  3. import { dirname, join, resolve } from 'node:path'
  4. import { fileURLToPath } from 'node:url'
  5. import { build } from 'vite'
  6. const packageDir = resolve(dirname(fileURLToPath(import.meta.url)), '..')
  7. const entry = join(packageDir, 'src', 'global.ts')
  8. const excalidrawStub = resolve(packageDir, '..', 'web', 'scripts', 'excalidraw-iife-stub.ts')
  9. const outDir = join(packageDir, 'dist')
  10. const fileName = 'flyfish-file-viewer-web-full.iife.js'
  11. const rendererOutDir = join(outDir, 'renderers')
  12. const generatedDir = join(packageDir, '.generated-iife-renderers')
  13. const rendererBuilds = [
  14. { key: 'word', packageName: '@file-viewer/renderer-word', exportName: 'wordRenderer', globalName: 'FlyfishFileViewerWebFullRendererWord' },
  15. { key: 'pdf', packageName: '@file-viewer/renderer-pdf', exportName: 'pdfRenderer', globalName: 'FlyfishFileViewerWebFullRendererPdf' },
  16. { key: 'ofd', packageName: '@file-viewer/renderer-ofd', exportName: 'ofdRenderer', globalName: 'FlyfishFileViewerWebFullRendererOfd' },
  17. { key: 'presentation', packageName: '@file-viewer/renderer-presentation', exportName: 'presentationRenderer', globalName: 'FlyfishFileViewerWebFullRendererPresentation' },
  18. { key: 'spreadsheet', packageName: '@file-viewer/renderer-spreadsheet', exportName: 'spreadsheetRenderer', globalName: 'FlyfishFileViewerWebFullRendererSpreadsheet' },
  19. { key: 'cad', packageName: '@file-viewer/renderer-cad', exportName: 'cadRenderer', globalName: 'FlyfishFileViewerWebFullRendererCad' },
  20. { key: 'typst', packageName: '@file-viewer/renderer-typst', exportName: 'typstRenderer', globalName: 'FlyfishFileViewerWebFullRendererTypst' },
  21. { key: 'drawing', packageName: '@file-viewer/renderer-drawing', exportName: 'drawingRenderer', globalName: 'FlyfishFileViewerWebFullRendererDrawing' },
  22. { key: 'model', packageName: '@file-viewer/renderer-3d', exportName: 'modelRenderer', globalName: 'FlyfishFileViewerWebFullRendererModel' },
  23. { key: 'archive', packageName: '@file-viewer/renderer-archive', exportName: 'archiveRenderer', globalName: 'FlyfishFileViewerWebFullRendererArchive' },
  24. { key: 'email', packageName: '@file-viewer/renderer-email', exportName: 'emailRenderer', globalName: 'FlyfishFileViewerWebFullRendererEmail' },
  25. { key: 'ebook', packageName: '@file-viewer/renderer-epub', exportName: 'ebookRenderer', globalName: 'FlyfishFileViewerWebFullRendererEbook' },
  26. { key: 'text', packageName: '@file-viewer/renderer-text', exportName: 'textRenderer', globalName: 'FlyfishFileViewerWebFullRendererText' },
  27. { key: 'image', packageName: '@file-viewer/renderer-image', exportName: 'imageRenderer', globalName: 'FlyfishFileViewerWebFullRendererImage' },
  28. { key: 'media', packageName: '@file-viewer/renderer-media', exportName: 'mediaRenderer', globalName: 'FlyfishFileViewerWebFullRendererMedia' },
  29. { key: 'mindmap', packageName: '@file-viewer/renderer-mindmap', exportName: 'mindmapRenderer', globalName: 'FlyfishFileViewerWebFullRendererMindmap' },
  30. { key: 'geo', packageName: '@file-viewer/renderer-geo', exportName: 'geoRenderer', globalName: 'FlyfishFileViewerWebFullRendererGeo' },
  31. { key: 'data', packageName: '@file-viewer/renderer-data', exportName: 'dataRenderer', globalName: 'FlyfishFileViewerWebFullRendererData' },
  32. { key: 'eda', packageName: '@file-viewer/renderer-eda', exportName: 'edaRenderer', globalName: 'FlyfishFileViewerWebFullRendererEda' }
  33. ]
  34. if (!existsSync(entry)) {
  35. throw new Error(`Missing web full global entry: ${entry}`)
  36. }
  37. await mkdir(outDir, { recursive: true })
  38. await rm(rendererOutDir, { recursive: true, force: true })
  39. await mkdir(rendererOutDir, { recursive: true })
  40. await build({
  41. configFile: false,
  42. publicDir: false,
  43. logLevel: 'warn',
  44. define: {
  45. 'process.env.NODE_ENV': JSON.stringify('production'),
  46. 'process.env': JSON.stringify({ NODE_ENV: 'production' }),
  47. 'import.meta.url': 'document.currentScript?.src || location.href'
  48. },
  49. resolve: {
  50. alias: {
  51. // Keep the CDN full bundle usable without React peer dependencies.
  52. '@excalidraw/excalidraw': excalidrawStub
  53. },
  54. dedupe: ['@file-viewer/core']
  55. },
  56. build: {
  57. emptyOutDir: false,
  58. minify: 'esbuild',
  59. sourcemap: false,
  60. target: 'es2020',
  61. lib: {
  62. entry,
  63. name: 'FlyfishFileViewerWebFull',
  64. formats: ['iife'],
  65. fileName: () => fileName
  66. },
  67. rollupOptions: {
  68. output: {
  69. exports: 'named',
  70. extend: true
  71. }
  72. }
  73. }
  74. })
  75. await rm(generatedDir, { recursive: true, force: true })
  76. await mkdir(generatedDir, { recursive: true })
  77. for (const renderer of rendererBuilds) {
  78. const rendererEntry = join(generatedDir, `${renderer.key}.ts`)
  79. await writeFile(rendererEntry, `
  80. import { ${renderer.exportName} as renderer } from '${renderer.packageName}'
  81. const host = globalThis
  82. const bucket = host.FlyfishFileViewerWebFullRenderers || (host.FlyfishFileViewerWebFullRenderers = {})
  83. bucket['${renderer.key}'] = renderer
  84. bucket[renderer.id] = renderer
  85. `, 'utf8')
  86. await build({
  87. configFile: false,
  88. publicDir: false,
  89. logLevel: 'warn',
  90. define: {
  91. 'process.env.NODE_ENV': JSON.stringify('production'),
  92. 'process.env': JSON.stringify({ NODE_ENV: 'production' }),
  93. 'import.meta.url': 'document.currentScript?.src || location.href'
  94. },
  95. resolve: {
  96. alias: {
  97. '@excalidraw/excalidraw': excalidrawStub
  98. },
  99. dedupe: ['@file-viewer/core']
  100. },
  101. build: {
  102. emptyOutDir: false,
  103. minify: 'esbuild',
  104. sourcemap: false,
  105. target: 'es2020',
  106. lib: {
  107. entry: rendererEntry,
  108. name: renderer.globalName,
  109. formats: ['iife'],
  110. fileName: () => `renderers/${renderer.key}.iife.js`
  111. },
  112. rollupOptions: {
  113. output: {
  114. exports: 'none',
  115. extend: true
  116. }
  117. }
  118. }
  119. })
  120. }
  121. await rm(generatedDir, { recursive: true, force: true })
  122. const assetSourceCandidates = [
  123. resolve(packageDir, '..', 'web', 'viewer'),
  124. resolve(packageDir, '..', '..', 'compat', 'web', 'viewer'),
  125. resolve(packageDir, '..', '..', '..', 'apps', 'viewer-demo', 'dist')
  126. ]
  127. const assetSource = assetSourceCandidates.find(candidate =>
  128. existsSync(resolve(candidate, 'flyfish-viewer-assets.json')) ||
  129. existsSync(resolve(candidate, 'vendor')) ||
  130. existsSync(resolve(candidate, 'wasm'))
  131. )
  132. if (assetSource) {
  133. for (const entry of [
  134. 'vendor',
  135. 'wasm',
  136. 'flyfish-viewer-assets.json',
  137. 'flyfish-viewer-manifest.json'
  138. ]) {
  139. const sourcePath = resolve(assetSource, entry)
  140. if (!existsSync(sourcePath)) {
  141. continue
  142. }
  143. const targetPath = resolve(outDir, entry)
  144. await rm(targetPath, { recursive: true, force: true })
  145. await cp(sourcePath, targetPath, { recursive: true })
  146. }
  147. console.log(`[web-full-iife] Copied viewer assets from ${assetSource}`)
  148. } else {
  149. console.warn('[web-full-iife] Viewer assets were not copied. Run pnpm build:viewer-assets before publishing the full CDN package.')
  150. }
  151. console.log(`[web-full-iife] Built ${join(outDir, fileName)} and ${rendererBuilds.length} async renderer bundles`)