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

@resource-fallback/core

v0.3.1

Published

Browser runtime + Node helpers for resource-fallback (multi-CDN retry & fallback)

Readme

@resource-fallback/core

中文 | English

浏览器运行时 + Node 端工具函数,是 resource-fallback 方案的核心包。

终端用户通常不需要直接依赖本包——请安装 @resource-fallback/vite-plugin 或 @resource-fallback/webpack-plugin。仅当需要自定义集成或手动注入运行时时才需要直接使用。

安装

pnpm add @resource-fallback/core

常用 Node 端 API

import {
  defineConfig,
  buildInjectedTags,
  getRuntimeCode,
  getRuntimePath,
  getServiceWorkerCode,
  getServiceWorkerPath,
  buildResourceFallbackManifest,
  buildServiceWorkerAssets,
  serialiseConfig,
} from '@resource-fallback/core';

| 函数 | 说明 | | ------------------------------------------ | ------------------------------------------------------------------------------------------- | | defineConfig(opts) | 恒等辅助函数,提供类型安全的配置编写体验 | | getRuntimePath() | 返回 IIFE 运行时文件的绝对路径 | | getRuntimeCode() | 返回 IIFE 运行时文件的字符串内容(首次调用后缓存) | | getServiceWorkerPath() | 返回 Service Worker 运行时文件的绝对路径 | | getServiceWorkerCode() | 返回 Service Worker 运行时文件的字符串内容(首次调用后缓存) | | buildResourceFallbackManifest(input) | 根据版本种子、规则和资源列表构建稳定版本的资源 manifest | | buildServiceWorkerAssets(options, input) | 按配置生成预置 manifest/config 的 Service Worker 产物;未启用 SW 时返回 null | | buildInjectedTags(opts) | 根据配置构建需要注入 HTML 的 <script> / <link> 标签描述数组;会先序列化配置并丢弃函数值 | | serialiseConfig(cfg) | 将运行时配置序列化为可嵌入页面的 JSON 字符串;函数字段不会保留 |

defineConfig

import { defineConfig } from '@resource-fallback/core';

export default defineConfig({
  rules: [
    {
      base: 'https://cdn.example.com/',
      urls: ['https://backup.example.com/', '/'],
      retry: { max: 2, baseDelay: 300 },
      circuit: { threshold: 3 },
    },
  ],
  debug: 'auto',
});

buildInjectedTags

为自定义插件/构建流程手动注入运行时:

import { buildInjectedTags } from '@resource-fallback/core';

const tags = buildInjectedTags({
  rules: [{ base: 'https://cdn.example.com/', urls: ['/'] }],
  nonce: 'abc123',
  injectPreconnect: true,
});

// tags 结构示例:
// [
//   { tagName: 'link', attributes: { rel: 'preconnect', href: 'https://cdn.example.com', crossorigin: 'anonymous' } },
//   { tagName: 'script', attributes: { nonce: 'abc123' }, innerHTML: '<IIFE code>;window.__RF__.install({...})' },
// ]

注意:buildInjectedTags() 和插件自动生成的 window.__RF__.install(...) 调用都会先序列化配置对象。hooks 里的函数、以及其他函数类型字段,都会在这一阶段被丢弃。externalRuntime 只把 runtime IIFE 改为外链,自动 install(...) 仍是一段内联脚本;严格 CSP 下应为它配置 nonce 或等效授权。它同样不会保留这些函数;自动注入场景推荐监听 DOM rf:* 事件。如需 JS hooks,请在页面里手动调用 window.__RF__.install()。

浏览器运行时

运行时以 IIFE 格式注入页面(当前构建约 10KB gzip,具体以构建产物为准),通过 window.__RF__ 暴露接口:

interface RfGlobal {
  install(config: RuntimeConfig): void;
  url(filename: string): string;
  load(filename: string): Promise<unknown>; // Vite 专用
  dispose(): void;
  installed: boolean;
  version: string;
}

运行时模块

| 模块 | 职责 | | -------------------- | ---------------------------------------------------------------------------------------------------------------- | | entry | 初始化 window.__RF__ 全局对象,创建共享 RecoveryCoordinator / ownership / lifecycle,并调度各适配器安装 | | observer | 监听 window 上的 error 事件(捕获阶段),把 <script> 和 <link rel="stylesheet"> 失败交给共享 coordinator | | coordinator | 页面侧恢复决策引擎;统一负责规则匹配、重试、回退、熔断、超时、取消和恢复事件;适配器只提供原生 transport | | circuit | per-host 熔断状态;页面侧当前只创建一个 registry,并通过 localStorage 实现跨标签页状态共享 | | retry | 指数退避延迟计算(baseDelay × 2^(attempt-1)),可选 ±25% 抖动 | | hooks | 事件总线,同时分发 DOM CustomEvent 和 JS 函数钩子 | | kill-switch | 三重紧急开关检测(全局变量 / 查询参数 / Cookie) | | logger | 可选的日志输出,支持 debug: 'auto'(通过 localStorage.__RF_DEBUG__ 控制) | | adapter-vite | 通过共享 coordinator 执行 Vite 动态 import(__RF__.load)+ vite:preloadError 处理 | | adapter-webpack | 拦截 chunkLoadingGlobal 的 push 方法 + 包装 __webpack_require__.l | | adapter-systemjs | hook System.constructor.prototype.instantiate,为 legacy bundle 提供回退 |

Observer 行为细节

  • 仅处理顶层 <script> 和 <link rel="stylesheet"> 的 error 事件
  • 自动跳过 <link rel="preload|prefetch|modulepreload"> 等预加载提示
  • 自动跳过带 data-webpack 属性的 <script>(由 webpack adapter 处理)
  • 通过共享 ownership registry 避免与 Webpack/SystemJS 等运行时适配器重复接管同一资源
  • ES Module 脚本重试时自动添加 __rf= 查询参数,绕过浏览器模块缓存
  • 经典脚本和 CSS 不添加 cache-bust 参数,避免降低 CDN 缓存命中率
  • 替换标签使用 createElement 而非 cloneNode,避免浏览器的 "already started" 标记

共享恢复与规则限制

  • 页面侧 RecoveryCoordinator 会按 owner + logical resource key 共享一次进行中的恢复 Promise
  • 同一个 owner 命中同一个逻辑资源时会加入同一条 retry / fallback 链;不同 owner 或不同逻辑 key 不共享
  • ownership registry 会阻止 Observer 与 Vite / Webpack / SystemJS 适配器分别接管同一个逻辑资源
  • 规则编译时按 base 长度降序排序,匹配时优先更长前缀
  • window.__RF__.url(filename) 只使用第一条已编译规则的 base 构造首轮 URL,不感知熔断状态
  • 页面 runtime 当前只有一个 circuit registry,使用第一条已编译规则的 circuit 选项初始化;Service Worker 仍使用 resolver,但其熔断状态始终是独立内存

事件

运行时在每个决策点分发 DOM CustomEvent:

| 事件 | 触发时机 | event.detail | | ------------- | ---------------------------------------- | ------------------------------------------------ | | rf:retry | 同一 URL 重试 | { url: string, attempt: number } | | rf:fallback | 切换到下一个候选 URL | { from: string, to: string, reason?: unknown } | | rf:success | 页面或 SW 经 retry / fallback 后恢复成功 | { url: string, attempts: number } | | rf:error | 页面侧 session 失败,或 SW 透传错误 | { url: string, reason?: unknown } |

页面侧和 SW 首轮直接成功都不会触发 rf:success。

导出

// package.json exports
{
  ".": "Node 端 API(defineConfig / buildInjectedTags / 类型等)",
  "./runtime": "浏览器 IIFE 运行时文件(runtime.iife.js)",
}

类型导出

export type {
  CircuitOptions,
  BuildInjectedTagsOptions,
  ErrorEvent,
  FallbackEvent,
  FallbackRule,
  HtmlTag,
  HtmlTagAttributes,
  NormalizedServiceWorkerOptions,
  PluginOptions,
  ResolveResult,
  ResourceFallbackAssetOwner,
  ResourceFallbackAssetType,
  ResourceFallbackManifest,
  ResourceFallbackManifestAsset,
  RetryEvent,
  RetryOptions,
  RuntimeConfig,
  RuntimeHooks,
  ServiceWorkerOptions,
  SriPolicy,
  SuccessEvent,
} from '@resource-fallback/core';

许可证

MIT