npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@langhe/pdf-sdk

v0.1.2

Published

朗阅 PDF SDK 提供 Web 端 PDF 在线预览、批注、保存、导出和授权能力,可通过 npm 包接入到业务系统中。

Readme

@langhe/pdf-sdk

朗阅 PDF SDK 提供 Web 端 PDF 在线预览、批注、保存、导出和授权能力,可通过 npm 包接入到业务系统中。

联系方式:微信号 13512039065

一、核心能力

| 能力 | 说明 | | --- | --- | | PDF 预览 | 支持 PDF 打开、分页渲染、滚动、缩放、旋转、页码跳转 | | 大文件预览 | 支持大文档按需渲染,减少长期浏览时的内存占用 | | 缩略图 | 支持缩略图列表、当前页高亮、点击跳页 | | 搜索 | 支持关键词搜索、上一条 / 下一条、命中高亮 | | 批注 | 支持高亮、下划线、删除线、文本、矩形、圆形、箭头、手写、折线、多边形、印章、签名 | | 批注保存 | 支持读取、保存、回显批注数据 | | 批注导出 | 支持导出批注 JSON | | PDF 导出 | 支持导出带批注的 PDF 文件 | | 框架接入 | 支持原生 JavaScript、React、Vue3、Vue2 | | 授权 | 支持本地离线 licenseKey 校验,生产环境授权交付 |

二、安装

npm install @langhe/pdf-sdk @langhe/pdf-viewer

如果项目使用 pnpm:

pnpm add @langhe/pdf-sdk @langhe/pdf-viewer

入口说明:

| 包 | 说明 | | --- | --- | | @langhe/pdf-sdk | SDK 主入口 | | @langhe/pdf-viewer | Viewer UI 和样式 | | @langhe/pdf-react | React 组件封装 | | @langhe/pdf-vue3 | Vue3 组件封装 | | @langhe/pdf-vue2 | Vue2 组件封装 |

三、开发环境 licenseKey

下面的 licenseKey 仅用于本地开发和接入验证,支持 localhost127.0.0.1[::1],有效期至 2027-12-31 23:59:59 UTC

export const LANGYUE_PDF_DEV_LICENSE_KEY =
  'eyJ2ZXJzaW9uIjoxLCJsaWNlbnNlSWQiOiJMWS1QREYtMjAyNjA3MDQtSk5MSkhXIiwiY2xpZW50SWQiOiJsYW5neXVlLWRldiIsImNsaWVudE5hbWUiOiJMYW5neXVlIFBERiBTREsgRGV2ZWxvcG1lbnQiLCJwcm9kdWN0IjoibGFuZ3l1ZS1wZGYtc2RrIiwiZG9tYWlucyI6WyJsb2NhbGhvc3QiLCIxMjcuMC4wLjEiLCJbOjoxXSJdLCJpc3N1ZWRBdCI6IjIwMjYtMDctMDRUMTM6MzM6MDIuNzA5WiIsImV4cGlyZXNBdCI6IjIwMjctMTItMzFUMjM6NTk6NTkuMDAwWiIsIm1ldGFkYXRhIjp7ImNvbnRyYWN0Tm8iOiJERVYtTlBNLTIwMjYifX0.pbTSv0zG1mlv0gTuLM1-rfN6H7rJhpynXUEM89AiowlvmeDMltuN9d-kLLRo6uVzQEVfy0zRPHwmstHzSgEH9w'

生产环境需要正式授权,请联系微信号 13512039065

四、最小接入

页面准备容器:

<div id="pdf-viewer"></div>

容器必须有明确宽高:

html,
body,
#pdf-viewer {
  width: 100%;
  height: 100%;
  margin: 0;
}

初始化 SDK:

import { createLangyuePDF } from '@langhe/pdf-sdk'
import '@langhe/pdf-viewer/style.css'

const viewer = await createLangyuePDF({
  container: '#pdf-viewer',
  document: {
    src: '/files/example.pdf',
    documentId: 'doc-001',
    fileName: 'example.pdf'
  },
  user: {
    id: 'u-001',
    name: '张三'
  },
  licenseKey: LANGYUE_PDF_DEV_LICENSE_KEY,
  license: {
    environment: 'development',
    hostname: window.location.hostname,
    failureStrategy: 'block'
  }
})

五、打开 PDF

打开 URL PDF:

await viewer.open({
  src: '/api/files/doc-001.pdf',
  documentId: 'doc-001',
  fileName: '合同.pdf'
})

打开二进制 PDF:

const response = await fetch('/api/files/doc-001')
const data = await response.arrayBuffer()

await viewer.open({
  data,
  documentId: 'doc-001',
  fileName: '合同.pdf'
})

六、批注数据接入

URL 接口模式

const viewer = await createLangyuePDF({
  container: '#pdf-viewer',
  document: {
    src: '/files/doc-001.pdf',
    documentId: 'doc-001'
  },
  user: {
    id: 'u-001',
    name: '张三'
  },
  licenseKey,
  license: {
    environment: 'production',
    failureStrategy: 'block'
  },
  dataSource: {
    loadUrl: '/api/documents/doc-001/annotations',
    saveUrl: '/api/documents/doc-001/annotations',
    headers: async () => ({
      Authorization: `Bearer ${await getAccessToken()}`
    })
  }
})

推荐加载接口返回:

{
  "schemaVersion": "2.0",
  "annotations": []
}

回调模式

const viewer = await createLangyuePDF({
  container: '#pdf-viewer',
  document: {
    src: '/files/doc-001.pdf',
    documentId: 'doc-001'
  },
  dataSource: {
    load: async context => {
      return annotationService.load(context.document?.documentId)
    },
    save: async (annotations, context) => {
      await annotationService.save(context.document?.documentId, {
        annotations,
        reason: context.reason
      })
    }
  }
})

七、常用方法

viewer.goToPage(3)
viewer.zoomIn()
viewer.zoomOut()

const annotations = viewer.getAnnotations()
await viewer.saveAnnotations()

await viewer.exportPdf({
  fileName: '合同-带批注.pdf',
  download: true
})

viewer.destroy()

| 方法 | 说明 | | --- | --- | | open(input) | 打开 PDF | | close() | 关闭当前 PDF | | destroy() | 销毁 SDK 实例 | | goToPage(pageNumber) | 跳转页码 | | zoomIn() / zoomOut() | 放大 / 缩小 | | search(query) | 搜索文本 | | getAnnotations() | 获取批注 | | setAnnotations(annotations) | 设置批注 | | saveAnnotations() | 保存批注 | | exportAnnotations() | 导出批注 JSON | | exportPdf() | 导出带批注 PDF | | getLicenseStatus() | 获取授权状态 |

八、事件监听

viewer.on('annotations:dirty', event => {
  saveButton.disabled = !event.dirty
})

viewer.on('annotations:save', event => {
  console.log('批注已保存', event.annotations.length)
})

viewer.on('error', event => {
  console.error(event.error.code, event.error.message)
})

viewer.on('page:change', event => {
  console.log(`${event.pageNumber} / ${event.pageCount}`)
})

九、生产环境授权

生产环境必须传入正式 licenseKey

const viewer = await createLangyuePDF({
  container: '#pdf-viewer',
  document: {
    src: '/api/files/doc-001.pdf',
    documentId: 'doc-001'
  },
  licenseKey: window.APP_CONFIG.langyuePdfLicenseKey,
  license: {
    environment: 'production',
    hostname: window.location.hostname,
    failureStrategy: 'block'
  }
})

授权校验在浏览器本地离线完成,不需要联网。

| 场景 | 行为 | | --- | --- | | 开发环境未传 licenseKey | 默认放行 | | 生产环境未传 licenseKey | 阻止初始化 | | licenseKey 无效 | 授权失败 | | 域名未授权 | 授权失败 | | 授权过期 | 授权失败 |

读取授权状态:

const status = viewer.getLicenseStatus()
console.log(status.valid, status.code, status.message)

十、PDFium 资源部署

如需把资源放到 public 目录或 CDN,需要准备:

pdfium.wasm
PdfiumPreviewReaderWorker.js
PdfiumStreamingWorker.js

配置资源路径:

await createLangyuePDF({
  container: '#pdf-viewer',
  document: { src: '/files/doc-001.pdf' },
  resources: {
    pdfium: {
      baseUrl: '/assets/pdfium'
    }
  }
})

生产环境检查:

| 检查项 | 要求 | | --- | --- | | wasm MIME | application/wasm | | worker MIME | JavaScript 文件可以作为 module worker 加载 | | 跨域 | CDN 场景需要配置 CORS | | CSP | 如业务系统配置 CSP,需要允许 worker 和 wasm 加载来源 |

十一、React 接入

npm install @langhe/pdf-sdk @langhe/pdf-viewer @langhe/pdf-react react
import { useMemo } from 'react'
import { LangyuePDFReact } from '@langhe/pdf-react'
import '@langhe/pdf-viewer/style.css'

export function ContractViewer() {
  const options = useMemo(() => ({
    document: {
      src: '/files/doc-001.pdf',
      documentId: 'doc-001'
    },
    user: {
      id: 'u-001',
      name: '张三'
    },
    licenseKey: LANGYUE_PDF_DEV_LICENSE_KEY,
    license: {
      environment: 'development'
    }
  }), [])

  return (
    <LangyuePDFReact
      className="pdf-host"
      options={options}
      onReady={viewer => {
        viewer.setCommentsSidebarVisible(true)
      }}
    />
  )
}

十二、Vue3 接入

npm install @langhe/pdf-sdk @langhe/pdf-viewer @langhe/pdf-vue3 vue
<script setup lang="ts">
import { LangyuePDFVue3 } from '@langhe/pdf-vue3'
import '@langhe/pdf-viewer/style.css'

const options = {
  document: {
    src: '/files/doc-001.pdf',
    documentId: 'doc-001'
  },
  user: {
    id: 'u-001',
    name: '张三'
  },
  licenseKey: LANGYUE_PDF_DEV_LICENSE_KEY,
  license: {
    environment: 'development'
  }
}
</script>

<template>
  <LangyuePDFVue3 class="pdf-host" :options="options" />
</template>

十三、Vue2 接入

npm install @langhe/pdf-sdk @langhe/pdf-viewer @langhe/pdf-vue2 vue
<template>
  <LangyuePDFVue2
    ref="viewer"
    class="pdf-host"
    :options="options"
    @ready="handleReady"
  />
</template>

<script>
import { LangyuePDFVue2 } from '@langhe/pdf-vue2'
import '@langhe/pdf-viewer/style.css'

export default {
  components: { LangyuePDFVue2 },
  data() {
    return {
      options: {
        document: {
          src: '/files/doc-001.pdf',
          documentId: 'doc-001'
        },
        user: {
          id: 'u-001',
          name: '张三'
        },
        licenseKey: LANGYUE_PDF_DEV_LICENSE_KEY,
        license: {
          environment: 'development'
        }
      }
    }
  },
  methods: {
    handleReady(viewer) {
      viewer.setCommentsSidebarVisible(true)
    },
    save() {
      return this.$refs.viewer.saveAnnotations()
    }
  }
}
</script>

十四、上线检查

| 检查项 | 说明 | | --- | --- | | npm 包 | 已安装 @langhe/pdf-sdk@langhe/pdf-viewer | | 样式 | 已引入 @langhe/pdf-viewer/style.css | | 容器 | viewer 容器有明确宽高 | | PDF 地址 | PDF URL 可访问,跨域和鉴权已处理 | | documentId | 每份业务文档都有稳定唯一 ID | | 用户信息 | 已传入当前登录用户 ID 和名称 | | 批注接口 | 已完成批注读取和保存接口 | | 授权 | 生产环境已配置正式 licenseKey | | PDFium 资源 | wasm 和 worker 在生产环境不 404 | | 页面销毁 | 路由切换或组件卸载时调用 viewer.destroy() |

十五、联系我们

正式授权、商务合作、接入支持请联系:

微信号:13512039065