@file-viewer/vite-plugin 3.0.2 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -147,6 +147,13 @@ This is useful when upload accept lists, sample matrices, or attachment allow-li
147
147
 
148
148
  When a file extension is in the supported matrix but the current project has not assembled its renderer, core now shows an install-oriented “renderer assembly required” state with the recommended preset / renderer package. For example, `.pdf` points to `@file-viewer/preset-office` or `@file-viewer/renderer-pdf`. Only truly unknown extensions show an unsupported-format state.
149
149
 
150
+ ## Nested Vite Projects
151
+
152
+ From 3.0.3, a nested metadata-only project can use a resolvable Full dependency
153
+ declared in an ancestor `package.json`. A nearer light component or preset keeps
154
+ its own root asset layout. Explicit `copyAssets.baseDir` still takes precedence;
155
+ `publicDir` and `build.outDir` stay relative to the Vite root, not the dependency owner.
156
+
150
157
  ## Current Boundary
151
158
 
152
159
  The plugin currently generates imports for extracted renderer packages: Word, Spreadsheet, PDF, OFD, Presentation, CAD, Draw.io/Excalidraw/Mermaid/PlantUML, 3D, Data, EDA, Typst, archives, email, EPUB, code/Markdown/Patch/Git Bundle, image, media, XMind, and Geo. Declare them explicitly with `formats`, or let `scan: true` discover source hints automatically; core-supported extensions such as `.zipx`, `.cbz`, `.tiff`, `.mjs`, `.gv`, `.patch`, `.bundle`, `.mermaid`, `.puml`, and `.mpeg` also resolve to their renderer packages. With `copyAssets:true`, the plugin detects installed capability packages. Full packages copy matching assets into dev `publicDir/file-viewer/` and production `outDir/file-viewer/`; standard packages/presets keep the existing root placement, including the Typst compiler / renderer WASM files and default fonts. `preset: 'auto' | 'lite' | 'office' | 'engineering' | 'all'` imports matching `@file-viewer/preset-*` packages; when `formats` are also present, the plugin adds extra renderers outside the preset.
package/README.md CHANGED
@@ -147,6 +147,13 @@ export const fileViewerFormats = ['pdf', 'docx', 'xlsx']
147
147
 
148
148
  如果用户打开的是支持矩阵内的格式,但项目没有安装或装配对应 renderer,core 会显示“需要装配预览能力”,并提示推荐安装的 preset / renderer 包,例如 `.pdf` 会引导安装 `@file-viewer/preset-office` 或 `@file-viewer/renderer-pdf`。只有真正不在支持矩阵中的扩展名才显示“不支持在线预览”。
149
149
 
150
+ ## 嵌套 Vite 项目
151
+
152
+ 从 3.0.3 起,子目录只有项目元数据或 Vite 插件声明时,会沿祖先 `package.json`
153
+ 查找实际可解析的 Full 依赖。子项目明确声明轻量组件或 preset 时保留其根目录资产布局,
154
+ 不会继承父项目的 Full 布局。`copyAssets.baseDir` 仍具有最高优先级;`publicDir`
155
+ 和 `build.outDir` 均相对于 Vite root,不相对于依赖所在目录。
156
+
150
157
  ## 当前边界
151
158
 
152
159
  当前插件会为已经拆出的 renderer 包生成导入:Word、Spreadsheet、PDF、OFD、Presentation、CAD、Draw.io/Excalidraw/Mermaid/PlantUML、3D、Data、EDA、Typst、压缩包、邮件、EPUB、代码/Markdown/Patch/Git Bundle、图片、媒体、XMind 和 Geo。可以通过 `formats` 显式声明,也可以通过 `scan: true` 从源码 hint 自动发现;`.zipx`、`.cbz`、`.tiff`、`.mjs`、`.gv`、`.patch`、`.bundle`、`.mermaid`、`.puml`、`.mpeg` 等 core 支持的扩展也会映射到对应 renderer。开启 `copyAssets:true` 时会识别已安装能力;full 包把匹配资源复制到开发 `publicDir/file-viewer/` 与构建 `outDir/file-viewer/`,标准包/preset 维持根目录行为,包括 Typst compiler / renderer WASM 与默认字体目录。`preset: 'auto' | 'lite' | 'office' | 'engineering' | 'all'` 会导入对应 `@file-viewer/preset-*` 包;如果同时声明 `formats`,插件会在 preset 之外补充额外 renderer。
package/dist/index.js CHANGED
@@ -465,6 +465,15 @@ const rendererModules = [
465
465
  rendererIds: ['data-asset'],
466
466
  chunkName: 'file-viewer-data'
467
467
  },
468
+ {
469
+ id: 'binary',
470
+ packageName: '@file-viewer/renderer-binary',
471
+ exportName: 'binaryRenderer',
472
+ formats: ['binary', 'binary-inspector', 'bin', 'hex', 'elf', 'exe', 'dll', 'class', 'macho'],
473
+ rendererIds: ['binary-inspector'],
474
+ chunkName: 'file-viewer-binary',
475
+ includeInPresetAll: false
476
+ },
468
477
  {
469
478
  id: 'eda',
470
479
  packageName: '@file-viewer/renderer-eda',
@@ -1483,6 +1492,21 @@ async function copyPdfCjkFontAssets(from, to) {
1483
1492
  await copyFile(license, join(to, 'OFL-1.1.txt'));
1484
1493
  return true;
1485
1494
  }
1495
+ function hasPdfCjkFontAssets(root, stylesheet, license) {
1496
+ if (!root) {
1497
+ return false;
1498
+ }
1499
+ const files = join(root, 'files');
1500
+ try {
1501
+ return (existsSync(join(root, stylesheet)) &&
1502
+ existsSync(join(root, license)) &&
1503
+ statSync(files).isDirectory() &&
1504
+ readdirSync(files, { withFileTypes: true }).some((entry) => entry.isFile() && entry.name.endsWith('.woff2')));
1505
+ }
1506
+ catch {
1507
+ return false;
1508
+ }
1509
+ }
1486
1510
  async function copyKnownRendererAssets(targetRoot, rendererIds) {
1487
1511
  const selected = new Set(rendererIds);
1488
1512
  const results = [];
@@ -1551,25 +1575,24 @@ async function copyKnownRendererAssets(targetRoot, rendererIds) {
1551
1575
  '@file-viewer/renderer-pdf'
1552
1576
  ]);
1553
1577
  const pdfCjkFontTarget = join(targetRoot, 'vendor/pdf/fonts');
1554
- // The standard profile pack owns the CJK fallback font; presets that activate the pdf
1555
- // renderer without that pack declare the font package directly. renderer-pdf must not
1556
- // vendor a second copy, so when no source is installed the build warns instead of
1557
- // failing and PDF rendering keeps using embedded fonts.
1558
- const pdfCjkFontSourceAvailable = Boolean(standardPdfCjkFontRoot && existsSync(join(standardPdfCjkFontRoot, 'noto-sans-sc.css'))) ||
1559
- Boolean(stagedPdfCjkFontRoot && existsSync(join(stagedPdfCjkFontRoot, 'wght.css'))) ||
1560
- Boolean(dependencyPdfCjkFontRoot);
1578
+ // The PDF renderer owns the runtime font dependency so direct renderer installs retain
1579
+ // CJK fallback support. The standard profile pack is only a pre-staged copy source.
1580
+ // A missing source means an incomplete install and must not silently drop the fallback.
1581
+ const hasStandardPdfCjkFont = hasPdfCjkFontAssets(standardPdfCjkFontRoot, 'noto-sans-sc.css', 'OFL-1.1.txt');
1582
+ const hasStagedPdfCjkFont = hasPdfCjkFontAssets(stagedPdfCjkFontRoot, 'wght.css', 'LICENSE');
1583
+ const hasDependencyPdfCjkFont = hasPdfCjkFontAssets(dependencyPdfCjkFontRoot, 'wght.css', 'LICENSE');
1584
+ const pdfCjkFontSourceAvailable = hasStandardPdfCjkFont || hasStagedPdfCjkFont || hasDependencyPdfCjkFont;
1561
1585
  await push('pdf', 'pdf-cjk-font-fallback', pdfCjkFontTarget, async () => {
1562
- if (standardPdfCjkFontRoot &&
1563
- existsSync(join(standardPdfCjkFontRoot, 'noto-sans-sc.css'))) {
1586
+ if (hasStandardPdfCjkFont && standardPdfCjkFontRoot) {
1564
1587
  return copyDirectoryIfPresent(standardPdfCjkFontRoot, pdfCjkFontTarget);
1565
1588
  }
1566
- if (stagedPdfCjkFontRoot && existsSync(join(stagedPdfCjkFontRoot, 'wght.css'))) {
1589
+ if (hasStagedPdfCjkFont && stagedPdfCjkFontRoot) {
1567
1590
  return copyPdfCjkFontAssets(stagedPdfCjkFontRoot, pdfCjkFontTarget);
1568
1591
  }
1569
1592
  return copyPdfCjkFontAssets(dependencyPdfCjkFontRoot, pdfCjkFontTarget);
1570
1593
  }, pdfCjkFontSourceAvailable
1571
1594
  ? undefined
1572
- : `install ${independentlyOwnedAssetRendererIds.get('pdf')} or @fontsource-variable/noto-sans-sc`, undefined, pdfCjkFontSourceAvailable ? undefined : false);
1595
+ : `repair @file-viewer/renderer-pdf and its @fontsource-variable/noto-sans-sc dependency`, undefined, true);
1573
1596
  const pptxRoot = resolvePackageRoot('@file-viewer/pptx', [
1574
1597
  '@file-viewer/renderer-pptx',
1575
1598
  '@file-viewer/renderer-presentation'
@@ -2066,25 +2089,37 @@ function findNearestProjectPackageJson(projectRoot) {
2066
2089
  }
2067
2090
  }
2068
2091
  function resolveInstalledFullPackages(projectRoot) {
2069
- const packageJsonPath = findNearestProjectPackageJson(projectRoot);
2070
- if (!packageJsonPath) {
2071
- return [];
2072
- }
2092
+ let packageJsonPath = findNearestProjectPackageJson(projectRoot);
2093
+ const lightPackages = fileViewerFullPackages.map(packageName => packageName.replace(/-full$/, ''));
2094
+ const projectPackageRequire = createRequire(join(resolve(projectRoot), 'package.json'));
2073
2095
  try {
2074
- const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
2075
- const declaredPackages = new Set([
2076
- ...Object.keys(packageJson.dependencies || {}),
2077
- ...Object.keys(packageJson.devDependencies || {}),
2078
- ...Object.keys(packageJson.optionalDependencies || {}),
2079
- ...Object.keys(packageJson.peerDependencies || {})
2080
- ]);
2081
- const projectPackageRequire = createRequire(packageJsonPath);
2082
- return fileViewerFullPackages.filter((packageName) => declaredPackages.has(packageName) &&
2083
- Boolean(tryResolvePackageJson(packageName, projectPackageRequire)));
2096
+ while (packageJsonPath) {
2097
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
2098
+ const declaredPackages = new Set([
2099
+ ...Object.keys(packageJson.dependencies || {}),
2100
+ ...Object.keys(packageJson.devDependencies || {}),
2101
+ ...Object.keys(packageJson.optionalDependencies || {}),
2102
+ ...Object.keys(packageJson.peerDependencies || {})
2103
+ ]);
2104
+ const declaresRuntime = [...declaredPackages].some(packageName => fileViewerFullPackages.some(fullPackage => fullPackage === packageName) ||
2105
+ lightPackages.includes(packageName) ||
2106
+ packageName.startsWith('@file-viewer/preset-') ||
2107
+ packageName.startsWith('@file-viewer/renderer-'));
2108
+ if (declaresRuntime) {
2109
+ return fileViewerFullPackages.filter(packageName => declaredPackages.has(packageName) &&
2110
+ Boolean(tryResolvePackageJson(packageName, projectPackageRequire)));
2111
+ }
2112
+ // Vite roots can contain a metadata-only package.json while runtime
2113
+ // dependencies live in an ancestor. A nearer light runtime is a boundary.
2114
+ const directory = dirname(packageJsonPath);
2115
+ const parent = dirname(directory);
2116
+ packageJsonPath = parent === directory ? null : findNearestProjectPackageJson(parent);
2117
+ }
2084
2118
  }
2085
2119
  catch {
2086
2120
  return [];
2087
2121
  }
2122
+ return [];
2088
2123
  }
2089
2124
  function resolveInstalledAssetPackages(projectRoot) {
2090
2125
  const packageJsonPath = findNearestProjectPackageJson(projectRoot);
@@ -2341,7 +2376,7 @@ export function fileViewerRenderers(options = {}) {
2341
2376
  const projectRoot = resolve(process.cwd(), userConfig.root || '.');
2342
2377
  refreshSelection(projectRoot);
2343
2378
  refreshFullAssetRuntime(projectRoot, userConfig.base);
2344
- const dependencyAnchorPackages = collectDependencyAnchorPackages(selection, autoPresetIds);
2379
+ const dependencyAnchorPackages = collectDependencyAnchorPackages(selection, installedFullPackages.length ? unique([...autoPresetIds, 'all']) : autoPresetIds);
2345
2380
  const resolvedDependencyAnchorPackages = runtimeAssetBase
2346
2381
  ? unique([
2347
2382
  ...dependencyAnchorPackages,
@@ -2525,7 +2560,7 @@ export function fileViewerRenderers(options = {}) {
2525
2560
  return [];
2526
2561
  },
2527
2562
  async closeBundle() {
2528
- if (!options.copyAssets || copyOptions(options.copyAssets).mode === 'dev') {
2563
+ if (resolvedConfig?.command === 'serve' || !options.copyAssets || copyOptions(options.copyAssets).mode === 'dev') {
2529
2564
  return;
2530
2565
  }
2531
2566
  const copyTarget = resolveFileViewerCopyAssetsTarget('build', options.copyAssets, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@file-viewer/vite-plugin",
3
- "version": "3.0.2",
3
+ "version": "3.1.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Vite plugin for File Viewer on-demand renderer assembly, chunk planning, and offline asset deployment.",
@@ -63,7 +63,7 @@
63
63
  }
64
64
  },
65
65
  "devDependencies": {
66
- "@types/node": "^26.4.0",
66
+ "@types/node": "^26.5.0",
67
67
  "typescript": "^6.0.3",
68
68
  "vite": "^8.2.2"
69
69
  },
@@ -71,6 +71,8 @@
71
71
  "scripts": {
72
72
  "build": "tsc -b tsconfig.json",
73
73
  "type-check": "tsc -b tsconfig.json",
74
- "verify:github-242": "node scripts/verify-github-242.mjs"
74
+ "verify:github-242": "pnpm build && node scripts/verify-github-242.mjs && node scripts/verify-github-242-copy.mjs",
75
+ "verify:github-257": "pnpm build && node scripts/verify-github-257.mjs",
76
+ "verify:github-257-browser": "npm exec --yes --package playwright@1.61.1 -- node scripts/verify-github-257-browser.mjs"
75
77
  }
76
78
  }