@file-viewer/vite-plugin 3.1.1 → 3.2.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 +3 -160
- package/README.md +3 -160
- package/dist/index.d.ts +0 -80
- package/dist/index.js +85 -43
- package/package.json +12 -18
package/README.en.md
CHANGED
|
@@ -1,164 +1,7 @@
|
|
|
1
1
|
# @file-viewer/vite-plugin
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Runtime package version 3.2.0.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Usage and API documentation: https://doc.file-viewer.app/guide/on-demand-renderers
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
pnpm add @file-viewer/vue3-full
|
|
11
|
-
pnpm add -D @file-viewer/vite-plugin
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
```ts
|
|
15
|
-
import { defineConfig } from 'vite'
|
|
16
|
-
import { fileViewerRenderers } from '@file-viewer/vite-plugin'
|
|
17
|
-
|
|
18
|
-
export default defineConfig({
|
|
19
|
-
plugins: [
|
|
20
|
-
fileViewerRenderers({
|
|
21
|
-
copyAssets: true
|
|
22
|
-
})
|
|
23
|
-
]
|
|
24
|
-
})
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Installing a full package without publishing these assets leaves PDF Worker, CAD/Typst/Archive WASM, and other formats without runtime files. That is partial support, not a complete setup.
|
|
28
|
-
|
|
29
|
-
For a smaller install, use a standard component with one preset and keep the same Vite config. The plugin auto-discovers installed presets, so application code does not hand-write renderer imports and the plugin does not need `preset:'office'`:
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
pnpm add @file-viewer/vue3 @file-viewer/preset-office
|
|
33
|
-
pnpm add -D @file-viewer/vite-plugin
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Components keep `autoRenderers:true` by default, so `@file-viewer/vue3`, `@file-viewer/react`, `@file-viewer/web`, `@file-viewer/svelte`, `@file-viewer/jquery`, `@file-viewer/vue2.7`, and `@file-viewer/vue2.6` automatically consume the injected preset / renderer registry.
|
|
37
|
-
|
|
38
|
-
Available presets:
|
|
39
|
-
|
|
40
|
-
- `@file-viewer/preset-lite`: text, Markdown, code, image, audio, and video.
|
|
41
|
-
- `@file-viewer/preset-office`: PDF, Word, Excel, PowerPoint, OFD, RTF, and OpenDocument.
|
|
42
|
-
- `@file-viewer/preset-engineering`: CAD, 3D, drawing, XMind, Geo, Typst, Archive, Data, and EDA.
|
|
43
|
-
- `@file-viewer/preset-all`: the complete official demo format matrix.
|
|
44
|
-
|
|
45
|
-
Install individual renderer packages only for strict cuts, such as `@file-viewer/renderer-pdf`, `@file-viewer/renderer-word`, `@file-viewer/renderer-ofd`, `@file-viewer/renderer-presentation`, `@file-viewer/renderer-cad`, `@file-viewer/renderer-drawing`, `@file-viewer/renderer-3d`, `@file-viewer/renderer-data`, `@file-viewer/renderer-eda`, `@file-viewer/renderer-typst`, `@file-viewer/renderer-archive`, or `@file-viewer/renderer-text`, then use `formats` to generate exact imports.
|
|
46
|
-
|
|
47
|
-
## vite.config.ts
|
|
48
|
-
|
|
49
|
-
Prefer full/preset auto assembly for normal products. With only `copyAssets:true`, the plugin auto-discovers installed `@file-viewer/*-full` or `@file-viewer/preset-*` packages:
|
|
50
|
-
|
|
51
|
-
```ts
|
|
52
|
-
fileViewerRenderers({
|
|
53
|
-
copyAssets: true
|
|
54
|
-
})
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Use customization options only when you need source scanning, single-format cuts, or manual registry control:
|
|
58
|
-
|
|
59
|
-
```ts
|
|
60
|
-
import { defineConfig } from 'vite'
|
|
61
|
-
import { fileViewerRenderers } from '@file-viewer/vite-plugin'
|
|
62
|
-
|
|
63
|
-
export default defineConfig({
|
|
64
|
-
plugins: [
|
|
65
|
-
fileViewerRenderers({
|
|
66
|
-
formats: ['pdf', 'dwg', 'typst', 'zip', 'xmind'],
|
|
67
|
-
scan: true,
|
|
68
|
-
copyAssets: true,
|
|
69
|
-
chunkStrategy: 'renderer'
|
|
70
|
-
})
|
|
71
|
-
]
|
|
72
|
-
})
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
`inject` is enabled by default. The plugin injects `virtual:file-viewer-renderers` into Vite HTML entrypoints, preset imports register themselves in core, and framework components consume them through `autoRenderers`.
|
|
76
|
-
|
|
77
|
-
```ts
|
|
78
|
-
const options = {
|
|
79
|
-
// Defaults to true; set false when a product needs total manual control.
|
|
80
|
-
autoRenderers: true
|
|
81
|
-
}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### Customization Options
|
|
85
|
-
|
|
86
|
-
| Option | Description |
|
|
87
|
-
| --- | --- |
|
|
88
|
-
| `copyAssets` | `true` or `{ publicDir, outDir, mode, baseDir }`; copies matching Worker, WASM, font, and vendor assets. Installed full packages default to `<deployment-base>/file-viewer/`, which is required for complete full support; standard packages/presets keep the existing root behavior |
|
|
89
|
-
| `preset` | `'auto' | 'lite' | 'office' | 'engineering' | 'all'`; with no explicit formats, installed presets are discovered automatically |
|
|
90
|
-
| `autoPresets` | `true` or a preset list; useful with `scan:true` when installed presets should stay active |
|
|
91
|
-
| `formats` | File extensions or format tokens, for example `['pdf', 'docx', 'dwg']` |
|
|
92
|
-
| `renderers` | Renderer ids, for example `['pdf', 'word', 'cad']` |
|
|
93
|
-
| `scan` | `true` or `{ roots, extensions, maxFileSize }`; scans source hints and merges formats |
|
|
94
|
-
| `inject` | Defaults to `true`; set `false` to import `virtual:file-viewer-renderers` manually |
|
|
95
|
-
| `chunkStrategy` | `'renderer' | 'none'`; controls renderer-level chunk grouping |
|
|
96
|
-
| `stabilizeInteropChunks` | Defaults to `true`; when the host project already defines a `manualChunks` function, keeps CodeMirror / Lezer / Sandpack in one chunk to avoid production TDZ initialization errors |
|
|
97
|
-
| `missingRenderer` | `'error' | 'warn' | 'ignore'`; controls notices for planned renderer mappings |
|
|
98
|
-
|
|
99
|
-
When host apps split `node_modules` by package name, circular dependencies between `@codemirror/*`, `@lezer/*`, and Sandpack can show up in production as `codemirror-view.* Cannot access ... before initialization`. The plugin wraps existing `manualChunks` functions by default, stabilizes only those known interop chunks, and preserves the rest of the app's custom grouping. Set `stabilizeInteropChunks:false` only when the host build needs total control.
|
|
100
|
-
|
|
101
|
-
`copyAssets.baseDir` overrides automatic placement. It must be relative and cannot contain `..`; an empty string explicitly selects the root. The plugin now aligns the shared runtime asset base for standard packages, presets, and full packages; full packages also keep `setDefaultFullAssetBaseUrl()` synchronized. Only integrations that set `inject:false` and do not import the virtual module must call `setDefaultFileViewerAssetBaseUrl()` themselves (plus `setDefaultFullAssetBaseUrl()` for a full package). With Vite `base:'/app/'`, full-package dev URLs start with `/app/file-viewer/...`, while production files remain under `outDir/file-viewer/`.
|
|
102
|
-
|
|
103
|
-
For strict registry control, disable injection and pass the virtual module explicitly:
|
|
104
|
-
|
|
105
|
-
```ts
|
|
106
|
-
fileViewerRenderers({
|
|
107
|
-
formats: ['pdf'],
|
|
108
|
-
inject: false,
|
|
109
|
-
copyAssets: true
|
|
110
|
-
})
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
```ts
|
|
114
|
-
import { configuredFileViewerRenderers } from 'virtual:file-viewer-renderers'
|
|
115
|
-
|
|
116
|
-
const options = {
|
|
117
|
-
rendererMode: 'replace',
|
|
118
|
-
renderers: configuredFileViewerRenderers
|
|
119
|
-
}
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
You can also use `preset: 'auto'` to discover installed preset packages. When `preset-all` is installed, it wins to avoid importing narrower presets twice. Note: when `scan:true` is enabled, use `preset:'auto'` or `autoPresets:true` explicitly; otherwise the plugin treats source hints as the explicit renderer selection and skips zero-config preset discovery.
|
|
123
|
-
|
|
124
|
-
```ts
|
|
125
|
-
fileViewerRenderers({
|
|
126
|
-
preset: 'auto',
|
|
127
|
-
scan: true,
|
|
128
|
-
formats: ['pdf'],
|
|
129
|
-
copyAssets: true,
|
|
130
|
-
chunkStrategy: 'renderer'
|
|
131
|
-
})
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
`scan: true` inspects common source folders for lightweight hints and merges them with `formats`:
|
|
135
|
-
|
|
136
|
-
```ts
|
|
137
|
-
export const fileViewerFormats = ['pdf', 'docx', 'xlsx']
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
```html
|
|
141
|
-
<input accept=".pdf,.docx" data-file-viewer-formats="dwg,xmind" />
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
This is useful when upload accept lists, sample matrices, or attachment allow-lists already live in source code: dev and production builds can generate the renderer assembly module without a second hand-written import list.
|
|
145
|
-
|
|
146
|
-
## Missing Renderer Guidance
|
|
147
|
-
|
|
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
|
-
|
|
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
|
-
|
|
157
|
-
## Current Boundary
|
|
158
|
-
|
|
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.
|
|
160
|
-
|
|
161
|
-
## Documentation
|
|
162
|
-
|
|
163
|
-
- On-demand renderer architecture: <https://doc.file-viewer.app/guide/on-demand-renderers>
|
|
164
|
-
- Supported formats: <https://doc.file-viewer.app/guide/formats>
|
|
7
|
+
The package's own license is Apache-2.0. Included third-party notices apply to their respective components.
|
package/README.md
CHANGED
|
@@ -1,164 +1,7 @@
|
|
|
1
1
|
# @file-viewer/vite-plugin
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Runtime package version 3.2.0.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Usage and API documentation: https://doc.file-viewer.app/guide/on-demand-renderers
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
pnpm add @file-viewer/vue3-full
|
|
11
|
-
pnpm add -D @file-viewer/vite-plugin
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
```ts
|
|
15
|
-
import { defineConfig } from 'vite'
|
|
16
|
-
import { fileViewerRenderers } from '@file-viewer/vite-plugin'
|
|
17
|
-
|
|
18
|
-
export default defineConfig({
|
|
19
|
-
plugins: [
|
|
20
|
-
fileViewerRenderers({
|
|
21
|
-
copyAssets: true
|
|
22
|
-
})
|
|
23
|
-
]
|
|
24
|
-
})
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
只安装 full 包而不启用资源复制,PDF Worker、CAD/Typst/Archive WASM 等格式会缺少运行文件,只能获得部分格式支持。
|
|
28
|
-
|
|
29
|
-
需要更小体积时,改用“标准组件包 + 一个 preset”,Vite 配置保持不变。插件会自动发现已安装的 preset,无需手写 renderer import,也无需显式写 `preset:'office'`:
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
pnpm add @file-viewer/vue3 @file-viewer/preset-office
|
|
33
|
-
pnpm add -D @file-viewer/vite-plugin
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
组件默认 `autoRenderers:true`,会读取 Vite 插件注入的 preset / renderer registry。常规业务代码只要使用 `@file-viewer/vue3`、`@file-viewer/react`、`@file-viewer/web`、`@file-viewer/svelte`、`@file-viewer/jquery`、`@file-viewer/vue2.7` 或 `@file-viewer/vue2.6` 即可获得对应能力。
|
|
37
|
-
|
|
38
|
-
可选 preset:
|
|
39
|
-
|
|
40
|
-
- `@file-viewer/preset-lite`: 文本、Markdown、代码、图片、音频、视频。
|
|
41
|
-
- `@file-viewer/preset-office`: PDF、Word、Excel、PowerPoint、OFD、RTF、OpenDocument。
|
|
42
|
-
- `@file-viewer/preset-engineering`: CAD、3D、绘图、XMind、Geo、Typst、Archive、Data、EDA。
|
|
43
|
-
- `@file-viewer/preset-all`: 官方 demo 完整格式矩阵。
|
|
44
|
-
|
|
45
|
-
如果只需要极少数格式,也可以安装对应 renderer 包,例如 `@file-viewer/renderer-pdf`、`@file-viewer/renderer-word`、`@file-viewer/renderer-ofd`、`@file-viewer/renderer-presentation`、`@file-viewer/renderer-cad`、`@file-viewer/renderer-drawing`、`@file-viewer/renderer-3d`、`@file-viewer/renderer-data`、`@file-viewer/renderer-eda`、`@file-viewer/renderer-typst`、`@file-viewer/renderer-archive`、`@file-viewer/renderer-text`,再通过 `formats` 做精确裁剪。
|
|
46
|
-
|
|
47
|
-
## vite.config.ts
|
|
48
|
-
|
|
49
|
-
推荐默认使用 full/preset 自动装配。只传 `copyAssets:true` 时,插件会自动发现已安装的 `@file-viewer/*-full` 或 `@file-viewer/preset-*`,无需写 `preset:'all'`:
|
|
50
|
-
|
|
51
|
-
```ts
|
|
52
|
-
fileViewerRenderers({
|
|
53
|
-
copyAssets: true
|
|
54
|
-
})
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
只有在需要源码扫描、单格式裁剪、或手动 registry 管理时,再使用自定义能力:
|
|
58
|
-
|
|
59
|
-
```ts
|
|
60
|
-
import { defineConfig } from 'vite'
|
|
61
|
-
import { fileViewerRenderers } from '@file-viewer/vite-plugin'
|
|
62
|
-
|
|
63
|
-
export default defineConfig({
|
|
64
|
-
plugins: [
|
|
65
|
-
fileViewerRenderers({
|
|
66
|
-
formats: ['pdf', 'dwg', 'typst', 'zip', 'xmind'],
|
|
67
|
-
scan: true,
|
|
68
|
-
copyAssets: true,
|
|
69
|
-
chunkStrategy: 'renderer'
|
|
70
|
-
})
|
|
71
|
-
]
|
|
72
|
-
})
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
`inject` 默认开启,插件会把 `virtual:file-viewer-renderers` 注入 Vite HTML 入口,preset 导入后会自动注册到 core。常规业务只需要安装组件包和对应 preset,组件会通过 `autoRenderers` 默认读取这些能力。
|
|
76
|
-
|
|
77
|
-
```ts
|
|
78
|
-
const options = {
|
|
79
|
-
// 默认 true;需要完全手动控制时设为 false。
|
|
80
|
-
autoRenderers: true
|
|
81
|
-
}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### 可定制能力
|
|
85
|
-
|
|
86
|
-
| 选项 | 说明 |
|
|
87
|
-
| --- | --- |
|
|
88
|
-
| `copyAssets` | `true` 或 `{ publicDir, outDir, mode, baseDir }`;复制匹配的 Worker、WASM、字体和 vendor 资源。检测到 full 时默认发布到 `<部署基址>/file-viewer/`,这是 full 完整格式支持的必需项;标准包/preset 保持原有根目录行为 |
|
|
89
|
-
| `preset` | `'auto' | 'lite' | 'office' | 'engineering' | 'all'`;默认无显式格式时自动发现已安装 preset |
|
|
90
|
-
| `autoPresets` | `true` 或 preset 列表;常用于 `scan:true` 时继续自动激活已安装 preset |
|
|
91
|
-
| `formats` | 文件扩展名或格式 token,例如 `['pdf', 'docx', 'dwg']` |
|
|
92
|
-
| `renderers` | renderer id,例如 `['pdf', 'word', 'cad']` |
|
|
93
|
-
| `scan` | `true` 或 `{ roots, extensions, maxFileSize }`,扫描源码 hint 并合并格式 |
|
|
94
|
-
| `inject` | 默认 `true`;设为 `false` 后手动导入 `virtual:file-viewer-renderers` |
|
|
95
|
-
| `chunkStrategy` | `'renderer' | 'none'`,控制是否注入 renderer 级 chunk 分组 |
|
|
96
|
-
| `stabilizeInteropChunks` | 默认 `true`;当宿主项目已有 `manualChunks` 函数时,把 CodeMirror / Lezer / Sandpack 归到同一 chunk,避免生产构建 TDZ 初始化错误 |
|
|
97
|
-
| `missingRenderer` | `'error' | 'warn' | 'ignore'`,控制尚未提取的 renderer 映射提示方式 |
|
|
98
|
-
|
|
99
|
-
如果宿主项目按包名拆分 `node_modules`,`@codemirror/*`、`@lezer/*` 和 Sandpack 之间的循环依赖可能在生产构建中表现为 `codemirror-view.* Cannot access ... before initialization`。插件默认会包裹已有的 `manualChunks` 函数,只稳定这些已知互操作 chunk,保留其它自定义分组;确实需要完全接管时可设置 `stabilizeInteropChunks:false`。
|
|
100
|
-
|
|
101
|
-
`copyAssets.baseDir` 可以覆盖自动目录:必须是相对路径,不能包含 `..`;传空字符串表示显式复制到根目录。插件会为标准包、preset 和 full 包同步统一运行时资源根;full 包仍同时同步 `setDefaultFullAssetBaseUrl()`。只有设置 `inject:false` 且不手动导入虚拟模块时,业务才需要调用 `setDefaultFileViewerAssetBaseUrl()`(full 包同时调用 `setDefaultFullAssetBaseUrl()`)。Vite 配置了 `base:'/app/'` 时,full 包开发 URL 为 `/app/file-viewer/...`,构建文件仍位于 `outDir/file-viewer/`。
|
|
102
|
-
|
|
103
|
-
如果你需要严格控制 registry,可以关闭注入并手动传入:
|
|
104
|
-
|
|
105
|
-
```ts
|
|
106
|
-
fileViewerRenderers({
|
|
107
|
-
formats: ['pdf'],
|
|
108
|
-
inject: false,
|
|
109
|
-
copyAssets: true
|
|
110
|
-
})
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
```ts
|
|
114
|
-
import { configuredFileViewerRenderers } from 'virtual:file-viewer-renderers'
|
|
115
|
-
|
|
116
|
-
const options = {
|
|
117
|
-
rendererMode: 'replace',
|
|
118
|
-
renderers: configuredFileViewerRenderers
|
|
119
|
-
}
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
也可以使用 `preset: 'auto'` 发现项目中已安装的 preset 包;当 `preset-all` 存在时会优先使用它,避免重复导入其它 preset。注意:如果同时开启 `scan:true`,请显式使用 `preset:'auto'` 或 `autoPresets:true`,否则插件会以源码 hint 为准,不再做“无配置 preset 自动发现”。
|
|
123
|
-
|
|
124
|
-
```ts
|
|
125
|
-
fileViewerRenderers({
|
|
126
|
-
preset: 'auto',
|
|
127
|
-
scan: true,
|
|
128
|
-
formats: ['pdf'],
|
|
129
|
-
copyAssets: true,
|
|
130
|
-
chunkStrategy: 'renderer'
|
|
131
|
-
})
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
`scan: true` 会扫描常见源码目录里的轻量 hint,并把它们合并到 `formats`:
|
|
135
|
-
|
|
136
|
-
```ts
|
|
137
|
-
export const fileViewerFormats = ['pdf', 'docx', 'xlsx']
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
```html
|
|
141
|
-
<input accept=".pdf,.docx" data-file-viewer-formats="dwg,xmind" />
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
这适合业务把上传入口、示例矩阵或附件白名单维护在源码中时使用:开发和构建阶段插件会自动生成 renderer 装配模块,少写一份手工 import 清单。
|
|
145
|
-
|
|
146
|
-
## 缺失 renderer 提示
|
|
147
|
-
|
|
148
|
-
如果用户打开的是支持矩阵内的格式,但项目没有安装或装配对应 renderer,core 会显示“需要装配预览能力”,并提示推荐安装的 preset / renderer 包,例如 `.pdf` 会引导安装 `@file-viewer/preset-office` 或 `@file-viewer/renderer-pdf`。只有真正不在支持矩阵中的扩展名才显示“不支持在线预览”。
|
|
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
|
-
|
|
157
|
-
## 当前边界
|
|
158
|
-
|
|
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。
|
|
160
|
-
|
|
161
|
-
## 文档
|
|
162
|
-
|
|
163
|
-
- 按需渲染架构: <https://doc.file-viewer.app/guide/on-demand-renderers>
|
|
164
|
-
- 支持格式: <https://doc.file-viewer.app/guide/formats>
|
|
7
|
+
The package's own license is Apache-2.0. Included third-party notices apply to their respective components.
|
package/dist/index.d.ts
CHANGED
|
@@ -4,101 +4,28 @@ export type FileViewerVitePresetMode = FileViewerVitePreset | 'auto';
|
|
|
4
4
|
export type FileViewerMissingRendererMode = 'error' | 'warn' | 'ignore';
|
|
5
5
|
export type FileViewerChunkStrategy = 'renderer' | 'none';
|
|
6
6
|
export interface FileViewerRendererScanOptions {
|
|
7
|
-
/**
|
|
8
|
-
* Disable a shared scan object without branching user config.
|
|
9
|
-
*/
|
|
10
7
|
enabled?: boolean;
|
|
11
|
-
/**
|
|
12
|
-
* Source roots, relative to Vite root, that should be inspected for format hints.
|
|
13
|
-
* Defaults to common application source folders.
|
|
14
|
-
*/
|
|
15
8
|
roots?: readonly string[];
|
|
16
|
-
/**
|
|
17
|
-
* Text-like source extensions to inspect. Values may include or omit the dot.
|
|
18
|
-
*/
|
|
19
9
|
extensions?: readonly string[];
|
|
20
|
-
/**
|
|
21
|
-
* Large generated files are ignored by default to keep config/startup fast.
|
|
22
|
-
*/
|
|
23
10
|
maxFileSize?: number;
|
|
24
11
|
}
|
|
25
12
|
export interface FileViewerCopyAssetsOptions {
|
|
26
|
-
/**
|
|
27
|
-
* Directory used by Vite dev. Defaults to config.publicDir.
|
|
28
|
-
*/
|
|
29
13
|
publicDir?: string;
|
|
30
|
-
/**
|
|
31
|
-
* Directory used after production build. Defaults to build.outDir.
|
|
32
|
-
*/
|
|
33
14
|
outDir?: string;
|
|
34
|
-
/**
|
|
35
|
-
* Directory below publicDir/outDir where assets are published. When omitted,
|
|
36
|
-
* projects with an installed @file-viewer/*-full package use `file-viewer`;
|
|
37
|
-
* other projects keep the existing output-root layout. Use an empty string
|
|
38
|
-
* to explicitly publish at the output root. The injected runtime module
|
|
39
|
-
* keeps every renderer's default asset base aligned with this directory.
|
|
40
|
-
*/
|
|
41
15
|
baseDir?: string;
|
|
42
|
-
/**
|
|
43
|
-
* Copy during dev server startup, build closeBundle, or both.
|
|
44
|
-
*/
|
|
45
16
|
mode?: 'dev' | 'build' | 'both';
|
|
46
17
|
}
|
|
47
18
|
export interface FileViewerRenderersPluginOptions {
|
|
48
|
-
/**
|
|
49
|
-
* File extensions or renderer ids. Examples: pdf, .dwg, typst, zip, xmind.
|
|
50
|
-
*/
|
|
51
19
|
formats?: readonly string[];
|
|
52
|
-
/**
|
|
53
|
-
* Explicit renderer ids. Useful when several extensions share one renderer.
|
|
54
|
-
*/
|
|
55
20
|
renderers?: readonly string[];
|
|
56
|
-
/**
|
|
57
|
-
* Presets import their dedicated @file-viewer/preset-* package. Use `auto`
|
|
58
|
-
* to discover installed preset packages, and add `formats` / `renderers`
|
|
59
|
-
* when you need to extend a preset with extra lines.
|
|
60
|
-
*/
|
|
61
21
|
preset?: FileViewerVitePresetMode;
|
|
62
|
-
/**
|
|
63
|
-
* Auto-discovers installed `@file-viewer/preset-*` packages and registers
|
|
64
|
-
* them globally for framework components. Defaults to true only when no
|
|
65
|
-
* explicit preset/formats/renderers are configured, or when `preset: 'auto'`.
|
|
66
|
-
*/
|
|
67
22
|
autoPresets?: boolean | readonly FileViewerVitePreset[];
|
|
68
|
-
/**
|
|
69
|
-
* Injects the virtual renderer module into Vite HTML entrypoints so
|
|
70
|
-
* framework components can consume auto-registered renderers without
|
|
71
|
-
* application code importing `virtual:file-viewer-renderers`.
|
|
72
|
-
*/
|
|
73
23
|
inject?: boolean;
|
|
74
|
-
/**
|
|
75
|
-
* Virtual module id consumed by application code.
|
|
76
|
-
*/
|
|
77
24
|
moduleId?: string;
|
|
78
|
-
/**
|
|
79
|
-
* Controls how planned-but-not-yet-extracted renderer lines are reported.
|
|
80
|
-
*/
|
|
81
25
|
missingRenderer?: FileViewerMissingRendererMode;
|
|
82
|
-
/**
|
|
83
|
-
* Adds renderer-oriented manualChunks when the user did not define one.
|
|
84
|
-
*/
|
|
85
26
|
chunkStrategy?: FileViewerChunkStrategy;
|
|
86
|
-
/**
|
|
87
|
-
* Wraps existing manualChunks functions with known circular-dependency-safe
|
|
88
|
-
* vendor groups. This keeps CodeMirror/Lezer/Sandpack in one chunk when host
|
|
89
|
-
* apps split node_modules by package name, avoiding production TDZ errors.
|
|
90
|
-
*/
|
|
91
27
|
stabilizeInteropChunks?: boolean;
|
|
92
|
-
/**
|
|
93
|
-
* Copies known worker/WASM/vendor assets for selected renderer lines.
|
|
94
|
-
*/
|
|
95
28
|
copyAssets?: boolean | FileViewerCopyAssetsOptions;
|
|
96
|
-
/**
|
|
97
|
-
* Opt-in source scan. The plugin reads lightweight hints such as
|
|
98
|
-
* `fileViewerFormats = ['pdf', 'docx']`, `data-file-viewer-formats="pdf,docx"`,
|
|
99
|
-
* and upload `accept=".pdf,.docx"` declarations, then merges them with
|
|
100
|
-
* `formats` / `renderers` before generating the virtual module.
|
|
101
|
-
*/
|
|
102
29
|
scan?: boolean | FileViewerRendererScanOptions;
|
|
103
30
|
}
|
|
104
31
|
interface MissingRendererNotice {
|
|
@@ -109,11 +36,8 @@ interface MissingRendererNotice {
|
|
|
109
36
|
export declare function extractFileViewerRendererHintTokens(source: string): string[];
|
|
110
37
|
export declare function collectFileViewerRendererScanTokens(projectRoot: string, scan: FileViewerRenderersPluginOptions['scan']): string[];
|
|
111
38
|
export interface FileViewerCopyAssetsTargetConfig {
|
|
112
|
-
/** Vite project root. Defaults to process.cwd(). */
|
|
113
39
|
projectRoot?: string;
|
|
114
|
-
/** Resolved Vite publicDir. Defaults to `public`. */
|
|
115
40
|
publicDir?: string;
|
|
116
|
-
/** Resolved Vite build.outDir. Defaults to `dist`. */
|
|
117
41
|
outDir?: string;
|
|
118
42
|
}
|
|
119
43
|
export interface FileViewerCopyAssetsTarget {
|
|
@@ -124,10 +48,6 @@ export interface FileViewerCopyAssetsTarget {
|
|
|
124
48
|
installedFullPackages: string[];
|
|
125
49
|
installedAssetPackages: string[];
|
|
126
50
|
}
|
|
127
|
-
/**
|
|
128
|
-
* Resolves the exact directory used by copyAssets without running a Vite build.
|
|
129
|
-
* This is exported so integrations can validate their deployment contract.
|
|
130
|
-
*/
|
|
131
51
|
export declare function resolveFileViewerCopyAssetsTarget(mode: 'dev' | 'build', value?: true | FileViewerCopyAssetsOptions, config?: FileViewerCopyAssetsTargetConfig): FileViewerCopyAssetsTarget;
|
|
132
52
|
export declare function fileViewerRenderers(options?: FileViewerRenderersPluginOptions): Plugin;
|
|
133
53
|
export declare function createFileViewerManualChunks(options?: FileViewerRenderersPluginOptions): (id: string) => string | undefined;
|
package/dist/index.js
CHANGED
|
@@ -124,6 +124,16 @@ const rendererModules = [
|
|
|
124
124
|
rendererIds: ['drawing'],
|
|
125
125
|
chunkName: 'file-viewer-drawing'
|
|
126
126
|
},
|
|
127
|
+
{
|
|
128
|
+
id: 'bpmn',
|
|
129
|
+
packageName: '@file-viewer/renderer-drawing',
|
|
130
|
+
importPath: '@file-viewer/renderer-drawing/bpmn',
|
|
131
|
+
exportName: 'bpmnRenderer',
|
|
132
|
+
formats: ['bpmn'],
|
|
133
|
+
rendererIds: ['bpmn'],
|
|
134
|
+
chunkName: 'file-viewer-drawing',
|
|
135
|
+
includeInPresetAll: false
|
|
136
|
+
},
|
|
127
137
|
{
|
|
128
138
|
id: 'model',
|
|
129
139
|
packageName: '@file-viewer/renderer-3d',
|
|
@@ -234,6 +244,7 @@ const rendererModules = [
|
|
|
234
244
|
formats: [
|
|
235
245
|
'text',
|
|
236
246
|
'txt',
|
|
247
|
+
'lrc',
|
|
237
248
|
'log',
|
|
238
249
|
'code',
|
|
239
250
|
'md',
|
|
@@ -567,10 +578,6 @@ const fileViewerFullPackages = [
|
|
|
567
578
|
'@file-viewer/jquery-full',
|
|
568
579
|
'@file-viewer/svelte-full'
|
|
569
580
|
];
|
|
570
|
-
// Vite dep optimization rewrites import.meta.url into node_modules/.vite/deps
|
|
571
|
-
// and can trigger full-preset dev-server re-optimization reloads. Keep File
|
|
572
|
-
// Viewer packages out of dep optimization while still optimizing their
|
|
573
|
-
// CommonJS/UMD helper dependencies below.
|
|
574
581
|
const fileViewerOptimizationExcludedPackages = [
|
|
575
582
|
'@file-viewer/core',
|
|
576
583
|
'@file-viewer/ppt',
|
|
@@ -679,24 +686,15 @@ export function extractFileViewerRendererHintTokens(source) {
|
|
|
679
686
|
}
|
|
680
687
|
});
|
|
681
688
|
};
|
|
682
|
-
// Explicit JavaScript/TypeScript hints:
|
|
683
|
-
// const fileViewerFormats = ['pdf', 'docx']
|
|
684
|
-
// fileViewerRenderers: ['pdf', 'cad']
|
|
685
689
|
for (const match of source.matchAll(/\bfileViewer(?:Formats?|Renderers?)\b\s*[:=]\s*\[([\s\S]*?)\]/g)) {
|
|
686
690
|
push(collectQuotedTokens(match[1]));
|
|
687
691
|
}
|
|
688
|
-
// HTML / template hints:
|
|
689
|
-
// <div data-file-viewer-formats="pdf,docx"></div>
|
|
690
|
-
// <input accept=".pdf,.docx,application/vnd.ms-excel">
|
|
691
692
|
for (const match of source.matchAll(/\bdata-file-viewer-(?:formats?|renderers?)\s*=\s*["']([^"']+)["']/g)) {
|
|
692
693
|
push(collectDelimitedTokens(match[1]));
|
|
693
694
|
}
|
|
694
695
|
for (const match of source.matchAll(/\baccept\s*=\s*["']([^"']+)["']/g)) {
|
|
695
696
|
push(collectDelimitedTokens(match[1]));
|
|
696
697
|
}
|
|
697
|
-
// Comment hints are useful in non-framework projects where the upload UI is
|
|
698
|
-
// assembled dynamically:
|
|
699
|
-
// // file-viewer-formats: pdf,docx,dwg
|
|
700
698
|
for (const match of source.matchAll(/file-viewer-(?:formats?|renderers?)\s*:\s*([^\n\r<]+)/g)) {
|
|
701
699
|
push(collectDelimitedTokens(match[1]));
|
|
702
700
|
}
|
|
@@ -823,7 +821,7 @@ function renderVirtualModule(selection, formats, autoPresetIds = [], runtimeAsse
|
|
|
823
821
|
? `import { ${presetModule.exportName} as presetRenderers } from '${presetModule.packageName}';`
|
|
824
822
|
: null;
|
|
825
823
|
const autoPresetImports = autoPresetModules.map((preset, index) => `import { ${preset.exportName} as autoPresetRenderers${index} } from '${preset.packageName}';`);
|
|
826
|
-
const rendererImports = selection.descriptors.map((descriptor, index) => `import { ${descriptor.exportName} as renderer${index} } from '${descriptor.packageName}';`);
|
|
824
|
+
const rendererImports = selection.descriptors.map((descriptor, index) => `import { ${descriptor.exportName} as renderer${index} } from '${descriptor.importPath ?? descriptor.packageName}';`);
|
|
827
825
|
const rendererNames = [
|
|
828
826
|
...(presetModule ? ['presetRenderers'] : []),
|
|
829
827
|
...autoPresetModules.map((_preset, index) => `autoPresetRenderers${index}`),
|
|
@@ -925,7 +923,6 @@ function resolveProjectViteMajor(projectRoot) {
|
|
|
925
923
|
return major;
|
|
926
924
|
}
|
|
927
925
|
catch {
|
|
928
|
-
// Try the plugin's own Vite installation when the project does not expose one.
|
|
929
926
|
}
|
|
930
927
|
}
|
|
931
928
|
return 7;
|
|
@@ -955,10 +952,16 @@ function getNodeModulePackageName(id) {
|
|
|
955
952
|
: parts[0];
|
|
956
953
|
}
|
|
957
954
|
function getStableInteropChunkName(id) {
|
|
955
|
+
if (id.startsWith('\0') && /(?:^|\/)commonjsHelpers\.js$/.test(id.slice(1))) {
|
|
956
|
+
return 'vendor-commonjs';
|
|
957
|
+
}
|
|
958
958
|
const packageName = getNodeModulePackageName(id);
|
|
959
959
|
if (!packageName) {
|
|
960
960
|
return undefined;
|
|
961
961
|
}
|
|
962
|
+
if (packageName === 'pako') {
|
|
963
|
+
return 'vendor-commonjs';
|
|
964
|
+
}
|
|
962
965
|
if (packageName === 'codemirror' ||
|
|
963
966
|
packageName === '@replit/codemirror-vim' ||
|
|
964
967
|
packageName.startsWith('@codemirror/') ||
|
|
@@ -979,6 +982,11 @@ function createStableInteropManualChunks(manualChunks) {
|
|
|
979
982
|
function createRolldownCodeSplittingGroups(selection, autoPresetIds, options) {
|
|
980
983
|
const groups = [];
|
|
981
984
|
if (options.stabilizeInteropChunks !== false) {
|
|
985
|
+
groups.push({
|
|
986
|
+
name: 'vendor-commonjs',
|
|
987
|
+
test: (id) => getStableInteropChunkName(id) === 'vendor-commonjs',
|
|
988
|
+
priority: -10
|
|
989
|
+
});
|
|
982
990
|
groups.push({
|
|
983
991
|
name: 'vendor-codemirror',
|
|
984
992
|
test: (id) => getStableInteropChunkName(id) === 'vendor-codemirror',
|
|
@@ -1129,7 +1137,6 @@ function collectWorkspacePackageJsons(root) {
|
|
|
1129
1137
|
}
|
|
1130
1138
|
}
|
|
1131
1139
|
catch {
|
|
1132
|
-
// Ignore malformed package.json files in unrelated workspace folders.
|
|
1133
1140
|
}
|
|
1134
1141
|
}
|
|
1135
1142
|
for (const entry of readdirSync(directory)) {
|
|
@@ -1327,7 +1334,6 @@ function resolvePackageEntry(packageName, anchorPackages = []) {
|
|
|
1327
1334
|
return requireFn.resolve(packageName);
|
|
1328
1335
|
}
|
|
1329
1336
|
catch {
|
|
1330
|
-
// Continue probing alternate anchors.
|
|
1331
1337
|
}
|
|
1332
1338
|
}
|
|
1333
1339
|
return null;
|
|
@@ -1345,14 +1351,12 @@ function resolvePackageEntry(packageName, anchorPackages = []) {
|
|
|
1345
1351
|
}
|
|
1346
1352
|
}
|
|
1347
1353
|
catch {
|
|
1348
|
-
// Fall back to Node resolution below.
|
|
1349
1354
|
}
|
|
1350
1355
|
for (const requireFn of requireFns) {
|
|
1351
1356
|
try {
|
|
1352
1357
|
return requireFn.resolve(packageName);
|
|
1353
1358
|
}
|
|
1354
1359
|
catch {
|
|
1355
|
-
// Continue probing alternate anchors.
|
|
1356
1360
|
}
|
|
1357
1361
|
}
|
|
1358
1362
|
return null;
|
|
@@ -1575,9 +1579,6 @@ async function copyKnownRendererAssets(targetRoot, rendererIds) {
|
|
|
1575
1579
|
'@file-viewer/renderer-pdf'
|
|
1576
1580
|
]);
|
|
1577
1581
|
const pdfCjkFontTarget = join(targetRoot, 'vendor/pdf/fonts');
|
|
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
1582
|
const hasStandardPdfCjkFont = hasPdfCjkFontAssets(standardPdfCjkFontRoot, 'noto-sans-sc.css', 'OFL-1.1.txt');
|
|
1582
1583
|
const hasStagedPdfCjkFont = hasPdfCjkFontAssets(stagedPdfCjkFontRoot, 'wght.css', 'LICENSE');
|
|
1583
1584
|
const hasDependencyPdfCjkFont = hasPdfCjkFontAssets(dependencyPdfCjkFontRoot, 'wght.css', 'LICENSE');
|
|
@@ -1643,6 +1644,9 @@ async function copyKnownRendererAssets(targetRoot, rendererIds) {
|
|
|
1643
1644
|
sourceVersion: cadRuntimeVersion || undefined
|
|
1644
1645
|
}
|
|
1645
1646
|
: undefined);
|
|
1647
|
+
for (const [id, filename] of [['cad-license', 'LICENSE'], ['cad-notice', 'NOTICE']]) {
|
|
1648
|
+
await push('cad', id, join(targetRoot, 'wasm/cad', cadRuntimeVersion || '', filename), () => copyFileIfPresent(cadRoot ? join(cadRoot, filename) : null, join(targetRoot, 'wasm/cad', cadRuntimeVersion || '', filename)), undefined, cadRoot ? { sourcePackage: '@flyfish-dev/cad-viewer', sourceVersion: cadRuntimeVersion || undefined } : undefined);
|
|
1649
|
+
}
|
|
1646
1650
|
const modelDependencyAnchors = [
|
|
1647
1651
|
'@file-viewer/renderer-3d',
|
|
1648
1652
|
'@file-viewer/geometry-engine'
|
|
@@ -1699,6 +1703,10 @@ async function copyKnownRendererAssets(targetRoot, rendererIds) {
|
|
|
1699
1703
|
}
|
|
1700
1704
|
const sqlJsRoot = resolvePackageRoot('sql.js', ['@file-viewer/renderer-data']);
|
|
1701
1705
|
const designRendererRoot = resolvePackageRoot('@file-viewer/renderer-design');
|
|
1706
|
+
const designRendererIds = rendererModules.find(descriptor => descriptor.packageName === '@file-viewer/renderer-design')?.rendererIds || [];
|
|
1707
|
+
for (const rendererId of designRendererIds) {
|
|
1708
|
+
await push(rendererId, `${rendererId}-third-party-notices`, join(targetRoot, 'vendor/design/THIRD_PARTY_NOTICES.md'), () => copyFileIfPresent(designRendererRoot ? join(designRendererRoot, 'THIRD_PARTY_NOTICES.md') : null, join(targetRoot, 'vendor/design/THIRD_PARTY_NOTICES.md')), undefined, undefined, true);
|
|
1709
|
+
}
|
|
1702
1710
|
const introspectWasmRoot = resolvePackageRoot('@paged-media/introspect-wasm', [
|
|
1703
1711
|
'@file-viewer/renderer-design'
|
|
1704
1712
|
]);
|
|
@@ -1764,14 +1772,23 @@ const independentlyOwnedAssetRendererIds = new Map([
|
|
|
1764
1772
|
['office-wordperfect', '@file-viewer/assets-wordperfect'],
|
|
1765
1773
|
['data-asset', '@file-viewer/assets-data']
|
|
1766
1774
|
]);
|
|
1767
|
-
function resolveInstalledCapabilityAssetSources(installedAssetPackages, anchorPackages) {
|
|
1775
|
+
function resolveInstalledCapabilityAssetSources(installedAssetPackages, anchorPackages, ownerPackageRoot) {
|
|
1768
1776
|
return installedAssetPackages.map((packageName) => {
|
|
1769
1777
|
if (packageName === 'file-viewer-copy-assets') {
|
|
1770
1778
|
throw new Error('[file-viewer:vite-plugin] The v2 aggregate asset carrier is forbidden in a v3 capability plan.');
|
|
1771
1779
|
}
|
|
1772
|
-
const
|
|
1780
|
+
const ownedPackageJson = ownerPackageRoot
|
|
1781
|
+
? tryResolvePackageJson(packageName, createRequire(join(ownerPackageRoot, 'package.json')))
|
|
1782
|
+
: null;
|
|
1783
|
+
const packageRoot = ownerPackageRoot
|
|
1784
|
+
? (ownedPackageJson ? dirname(ownedPackageJson) : null)
|
|
1785
|
+
: resolvePackageRoot(packageName, anchorPackages);
|
|
1773
1786
|
if (!packageRoot)
|
|
1774
1787
|
throw new Error(`[file-viewer:vite-plugin] Could not resolve installed asset owner ${packageName}.`);
|
|
1788
|
+
const packageJson = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'));
|
|
1789
|
+
if (packageJson.name !== packageName) {
|
|
1790
|
+
throw new Error(`[file-viewer:vite-plugin] Asset owner identity differs from ${packageName}.`);
|
|
1791
|
+
}
|
|
1775
1792
|
const packageVersion = readPackageVersion(packageRoot);
|
|
1776
1793
|
if (!packageVersion)
|
|
1777
1794
|
throw new Error(`[file-viewer:vite-plugin] Could not read ${packageName} version.`);
|
|
@@ -1939,8 +1956,6 @@ function resolveBundledFullAssetSource(installedFullPackages) {
|
|
|
1939
1956
|
};
|
|
1940
1957
|
}
|
|
1941
1958
|
}
|
|
1942
|
-
// Source workspaces may not have staged file-viewer-copy-assets/viewer yet.
|
|
1943
|
-
// @file-viewer/web keeps the same tracked payload for local development.
|
|
1944
1959
|
const webPackageRoot = resolvePackageRoot('@file-viewer/web', installedFullPackages);
|
|
1945
1960
|
const webPayloadRoot = webPackageRoot ? join(webPackageRoot, 'viewer') : null;
|
|
1946
1961
|
const sourceVersion = readPackageVersion(webPackageRoot);
|
|
@@ -1987,6 +2002,39 @@ async function copyBundledFullRendererAssets(targetRoot, rendererIds, installedF
|
|
|
1987
2002
|
if (manifest.schemaVersion !== 1 || !Array.isArray(manifest.rendererAssetManifests)) {
|
|
1988
2003
|
throw new Error(`[file-viewer:vite-plugin] Unsupported full asset manifest in ${sourceManifestPath}.`);
|
|
1989
2004
|
}
|
|
2005
|
+
const packageJson = JSON.parse(readFileSync(join(source.packageRoot, 'package.json'), 'utf8'));
|
|
2006
|
+
const dependencies = packageJson.dependencies || {};
|
|
2007
|
+
const splitPackageNames = Object.keys(dependencies)
|
|
2008
|
+
.filter(name => name.startsWith('@file-viewer/assets-'));
|
|
2009
|
+
for (const name of splitPackageNames) {
|
|
2010
|
+
const pin = dependencies[name].replace(/^workspace:/, '');
|
|
2011
|
+
if (pin !== source.sourceVersion) {
|
|
2012
|
+
throw new Error(`[file-viewer:vite-plugin] ${source.packageName} must pin ${name} to ${source.sourceVersion}.`);
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
const splitSources = resolveInstalledCapabilityAssetSources(splitPackageNames, [], source.packageRoot);
|
|
2016
|
+
const assetOwners = new Map();
|
|
2017
|
+
const descriptorKeys = ['rendererId', 'kind', 'target', 'required', 'defaultPath'];
|
|
2018
|
+
for (const owner of splitSources) {
|
|
2019
|
+
if (owner.packageVersion !== source.sourceVersion) {
|
|
2020
|
+
throw new Error(`[file-viewer:vite-plugin] ${source.packageName} cannot use ${owner.packageName}@${owner.packageVersion}; expected ${source.sourceVersion}.`);
|
|
2021
|
+
}
|
|
2022
|
+
for (const group of owner.manifest.rendererAssetManifests || []) {
|
|
2023
|
+
const bundledGroup = manifest.rendererAssetManifests.find(entry => entry.rendererId === group.rendererId);
|
|
2024
|
+
for (const asset of group.assets) {
|
|
2025
|
+
if (asset.target !== 'public' || !asset.defaultPath)
|
|
2026
|
+
continue;
|
|
2027
|
+
const bundledAsset = bundledGroup?.assets.find(entry => entry.id === asset.id);
|
|
2028
|
+
if (!bundledAsset || descriptorKeys.some(key => bundledAsset[key] !== asset[key])) {
|
|
2029
|
+
throw new Error(`[file-viewer:vite-plugin] Split asset ${owner.packageName}:${asset.id} differs from the declared Full manifest.`);
|
|
2030
|
+
}
|
|
2031
|
+
const key = `${asset.rendererId}:${asset.id}`;
|
|
2032
|
+
if (assetOwners.has(key))
|
|
2033
|
+
throw new Error(`[file-viewer:vite-plugin] Multiple split asset owners declare ${key}.`);
|
|
2034
|
+
assetOwners.set(key, owner);
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
1990
2038
|
await mkdir(targetRoot, { recursive: true });
|
|
1991
2039
|
await cp(source.payloadRoot, targetRoot, { recursive: true, force: true });
|
|
1992
2040
|
const results = [];
|
|
@@ -1998,18 +2046,22 @@ async function copyBundledFullRendererAssets(targetRoot, rendererIds, installedF
|
|
|
1998
2046
|
const destination = resolve(targetRoot, ...relativePath.split('/'));
|
|
1999
2047
|
let copied = false;
|
|
2000
2048
|
let reason;
|
|
2049
|
+
const owner = assetOwners.get(`${asset.rendererId}:${asset.id}`);
|
|
2001
2050
|
if (!isPathWithin(targetRoot, destination)) {
|
|
2002
2051
|
reason = 'asset manifest path escapes the copy target';
|
|
2003
2052
|
}
|
|
2004
2053
|
else {
|
|
2005
2054
|
try {
|
|
2055
|
+
if (owner) {
|
|
2056
|
+
await copyAssetPathWithoutConflicts(owner.payloadRoot, targetRoot, relativePath);
|
|
2057
|
+
}
|
|
2006
2058
|
copied = matchesBundledAssetKind(asset.kind, await stat(destination));
|
|
2007
2059
|
if (!copied) {
|
|
2008
2060
|
reason = `copied path does not match asset kind ${asset.kind}`;
|
|
2009
2061
|
}
|
|
2010
2062
|
}
|
|
2011
|
-
catch {
|
|
2012
|
-
reason = 'bundled full asset not found after copy';
|
|
2063
|
+
catch (error) {
|
|
2064
|
+
reason = owner ? error.message : 'bundled full asset not found after copy';
|
|
2013
2065
|
}
|
|
2014
2066
|
}
|
|
2015
2067
|
results.push({
|
|
@@ -2019,8 +2071,8 @@ async function copyBundledFullRendererAssets(targetRoot, rendererIds, installedF
|
|
|
2019
2071
|
copied,
|
|
2020
2072
|
required: asset.required,
|
|
2021
2073
|
reason,
|
|
2022
|
-
sourcePackage: source.packageName,
|
|
2023
|
-
sourceVersion: source.sourceVersion
|
|
2074
|
+
sourcePackage: owner?.packageName || source.packageName,
|
|
2075
|
+
sourceVersion: owner?.packageVersion || source.sourceVersion
|
|
2024
2076
|
});
|
|
2025
2077
|
}
|
|
2026
2078
|
await writeFile(join(targetRoot, 'flyfish-viewer-assets.json'), `${JSON.stringify({
|
|
@@ -2050,7 +2102,6 @@ async function copyRendererAssets(target, rendererIds) {
|
|
|
2050
2102
|
id: 'missing-independent-asset-owner',
|
|
2051
2103
|
to: target.targetRoot,
|
|
2052
2104
|
copied: false,
|
|
2053
|
-
// Specialist offline payloads stay opt-in; warn instead of failing the build.
|
|
2054
2105
|
required: false,
|
|
2055
2106
|
reason: `install ${requiredOwner} for this capability`
|
|
2056
2107
|
});
|
|
@@ -2109,8 +2160,6 @@ function resolveInstalledFullPackages(projectRoot) {
|
|
|
2109
2160
|
return fileViewerFullPackages.filter(packageName => declaredPackages.has(packageName) &&
|
|
2110
2161
|
Boolean(tryResolvePackageJson(packageName, projectPackageRequire)));
|
|
2111
2162
|
}
|
|
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
2163
|
const directory = dirname(packageJsonPath);
|
|
2115
2164
|
const parent = dirname(directory);
|
|
2116
2165
|
packageJsonPath = parent === directory ? null : findNearestProjectPackageJson(parent);
|
|
@@ -2182,10 +2231,6 @@ function resolveOutputRoot(value, fallback, projectRoot) {
|
|
|
2182
2231
|
const output = value || fallback;
|
|
2183
2232
|
return isAbsolute(output) ? resolve(output) : resolve(projectRoot, output);
|
|
2184
2233
|
}
|
|
2185
|
-
/**
|
|
2186
|
-
* Resolves the exact directory used by copyAssets without running a Vite build.
|
|
2187
|
-
* This is exported so integrations can validate their deployment contract.
|
|
2188
|
-
*/
|
|
2189
2234
|
export function resolveFileViewerCopyAssetsTarget(mode, value = true, config = {}) {
|
|
2190
2235
|
const projectRoot = resolve(config.projectRoot || process.cwd());
|
|
2191
2236
|
const options = copyOptions(value);
|
|
@@ -2245,10 +2290,6 @@ function resolveViteFullAssetBase(base, baseDir) {
|
|
|
2245
2290
|
function resolveDevAssetRequestPath(targetRoot, baseDir, requestPathname, viteBasePath) {
|
|
2246
2291
|
let requestRelativePath;
|
|
2247
2292
|
try {
|
|
2248
|
-
// Depending on the Vite major and middleware ordering, configureServer can
|
|
2249
|
-
// observe either the original base-prefixed URL or the pathname after
|
|
2250
|
-
// Vite's base middleware has stripped it. Accept both shapes, then keep the
|
|
2251
|
-
// strict viewer-asset allowlist and target-root boundary checks below.
|
|
2252
2293
|
const encodedRelativePath = viteBasePath === '/' || requestPathname.startsWith(viteBasePath)
|
|
2253
2294
|
? requestPathname.slice(viteBasePath === '/' ? 1 : viteBasePath.length)
|
|
2254
2295
|
: requestPathname.replace(/^\/+/, '');
|
|
@@ -2425,7 +2466,9 @@ export function fileViewerRenderers(options = {}) {
|
|
|
2425
2466
|
build: {
|
|
2426
2467
|
rollupOptions: {
|
|
2427
2468
|
output: {
|
|
2428
|
-
manualChunks:
|
|
2469
|
+
manualChunks: options.stabilizeInteropChunks === false
|
|
2470
|
+
? createManualChunks(selection, autoPresetIds)
|
|
2471
|
+
: createStableInteropManualChunks(createManualChunks(selection, autoPresetIds))
|
|
2429
2472
|
}
|
|
2430
2473
|
}
|
|
2431
2474
|
}
|
|
@@ -2514,7 +2557,6 @@ export function fileViewerRenderers(options = {}) {
|
|
|
2514
2557
|
}
|
|
2515
2558
|
}
|
|
2516
2559
|
catch {
|
|
2517
|
-
// Let Vite return its normal 404/fallback response.
|
|
2518
2560
|
}
|
|
2519
2561
|
}
|
|
2520
2562
|
next();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@file-viewer/vite-plugin",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.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.",
|
|
@@ -24,8 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"repository": {
|
|
26
26
|
"type": "git",
|
|
27
|
-
"url": "git+https://github.com/flyfish-dev/file-viewer.git"
|
|
28
|
-
"directory": "packages/presets/vite-plugin"
|
|
27
|
+
"url": "git+https://github.com/flyfish-dev/file-viewer.git"
|
|
29
28
|
},
|
|
30
29
|
"homepage": "https://doc.file-viewer.app/guide/on-demand-renderers",
|
|
31
30
|
"bugs": {
|
|
@@ -48,11 +47,12 @@
|
|
|
48
47
|
"./package.json": "./package.json"
|
|
49
48
|
},
|
|
50
49
|
"files": [
|
|
51
|
-
"dist",
|
|
52
50
|
"client.d.ts",
|
|
53
|
-
"
|
|
51
|
+
"dist/index.d.ts",
|
|
52
|
+
"dist/index.js",
|
|
53
|
+
"LICENSE",
|
|
54
54
|
"README.en.md",
|
|
55
|
-
"
|
|
55
|
+
"README.md"
|
|
56
56
|
],
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"vite": ">=5 <9"
|
|
@@ -62,17 +62,11 @@
|
|
|
62
62
|
"optional": false
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
|
-
"devDependencies": {
|
|
66
|
-
"@types/node": "^26.5.1",
|
|
67
|
-
"typescript": "^6.0.3",
|
|
68
|
-
"vite": "^8.2.2"
|
|
69
|
-
},
|
|
70
65
|
"license": "Apache-2.0",
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
"verify:github-257-browser": "npm exec --yes --package playwright@1.61.1 -- node scripts/verify-github-257-browser.mjs"
|
|
66
|
+
"fileViewer": {
|
|
67
|
+
"distribution": {
|
|
68
|
+
"schemaVersion": 1,
|
|
69
|
+
"mode": "runtime-only"
|
|
70
|
+
}
|
|
77
71
|
}
|
|
78
|
-
}
|
|
72
|
+
}
|