feat(webfont-sdk): 0.2.0 新增服务端 API 客户端子路径 webfont-sdk/api

- createWebFontApi 工厂封装全部 6 个 REST 接口(fonts/fontMeta/
  config/stats/upload/reportEvent)+ 全套类型,独立子路径导出不进主入口
- leafer demo 删除硬编码 FONTS 数组,改 api.fonts() 实时拉取
  (24 个字体 vs 原硬编码 6 个),初始字体带回退、失败显式报错
- 主站 src/api.ts 重写为 SDK 客户端薄适配层(dogfooding):
  旧类型名保留为别名组件零改动,顺带消灭 FontInfo 重复声明
- /docs 文档页新增 npm 安装、双模式用法、API 客户端示例(中英)
- 主站 package.json 添加 workspace 依赖 webfont-sdk

已发布 npm webfont-sdk@0.2.0,CDN 与 demo 端到端验证通过。
This commit is contained in:
崮生(子虚) 2026-08-15 20:35:17 +08:00
parent b385bc89bc
commit ca1d2fc1e7
10 changed files with 397 additions and 149 deletions

View File

@ -20,7 +20,8 @@
"dependencies": {
"@unhead/vue": "^2.1.17",
"pinyin-pro": "^3.29.1",
"web-streams-polyfill": "^4.3.0"
"web-streams-polyfill": "^4.3.0",
"webfont-sdk": "workspace:*"
},
"devDependencies": {
"@leafer-ui/node": "2.2.9",

View File

@ -54,31 +54,36 @@
<script type="importmap">
{
"imports": {
"webfont-sdk": "https://cdn.jsdelivr.net/npm/webfont-sdk@0.1.0/dist/index.js"
"webfont-sdk": "https://cdn.jsdelivr.net/npm/webfont-sdk@0.2.0/dist/index.js",
"webfont-sdk/api": "https://cdn.jsdelivr.net/npm/webfont-sdk@0.2.0/dist/api.js"
}
}
</script>
<script type="module">
import { WebFontPlugin } from 'https://cdn.jsdelivr.net/npm/leafer-x-webfont@0.1.0/dist/index.js'
import { createWebFontApi } from 'webfont-sdk/api'
const { Leafer, Text, Rect, Ellipse, Image } = LeaferUI
const status = document.getElementById('status')
const FONTS = [
{ name: '令东齐伋复刻体.ttf', label: '令东齐伋复刻体(古籍宋)' },
{ name: '霞鹜文楷.ttf', label: '霞鹜文楷(楷书)' },
{ name: '得意黑.ttf', label: '得意黑(标题黑体)' },
{ name: '演示佛系体.ttf', label: '演示佛系体' },
{ name: '源界明朝.ttf', label: '源界明朝(日式明朝)' },
{ name: '三极泼墨体.ttf', label: '三极泼墨体' },
]
const leafer = new Leafer({ view: 'canvas-host', fill: '#fafaf9' })
/** 字体子集化服务:本地开发连本地后端,任何部署环境(主站/GitHub Pages一律走线上服务后端 CORS 全开) */
const isDev = location.hostname === 'localhost' || location.hostname === '127.0.0.1'
const fontApi = isDev ? 'http://localhost:8087' : 'https://webfont.shenzilong.cn'
const webfont = new WebFontPlugin(leafer, { debug: true, baseUrl: fontApi })
/* ---------- 字体列表API 实时拉取(不再硬编码) ---------- */
const api = createWebFontApi({ baseUrl: fontApi })
let fonts
try {
fonts = (await api.fonts()).filter((f) => !f.temporary)
} catch (e) {
status.textContent = `字体列表拉取失败:${e.message}`
throw e
}
/** 初始字体选择:优先演示字体,服务端没有则回退列表第一个 */
const pick = (prefer) => fonts.find((f) => f.name === prefer)?.name ?? fonts[0]?.name ?? ''
/* ---------- 海报场景 ---------- */
const bg = new Rect({ x: 0, y: 0, width: 900, height: 480, fill: { type: 'linear', from: { x: 0, y: 0 }, to: { x: 1, y: 1 }, stops: [{ offset: 0, color: '#fef3c7' }, { offset: 1, color: '#fde68a' }] } })
const deco = new Ellipse({ x: 660, y: -80, width: 360, height: 360, fill: 'rgba(255,255,255,0.35)' })
@ -87,7 +92,7 @@
const title = new Text({
x: 80, y: 150,
text: '静心茶舍',
fontFamily: '令东齐伋复刻体.ttf',
fontFamily: pick('令东齐伋复刻体.ttf'),
fontSize: 96,
fill: '#1c1917',
letterSpacing: 8,
@ -95,7 +100,7 @@
const subtitle = new Text({
x: 84, y: 290,
text: '以茶为媒 · 观自在',
fontFamily: '霞鹜文楷.ttf',
fontFamily: pick('霞鹜文楷.ttf'),
fontSize: 28,
fill: '#57534e',
letterSpacing: 4,
@ -108,12 +113,15 @@
/* ---------- 控件交互 ---------- */
const fontSelect = document.getElementById('font-select')
for (const f of FONTS) {
for (const f of fonts) {
const opt = document.createElement('option')
opt.value = f.name
opt.textContent = f.label
/** label 用去扩展名的文件名;更精细的展示名是 font-config displayName 的职责 */
opt.textContent = f.name.replace(/\.(ttf|otf|woff2?)$/i, '')
fontSelect.appendChild(opt)
}
/** 当前标题字体在列表中高亮选中 */
if (fonts.some((f) => f.name === title.fontFamily)) fontSelect.value = title.fontFamily
fontSelect.onchange = () => {
title.fontFamily = fontSelect.value
status.textContent = '字体切换中…'

View File

@ -9,6 +9,7 @@
- **增量加载**`IncrementalEngine` 按字符集去重,只请求新增字符,同类文字滚动输入不重复请求
- **双模式**CSS 模式(`WebFont`,面向 DOM+ FontFace 模式(`WebFontCanvas`,面向 Canvas
- **API 客户端**`webfont-sdk/api` 子路径封装字体列表 / 元数据 / 上传 / 统计等 REST 接口
- **失败记忆**:裁剪失败的字符自动记录,不反复重试浪费请求
- **unicodeRange 注册**Canvas 模式用 unicodeRange 精确注册字符片段,天然无闪烁
- **并发控制**:可配置请求并发池,避免瞬时打爆服务端
@ -63,6 +64,31 @@ await WebFontCanvas.ready()
</script>
```
## 服务端 REST API 客户端
增量加载之外SDK 还封装了子集化服务的公开 REST 接口(字体列表 / 元数据 / 上传 / 统计),
独立子路径导出,不进主入口:
```ts
import { createWebFontApi } from 'webfont-sdk/api'
const api = createWebFontApi({ baseUrl: 'https://webfont.shenzilong.cn' })
/** 字体列表(文件名 + 是否临时字体) */
const fonts = await api.fonts()
/** 字体元数据codepoint 区间 / 各字符集覆盖率 / name 表信息 / 站长配置 */
const meta = await api.fontMeta('霞鹜文楷.ttf')
/** 上传临时字体默认到期自动清理admin 模式需 apiKey */
const result = await api.upload({ data: file, filename: '我的字体.ttf' })
if (!result.success) console.error(result.error)
/** 服务配置 / 运行统计 */
const config = await api.config()
const stats = await api.stats()
```
## 文档
完整 API 文档:<https://webfont.shenzilong.cn/docs>

View File

@ -1,7 +1,7 @@
{
"name": "webfont-sdk",
"version": "0.1.0",
"description": "Web 字体按需加载 SDK —— 只加载实际用到的字符,增量去重、无闪烁,支持 DOM(CSS) 与 Canvas(FontFace) 两种模式",
"version": "0.2.0",
"description": "Web 字体按需加载 SDK —— 只加载实际用到的字符,增量去重、无闪烁,支持 DOM(CSS) 与 Canvas(FontFace) 两种模式,内置服务端 REST API 客户端",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@ -11,6 +11,11 @@
"types": "./dist/index.d.ts",
"development": "./src/index.ts",
"import": "./dist/index.js"
},
"./api": {
"types": "./dist/api.d.ts",
"development": "./src/api.ts",
"import": "./dist/api.js"
}
},
"files": [

View File

@ -0,0 +1,228 @@
/**
* REST API webfont
*
* index.ts
* import { createWebFontApi } from 'webfont-sdk/api'
*
* routes
* - GET /api/fonts api.fonts()
* - GET /api/font-meta api.fontMeta(name) / codepoint / name
* - GET /api/config api.config()
* - GET /api/stats api.stats()
* - POST /api/upload api.upload({...}) /
* - POST /api/stats/event api.reportEvent(...) 线
*/
/** 字体列表项GET /api/fonts */
export interface IApiFontInfo {
/** 字体文件名(子集 API 查询用,如 '令东齐伋复刻体.ttf' */
name: string
/** 是否为临时上传字体(到期自动清理,列表展示时可过滤) */
temporary: boolean
}
/** 字符集覆盖率项fontMeta 返回) */
export interface IApiCharsetCoverage {
/** 字符集标识,如 'ascii'、'cjkBasic' */
key: string
/** 字符集名称(中文) */
name: string
/** 该字符集总字符数 */
total: number
/** 字体覆盖的字符数 */
covered: number
/** 覆盖率百分比0~100保留一位小数 */
percent: number
}
/** OpenType name 表信息(版权 / 作者 / 许可等fontMeta 返回) */
export interface IApiFontNameInfo {
copyright?: string
family?: string
subfamily?: string
uniqueId?: string
fullName?: string
version?: string
postScript?: string
trademark?: string
manufacturer?: string
designer?: string
description?: string
vendorUrl?: string
designerUrl?: string
license?: string
licenseUrl?: string
}
/** 人工配置项(服务端 font-config.json由站长维护fontMeta 返回) */
export interface IApiFontUserConfig {
/** 显示名称(优先于文件名) */
displayName?: string
/** 描述 / 简介 */
description?: string
/** 标签列表 */
tags?: string[]
/** 开源仓库地址 */
homepage?: string
/** 默认预览文字 */
previewText?: string
/** 详情页正文标题 */
bodyTitle?: string
/** 详情页正文段落 */
bodyText?: string
/** 详情页字符预览行 */
charsetPreview?: string
}
/** 字体元数据GET /api/font-meta */
export interface IApiFontMeta {
/** 元数据版本指纹(算法变更后 bump */
metaVersion: number
/** 字体支持的 codepoint 总数 */
totalCodePoints: number
/** 各标准字符集覆盖率 */
coverage: IApiCharsetCoverage[]
/** 支持的 codepoint 区间(紧凑表示,如 [[0x20, 0x7e], [0x4e00, 0x9fff]] */
ranges: Array<[number, number]>
/** name 表基本信息 */
info: IApiFontNameInfo
/** 人工配置(服务端配置了才有) */
config?: IApiFontUserConfig
}
/** 服务公开配置GET /api/config */
export interface IApiServerConfig {
/** 是否启用临时字体上传 */
enableTempUpload: boolean
/** 是否启用管理员上传(服务端配置了 API Key */
adminUploadEnabled: boolean
/** 支持的子集输出格式 */
supportedOutTypes: Array<'woff2' | 'ttf'>
/** 临时字体保留时限(秒) */
tempRetentionSeconds: number
/** 字体子集化最大并发数 */
subsetConcurrency: number
/** 队列等待超时(秒) */
subsetQueueTimeoutSeconds: number
}
/** 运行统计GET /api/stats */
export interface IApiServerStats {
/** 服务运行秒数 */
uptime: number
/** 总请求数 */
totalRequests: number
/** 子集化请求数 */
subsetRequests: number
/** 子集缓存命中数 */
subsetCacheHits: number
/** 累计裁剪字符数 */
totalChars: number
/** 临时字体上传次数 */
tempUploads: number
/** 离线裁剪完成次数 */
offlineSubsets: number
/** 离线裁剪字体下载次数 */
offlineDownloads: number
/** 子集结果缓存条目数 */
subsetCacheEntries: number
/** 字体二进制缓存条目数 */
fontBufferCacheEntries: number
}
/** 上传结果POST /api/upload失败是业务预期不抛错由调用方判断 success */
export interface IApiUploadResult {
success: boolean
error?: string
}
/** 客户端配置 */
export interface IWebFontApiOptions {
/** 服务基地址,默认官方在线服务 */
baseUrl?: string
/** 自定义 fetch 实现(老版本 Node / 测试注入用,默认全局 fetch */
fetchImpl?: typeof fetch
}
/** 上传参数 */
export interface IApiUploadInput {
/** 字体二进制内容 */
data: Blob
/** 保存到服务端的文件名(如 '我的字体.ttf' */
filename: string
/** 上传模式temp 临时字体(默认,到期自动清理)/ admin 管理员字体(需 apiKey */
mode?: 'temp' | 'admin'
/** admin 模式的 API Key */
apiKey?: string
}
/** API 客户端实例 */
export interface IWebFontApi {
/** 字体列表 */
fonts(): Promise<IApiFontInfo[]>
/** 字体元数据(覆盖率 / codepoint 区间 / name 表 / 人工配置) */
fontMeta(fontName: string): Promise<IApiFontMeta>
/** 服务公开配置 */
config(): Promise<IApiServerConfig>
/** 运行统计 */
stats(): Promise<IApiServerStats>
/** 上传字体(失败返回 { success: false, error },不抛错) */
upload(input: IApiUploadInput): Promise<IApiUploadResult>
/** 离线裁剪匿名事件上报(只发事件类型,不含任何内容数据;页面卸载也能送达) */
reportEvent(event: 'offline_subset' | 'offline_download'): void
}
/**
* API
*
* GET 2xx Errorfail fast
* upload 4xx + { success: false, error }
*/
export function createWebFontApi(options: IWebFontApiOptions = {}): IWebFontApi {
/** 去掉末尾斜杠,避免拼出双斜杠 */
const baseUrl = (options.baseUrl ?? 'https://webfont.shenzilong.cn').replace(/\/+$/, '')
const fetchImpl = options.fetchImpl ?? fetch
async function getJson<T>(path: string): Promise<T> {
const res = await fetchImpl(baseUrl + path)
if (!res.ok) {
const body = await res.text().catch(() => '')
throw new Error(`webfont-sdk/api GET ${path} → HTTP ${res.status}${body ? `: ${body.slice(0, 200)}` : ''}`)
}
return res.json() as Promise<T>
}
return {
fonts: () => getJson<IApiFontInfo[]>('/api/fonts'),
fontMeta: (fontName) => getJson<IApiFontMeta>(`/api/font-meta?font=${encodeURIComponent(fontName)}`),
config: () => getJson<IApiServerConfig>('/api/config'),
stats: () => getJson<IApiServerStats>('/api/stats'),
upload: async ({ data, filename, mode = 'temp', apiKey }: IApiUploadInput) => {
const form = new FormData()
form.append('font', data, filename)
/** 仅 admin 模式需要鉴权头 */
const headers: Record<string, string> = {}
if (apiKey) headers['Authorization'] = `Bearer ${apiKey}`
const res = await fetchImpl(`${baseUrl}/api/upload?mode=${mode}`, {
method: 'POST',
body: form,
headers,
})
return res.json() as Promise<IApiUploadResult>
},
reportEvent: (event) => {
const body = JSON.stringify({ event })
/** sendBeacon 优先:页面卸载时也能送达;失败静默降级 fetch keepalive——统计不干扰主流程 */
const nav = (globalThis as { navigator?: Navigator }).navigator
if (nav?.sendBeacon?.(`${baseUrl}/api/stats/event`, new Blob([body], { type: 'application/json' }))) return
fetchImpl(`${baseUrl}/api/stats/event`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body,
keepalive: true,
}).catch(() => {})
},
}
}

View File

@ -1,9 +1,9 @@
import { defineConfig } from 'tsdown'
export default [
/** ESM + d.ts —— npm 包主产物leafer 插件 / bundler 用户) */
/** ESM + d.ts —— npm 包主产物leafer 插件 / bundler 用户)api 为服务端 REST 客户端子路径 */
defineConfig({
entry: ['src/index.ts'],
entry: ['src/index.ts', 'src/api.ts'],
format: 'esm',
dts: true,
clean: true,

3
pnpm-lock.yaml generated
View File

@ -17,6 +17,9 @@ importers:
web-streams-polyfill:
specifier: ^4.3.0
version: 4.3.0
webfont-sdk:
specifier: workspace:*
version: link:packages/webfont-sdk
devDependencies:
'@leafer-ui/node':
specifier: 2.2.9

View File

@ -1,157 +1,80 @@
export interface FontInfo {
name: string;
/**
* API SDK webfont-sdk/api
*
* webfont-sdk SDK
* dogfoodingleafer demonpm
*
* FontInfo / FontMeta / ...
* import SDK
*
* baseUrl dev vite proxy /api 8087
* baseUrl "/api/..."
*/
import {
createWebFontApi,
type IApiFontInfo,
type IApiFontMeta,
type IApiServerConfig,
type IApiServerStats,
type IApiUploadResult,
} from "webfont-sdk/api";
const api = createWebFontApi({ baseUrl: "" });
/** 字体列表项(旧名兼容;新代码用 IApiFontInfo */
export type FontInfo = IApiFontInfo & {
/** 旧字段(后端实际不返回,恒 undefineddev 预览页模板引用,保留可选 */
dir?: string;
/** 是否为临时上传的字体 */
temporary?: boolean;
}
};
export interface ServerConfig {
enableTempUpload: boolean;
adminUploadEnabled: boolean;
supportedOutTypes: ("woff2" | "ttf")[];
/** 临时字体保留时限(秒) */
tempRetentionSeconds?: number;
/** 字体子集化最大并发数 */
subsetConcurrency?: number;
/** 队列等待超时(秒) */
subsetQueueTimeoutSeconds?: number;
}
/** 字体元数据(旧名兼容;新代码用 IApiFontMeta */
export type FontMeta = IApiFontMeta;
export interface UploadResult {
success: boolean;
error?: string;
}
/** 服务公开配置(旧名兼容;新代码用 IApiServerConfig */
export type ServerConfig = IApiServerConfig;
export interface ServerStats {
uptime: number;
totalRequests: number;
subsetRequests: number;
subsetCacheHits: number;
totalChars: number;
subsetCacheEntries: number;
fontBufferCacheEntries: number;
/** 临时文件上传次数 */
tempUploads?: number;
/** 离线裁剪完成次数 */
offlineSubsets?: number;
/** 离线裁剪字体下载次数 */
offlineDownloads?: number;
}
/** 上传结果(旧名兼容;新代码用 IApiUploadResult */
export type UploadResult = IApiUploadResult;
/** 字符集覆盖率 */
export interface CharsetCoverage {
/** 字符集标识,如 "ascii"、"cjkBasic" */
key: string;
name: string;
total: number;
covered: number;
percent: number;
}
/** 运行统计(旧名兼容;新代码用 IApiServerStats */
export type ServerStats = IApiServerStats;
/** 字体基本信息(来自 OpenType name 表) */
export interface FontInfo {
copyright?: string;
family?: string;
subfamily?: string;
uniqueId?: string;
fullName?: string;
version?: string;
postScript?: string;
trademark?: string;
manufacturer?: string;
designer?: string;
description?: string;
vendorUrl?: string;
designerUrl?: string;
license?: string;
licenseUrl?: string;
}
/** 人工配置项(来自 font-config.json由用户维护 */
export interface FontUserConfig {
/** 显示名称(优先于文件名) */
displayName?: string;
/** 描述/简介 */
description?: string;
/** 标签列表 */
tags?: string[];
/** 开源仓库地址(如 GitHub URL */
homepage?: string;
/** 默认预览文字 */
previewText?: string;
/** 详情页正文标题 */
bodyTitle?: string;
/** 详情页正文段落 */
bodyText?: string;
/** 详情页字符预览行 */
charsetPreview?: string;
}
/** 字体元数据 */
export interface FontMeta {
totalCodePoints: number;
coverage: CharsetCoverage[];
ranges: Array<[number, number]>;
/** 字体基本信息(版权、作者等) */
info: FontInfo;
/** 人工配置(来自 font-config.json */
config?: FontUserConfig;
}
export { type IApiCharsetCoverage as CharsetCoverage, type IApiFontUserConfig as FontUserConfig } from "webfont-sdk/api";
export async function fetchFonts(): Promise<FontInfo[]> {
const res = await fetch("/api/fonts");
return res.json();
return api.fonts();
}
export async function fetchFontMeta(fontName: string): Promise<FontMeta> {
const res = await fetch(`/api/font-meta?font=${encodeURIComponent(fontName)}`);
return res.json();
return api.fontMeta(fontName);
}
export async function fetchConfig(): Promise<ServerConfig> {
const res = await fetch("/api/config");
return res.json();
return api.config();
}
export async function fetchStats(): Promise<ServerStats> {
return api.stats();
}
/**
* /
*
* SDK FormData File
* FormData.append(name, File) filename
*/
export async function uploadFont(
file: File,
mode: "temp" | "admin",
apiKey?: string,
): Promise<UploadResult> {
const formData = new FormData();
formData.append("font", file);
const headers: Record<string, string> = {};
if (apiKey) {
headers["Authorization"] = `Bearer ${apiKey}`;
}
const res = await fetch(`/api/upload?mode=${mode}`, {
method: "POST",
body: formData,
headers,
});
return res.json();
}
export async function fetchStats(): Promise<ServerStats> {
const res = await fetch("/api/stats");
return res.json();
return api.upload({ data: file, filename: file.name, mode, apiKey });
}
/**
* 线
*
* /
* sendBeacon
* 线 SDK
* sendBeacon
*/
export function reportOfflineEvent(event: "offline_subset" | "offline_download"): void {
const body = JSON.stringify({ event });
if (navigator.sendBeacon?.("/api/stats/event", new Blob([body], { type: "application/json" }))) return;
fetch("/api/stats/event", {
method: "POST",
headers: { "Content-Type": "application/json" },
body,
keepalive: true,
}).catch(() => {});
api.reportEvent(event);
}

View File

@ -57,6 +57,12 @@ const messages = {
sdkModes: "还支持",
observeFont: "MutationObserver 事件驱动)和",
loadText: "手动传文本两种方式多种方式可同时使用SDK 内部自动按字体去重增量加载。",
/** npm SDK 章节 */
npmSdkTitle: "npm 包(推荐,工程化项目):",
npmSdkText: "安装 ",
npmSdkText2: " 后可在任意前端工程 / Node 项目中使用,支持 DOMCSS 模式)与 CanvasFontFace 模式):",
npmSdkApiTitle: "服务端 API 客户端:",
npmSdkApiText: "字体列表 / 元数据 / 上传 / 统计等 REST 接口封装在独立子路径,供字体选择器等场景使用:",
thanks: "感谢",
thanksText: "收录本项目",
buyCoffee: "觉得好用?",
@ -161,6 +167,12 @@ const messages = {
sdkModes: "Also supports ",
observeFont: " (MutationObserver-driven) and ",
loadText: " (manual text). Multiple modes can be used simultaneously with automatic deduplication.",
/** npm SDK section */
npmSdkTitle: "npm package (recommended for projects):",
npmSdkText: "Install ",
npmSdkText2: " to use in any frontend / Node project. Supports DOM (CSS mode) and Canvas (FontFace mode):",
npmSdkApiTitle: "Server API client:",
npmSdkApiText: "REST endpoints (font list / metadata / upload / stats) live in a separate subpath export:",
thanks: "Thanks to ",
thanksText: " for featuring this project",
buyCoffee: "Find it useful? ",

View File

@ -40,6 +40,41 @@ const basicUsageCode = computed(() => {
const jsSdkCode = computed(() => {
return '<script src="' + origin.value + '/webfont-sdk.js"><\/script>\n\n<h1 class="title">你的文字</h1>\n<p class="content">输入任意文字SDK 自动裁剪加载</p>\n\n<script>\n WebFont.observeFont({\n fontName: "字体文件名.ttf",\n selector: ".title, .content",\n family: "MyFont",\n });\n<\/script>';
});
/** npm 安装命令 */
const npmSdkCode = `npm install webfont-sdk`;
/** npm 包用法示例CSS 模式 + Canvas 模式),依赖 origin 需 computed */
const npmSdkUsageCode = computed(() => {
return `import { WebFont, WebFontCanvas } from 'webfont-sdk'
// DOM
const obs = WebFont.observeFont({
fontName: '字体文件名.ttf',
selector: '.title',
family: 'MyFont',
baseUrl: '${origin.value}',
})
// Canvas leafer / fabric / canvas
const face = WebFontCanvas.loadFontFace(
{ fontName: '字体文件名.ttf' },
() => redraw(), /* 片段就绪,重绘 */
)
face.update('画布上的文字')
await WebFontCanvas.ready()`;
});
/** 服务端 API 客户端示例webfont-sdk/api 子路径),依赖 origin 需 computed */
const npmSdkApiCode = computed(() => {
return `import { createWebFontApi } from 'webfont-sdk/api'
const api = createWebFontApi({ baseUrl: '${origin.value}' })
const fonts = await api.fonts() //
const meta = await api.fontMeta('字体名') // 覆盖率 / codepoint 区间
const r = await api.upload({ data: file, filename: '我的字体.ttf' })
if (!r.success) console.error(r.error)`;
});
</script>
<template>
@ -70,6 +105,13 @@ const jsSdkCode = computed(() => {
<div style="margin-top: 4px"><CodeBlock :code="jsSdkCode" lang="html" /></div>
<p style="margin-top: 12px">{{ t('sdkModes') }}<code>WebFont.observeFont()</code>{{ t('observeFont') }}<code>WebFont.loadText()</code>{{ t('loadText') }}</p>
<p style="margin-top: 20px"><b>{{ t('npmSdkTitle') }}</b>{{ t('npmSdkText') }}<code>webfont-sdk</code>{{ t('npmSdkText2') }}</p>
<div style="margin-top: 4px"><CodeBlock :code="npmSdkCode" lang="bash" /></div>
<div style="margin-top: 4px"><CodeBlock :code="npmSdkUsageCode" lang="ts" /></div>
<p style="margin-top: 20px"><b>{{ t('npmSdkApiTitle') }}</b>{{ t('npmSdkApiText') }}</p>
<div style="margin-top: 4px"><CodeBlock :code="npmSdkApiCode" lang="ts" /></div>
</div>
</div>
</template>