npm package: @microclear/file-viewer
Description: Browser document preview toolkit for Vue 3 applications.
Latest version: 0.1.7

# Microclear File Viewer

一个基于 `Vue 3 + TypeScript` 的浏览器端文档预览库，支持：

- PDF (`.pdf`)
- Word (`.docx`)
- Excel (`.xlsx`, `.xls`)
- 图片 (`png/jpg/jpeg/webp/gif/bmp/svg`)
- 普通文本 (`txt/md/csv/log/json/xml/yml/yaml`)

## 技术栈

- Vue 3
- Vite 4
- TypeScript 5
- Tailwind CSS 3

## 目录结构

```txt
src/
  core/                  # 无框架核心能力（类型识别/数据加载/统一渲染器）
  vue/                   # Vue 适配层（组件/插件/js-init，复用 core 渲染）
  dom/                   # 无 Vue 依赖的 DOM 适配层（复用 core 渲染）
  index.ts               # 聚合导出
```

## 快速开始

```bash
npm install
npm run dev:modern
```

本地调试可切换构建模式：

- `npm run dev:modern`：以 modern 模式启动
- `npm run dev:legacy`：以 legacy 模式启动

Demo 页面中，`#/prod` 会按当前 `mode` 加载对应 dist 产物（modern 或 legacy）。

## 作为库使用

```ts
import { createApp } from "vue";
import App from "./App.vue";
import { FileViewerPlugin } from "@microclear/file-viewer";
import "@microclear/file-viewer/style.css";

createApp(App).use(FileViewerPlugin).mount("#app");
```

或局部组件引入：

```vue
<script setup lang="ts">
import { DocumentPreview } from "@microclear/file-viewer";

const onLoaded = () => {
  console.log("preview loaded");
};
</script>

<template>
  <DocumentPreview :source="urlOrFile" @loaded="onLoaded" />
</template>
```

按层导入：

```ts
import { detectFileType, loadSource } from "@microclear/file-viewer/core";
import { DocumentPreview, FileViewerPlugin } from "@microclear/file-viewer/vue";
import { createFileViewerDom } from "@microclear/file-viewer/dom";
```

legacy 版本按子路径导入：

```ts
import { DocumentPreview } from "@microclear/file-viewer/legacy";
import { createFileViewerDom } from "@microclear/file-viewer/legacy/dom";
import "@microclear/file-viewer/legacy/style.css";
```

DOM 版本（无 Vue 依赖）：

```ts
import { createFileViewerDom } from "@microclear/file-viewer/dom";

const viewer = await createFileViewerDom({
  el: "#viewer",
  source: "https://example.com/demo.xlsx",
  config: {
    excel: { sheetMode: "tabs", maxRows: 500 }
  }
});

await viewer.update({ source: "https://example.com/demo.pdf" });
viewer.destroy();
```

## API

`DocumentPreview` props:

- `source?: string | File | Blob | ArrayBuffer | Uint8Array`
- `fileName?: string`
- `mimeType?: string`
- `config?: { maxFileSizeMB?: number, pdf?: { scale?: number }, excel?: { maxRows?: number; maxCols?: number; sheetIndex?: number; showSheetTabs?: boolean; sheetMode?: "tabs" | "stack" }, word?: { className?: string } }`

`DocumentPreview` events:

- `loaded`: 每次渲染完成后触发（含首次渲染与后续更新）。

`DocumentPreview` slots:

- `error`: 自定义错误渲染，slot props 为 `{ message: string }`。

说明:

- `Word` 预览当前支持 `docx`。旧版 `doc` 建议在服务端先转换为 `docx` 或 `pdf` 后再预览。
- `Excel` 预览已兼容 `xls`（旧版 BIFF）。`xlsx` 使用 `exceljs`，`xls` 使用 SheetJS（`xlsx`）解析。
- `Excel` 支持基础单元格样式预览（字体、颜色、背景、对齐、边框、缩进、旋转等）。
- `Excel` 多 sheet 支持两种模式：`tabs`（默认，标签切换）与 `stack`（全部纵向展示）。
- 默认最大文件大小限制为 `50MB`，可通过 `config.maxFileSizeMB` 调整。

## JS 初始化方式

```ts
import { createFileViewer } from "@microclear/file-viewer";
import "@microclear/file-viewer/style.css";

const viewer = createFileViewer({
  el: "#viewer",
  source: "https://example.com/demo.xlsx",
  config: {
    excel: {
      maxRows: 1000,
      showSheetTabs: true
    }
  }
});

viewer.update({
  source: "https://example.com/demo.docx"
});

// viewer.destroy();
```

## 打包

```bash
npm run build
```

构建产物分为两套：

- `dist/modern`：modern 版本（默认导出）
- `dist/legacy`：legacy 版本（旧浏览器兼容）

每套产物都包含 `ESM + UMD + d.ts + style.css`。

说明:

- 构建阶段启用 `terser` 并移除注释，`dist` 中不会保留源码注释。
- `build` 会依次执行 `build:modern` 与 `build:legacy`。
- `build:min` 会在双版本构建后执行 `scripts/minify-dist.mjs`，压缩 `dist/modern` 与 `dist/legacy` 的主产物。

## 测试

```bash
# 运行全部测试
npm test

# 运行单个测试文件
npm test -- tests/core/source.spec.ts

# 监听模式
npm run test:watch
```

## 发布到 NPM

```bash
# 1) 登录官方 npm
npm login --registry=https://registry.npmjs.org/

# 2) 执行发布（含 typecheck + test + publish）
npm run release:npm
```

说明:

- 已配置 `prepublishOnly`，发布前会自动执行 `npm run build`。
- 项目 `.npmrc` 使用了镜像源，发布脚本通过 `--registry=https://registry.npmjs.org/` 强制发布到官方 npm。