copy-cad-wasm.mjs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import { existsSync } from 'node:fs'
  2. import { copyFile, cp, mkdir, readdir, rm, stat } from 'node:fs/promises'
  3. import { dirname, isAbsolute, join, resolve } from 'node:path'
  4. import { createRequire } from 'node:module'
  5. import { fileURLToPath } from 'node:url'
  6. const require = createRequire(import.meta.url)
  7. const projectRoot = dirname(dirname(fileURLToPath(import.meta.url)))
  8. const packageResolveFallbacks = [
  9. 'packages/core/package.json',
  10. 'packages/renderers/cad/package.json',
  11. 'packages/renderers/typst/package.json',
  12. 'packages/renderers/data/package.json',
  13. 'packages/renderers/pdf/package.json',
  14. 'packages/renderers/archive/package.json',
  15. 'packages/renderers/drawing/package.json',
  16. 'packages/renderers/word/package.json'
  17. ].map(path => join(projectRoot, path)).filter(existsSync)
  18. const resolveFromProject = specifier => {
  19. try {
  20. return require.resolve(specifier)
  21. } catch {
  22. for (const packageJson of packageResolveFallbacks) {
  23. try {
  24. return createRequire(packageJson).resolve(specifier)
  25. } catch {
  26. // Keep probing renderer-owned dependencies after core sheds them.
  27. }
  28. }
  29. throw new Error(`[file-viewer] Unable to resolve package asset ${specifier}`)
  30. }
  31. }
  32. const findPackageJsonFromEntry = entry => {
  33. let current = dirname(entry)
  34. while (current && current !== dirname(current)) {
  35. const candidate = join(current, 'package.json')
  36. if (existsSync(candidate)) {
  37. return candidate
  38. }
  39. current = dirname(current)
  40. }
  41. throw new Error(`[file-viewer] Unable to locate package.json from ${entry}`)
  42. }
  43. const resolvePackageJson = packageName => {
  44. try {
  45. return resolveFromProject(`${packageName}/package.json`)
  46. } catch {
  47. return findPackageJsonFromEntry(resolveFromProject(packageName))
  48. }
  49. }
  50. const resolvePackageRoot = packageName => dirname(resolvePackageJson(packageName))
  51. const packageJson = resolvePackageJson('@flyfish-dev/cad-viewer')
  52. const packageRoot = dirname(packageJson)
  53. const distRoot = join(packageRoot, 'dist')
  54. const wasmDir = join(distRoot, 'wasm')
  55. const dwgWorker = join(wasmDir, 'dwg-worker.js')
  56. const typstCompilerWasm = join(
  57. resolvePackageRoot('@myriaddreamin/typst-ts-web-compiler'),
  58. 'pkg',
  59. 'typst_ts_web_compiler_bg.wasm'
  60. )
  61. const typstRendererWasm = join(
  62. resolvePackageRoot('@myriaddreamin/typst-ts-renderer'),
  63. 'pkg',
  64. 'typst_ts_renderer_bg.wasm'
  65. )
  66. const typstFontAssetsDir = join(resolvePackageRoot('@file-viewer/renderer-typst'), 'assets', 'fonts')
  67. const dataSqlWasm = join(resolvePackageRoot('sql.js'), 'dist', 'sql-wasm.wasm')
  68. const pdfjsRoot = resolvePackageRoot('pdfjs-dist')
  69. const pdfWorker = join(pdfjsRoot, 'legacy', 'build', 'pdf.worker.mjs')
  70. const pdfCmapsDir = join(pdfjsRoot, 'cmaps')
  71. const pdfWasmDir = join(pdfjsRoot, 'wasm')
  72. const pdfStandardFontsDir = join(pdfjsRoot, 'standard_fonts')
  73. const drawioSourceRoot = join(projectRoot, 'third_party', 'drawio')
  74. const rawArgs = process.argv.slice(2)
  75. const args = new Set(rawArgs)
  76. const readArgValue = name => {
  77. const index = rawArgs.indexOf(name)
  78. if (index === -1) {
  79. return undefined
  80. }
  81. const value = rawArgs[index + 1]
  82. return value && !value.startsWith('--') ? value : undefined
  83. }
  84. const resolveFromCwd = value => {
  85. if (!value) {
  86. return undefined
  87. }
  88. return isAbsolute(value) ? value : resolve(process.cwd(), value)
  89. }
  90. const publicRoot = resolveFromCwd(readArgValue('--public-root')) ?? join(projectRoot, 'apps/viewer-demo/public')
  91. const distBaseRoot = resolveFromCwd(readArgValue('--dist-root')) ?? join(projectRoot, 'apps/viewer-demo/dist')
  92. const baseTargetRoots = [
  93. !args.has('--dist-only') && publicRoot,
  94. (args.has('--dist') || args.has('--dist-only')) && distBaseRoot
  95. ].filter(Boolean)
  96. const cadTargetRoots = baseTargetRoots.map(root => join(root, 'wasm', 'cad'))
  97. const typstTargetRoots = baseTargetRoots.map(root => join(root, 'wasm', 'typst'))
  98. const dataTargetRoots = baseTargetRoots.map(root => join(root, 'wasm', 'data'))
  99. const pdfTargetRoots = baseTargetRoots.map(root => join(root, 'vendor', 'pdf'))
  100. const drawioTargetRoots = baseTargetRoots.map(root => join(root, 'vendor', 'drawio'))
  101. const copyWorkerChunks = async targetRoot => {
  102. const files = await readdir(wasmDir)
  103. await Promise.all(
  104. files
  105. .filter(file => /^dwg-worker-.+\.js$/.test(file))
  106. .map(file => copyChecked(join(wasmDir, file), join(targetRoot, file)))
  107. )
  108. }
  109. const copyChecked = async (from, to) => {
  110. const info = await stat(from)
  111. if (!info.isFile() || info.size <= 0) {
  112. throw new Error(`[file-viewer] Invalid viewer asset: ${from}`)
  113. }
  114. await copyFile(from, to)
  115. }
  116. const copyDirectoryChecked = async (from, to) => {
  117. const info = await stat(from)
  118. if (!info.isDirectory()) {
  119. throw new Error(`[file-viewer] Invalid viewer asset directory: ${from}`)
  120. }
  121. await rm(to, { recursive: true, force: true })
  122. await mkdir(dirname(to), { recursive: true })
  123. await cp(from, to, { recursive: true, force: true })
  124. }
  125. for (const targetRoot of cadTargetRoots) {
  126. await mkdir(targetRoot, { recursive: true })
  127. await copyChecked(join(wasmDir, 'libredwg-web.js'), join(targetRoot, 'libredwg-web.js'))
  128. await copyChecked(join(wasmDir, 'libredwg-web.wasm'), join(targetRoot, 'libredwg-web.wasm'))
  129. await copyChecked(join(wasmDir, 'dwfv-render.wasm'), join(targetRoot, 'dwfv-render.wasm'))
  130. await copyWorkerChunks(targetRoot)
  131. await copyChecked(dwgWorker, join(targetRoot, 'dwg-worker.js'))
  132. }
  133. for (const targetRoot of typstTargetRoots) {
  134. await mkdir(targetRoot, { recursive: true })
  135. await copyChecked(typstCompilerWasm, join(targetRoot, 'typst_ts_web_compiler_bg.wasm'))
  136. await copyChecked(typstRendererWasm, join(targetRoot, 'typst_ts_renderer_bg.wasm'))
  137. await copyDirectoryChecked(typstFontAssetsDir, join(targetRoot, 'fonts'))
  138. }
  139. for (const targetRoot of dataTargetRoots) {
  140. await mkdir(targetRoot, { recursive: true })
  141. await copyChecked(dataSqlWasm, join(targetRoot, 'sql-wasm.wasm'))
  142. }
  143. for (const targetRoot of pdfTargetRoots) {
  144. await mkdir(targetRoot, { recursive: true })
  145. await copyChecked(pdfWorker, join(targetRoot, 'pdf.worker.mjs'))
  146. await copyDirectoryChecked(pdfCmapsDir, join(targetRoot, 'cmaps'))
  147. await copyDirectoryChecked(pdfWasmDir, join(targetRoot, 'wasm'))
  148. await copyDirectoryChecked(pdfStandardFontsDir, join(targetRoot, 'standard_fonts'))
  149. }
  150. for (const targetRoot of drawioTargetRoots) {
  151. await copyDirectoryChecked(drawioSourceRoot, targetRoot)
  152. }
  153. console.log(
  154. `[file-viewer] Viewer WASM assets copied to ${
  155. [...cadTargetRoots, ...typstTargetRoots, ...dataTargetRoots, ...pdfTargetRoots, ...drawioTargetRoots]
  156. .map(root => root.replace(`${projectRoot}/`, ''))
  157. .join(', ')
  158. }`
  159. )