@edgeone/is-spa

中文文档
0.0.4发布于 2026/10/26MITCommonJS零依赖近 30 天下载 1.6万

检测前端项目是SPA、MPA、Hybrid还是SSG。 确定是否需要 Nginx/ CDN 回落到index.html .

中文使用文档
文档目录19 节
  1. 快速开始
  2. 安装
  3. API
  4. needsFallback(dir, options?): boolean
  5. autoDetect(dir): DetectionResult
  6. detect(projectRoot): DetectionResult
  7. detectBuildOutput(distDir): DetectionResult
  8. isSpa(projectRoot): boolean
  9. CLI
  10. 检测结果类型
  11. 支持的框架和路由库
  12. 框架检测(快速路径)
  13. 路由库检测
  14. 检测原理
  15. 源码检测
  16. 构建产物检测
  17. needsFallback 自动检测
  18. 测试
  19. License

is-spa-project

检测前端项目是否为 SPA(单页应用),判断部署时是否需要配置 Nginx/CDN 回源兜底到 index.html。

支持源码检测和构建产物检测两种模式,覆盖 React、Vue、Angular、Svelte、Next.js、Nuxt、SvelteKit、Remix、React Router 等主流框架。

快速开始

const { needsFallback } = require('is-spa-project')

// 传入任意目录,自动判断
needsFallback('./my-project')       // true — 需要配置兜底
needsFallback('./my-project/dist')  // true
needsFallback('./my-nuxt-app')      // false — 不需要兜底

安装

npm install is-spa-project

API

needsFallback(dir, options?): boolean

推荐使用。 判断是否需要配置回源兜底。

const { needsFallback } = require('is-spa-project')

// 自动模式(默认)— 自动判断源码/产物
needsFallback('./cra-spa')          // true
needsFallback('./cra-spa/build')    // true
needsFallback('./nuxt-app')         // false

// 强制源码检测
needsFallback('./my-project', { mode: 'source' })

// 强制构建产物检测
needsFallback('./my-project/dist', { mode: 'dist' })

options.mode:

值说明
'auto'(默认)自动判断目录是源码还是构建产物
'source'强制源码检测(分析 package.json、配置文件)
'dist'强制构建产物检测(分析 HTML 和 JS 文件)

autoDetect(dir): DetectionResult

自动识别目录类型,返回完整检测结果。

const { autoDetect } = require('is-spa-project')

const result = autoDetect('./my-project')
console.log(result.mode)       // 'source' | 'dist'
console.log(result.type)       // 'spa' | 'mpa' | 'hybrid' | 'ssg' | 'unknown'
console.log(result.confidence) // 'high' | 'medium' | 'low'
console.log(result.reason)     // 人类可读的判定原因

detect(projectRoot): DetectionResult

源码检测模式。分析 package.json、配置文件、入口文件。

detectBuildOutput(distDir): DetectionResult

构建产物检测模式。分析 HTML 文件和 JS bundle 中的路由代码。

isSpa(projectRoot): boolean

源码检测简化版,等价于 detect().type === 'spa' || 'hybrid'。

CLI

# 自动模式(自动判断源码/产物)
npx is-spa ./my-project
npx is-spa ./my-project/dist

# 强制构建产物模式
npx is-spa ./my-project/dist --dist

# JSON 输出
npx is-spa ./my-project --json
npx is-spa ./my-project/dist --dist --json

检测结果类型

类型含义需要兜底?部署配置
spa构建产物只有单个 index.html✅ 需要try_files $uri $uri/ /index.html
hybridSPA 主体 + 独立辅助页面✅ 需要主入口需要兜底
mpa多个独立 HTML 入口❌ 不需要每个路由有对应文件
ssgSSR/SSG 框架,每个路由有对应 HTML❌ 不需要框架构建工具自动处理
unknown无法判定❌ 不需要—

支持的框架和路由库

框架检测(快速路径)

框架依赖默认判定可切换为 SPA?
Create React Appreact-scriptsspa—
Angular CLI@angular/clispa—
Next.jsnextssg❌
Nuxtnuxtssg❌(generate 自动处理)
Gatsbygatsbyssg❌
React Router (Framework)@react-router/devssg✅ ssr: false → spa
SvelteKit@sveltejs/kitssg✅ fallback → spa
Remix@remix-run/reactssg✅ ssr: false → spa

路由库检测

路由库生态
vue-routerVue
react-router-dom / react-routerReact
@tanstack/react-routerReact
wouterReact
@angular/routerAngular
svelte-routingSvelte
svelte-spa-routerSvelte
page (page.js)Vanilla JS
navigoVanilla JS
universal-routerVanilla JS

检测原理

源码检测

package.json → 匹配已知框架?→ 框架快速路径(可能读取配置文件)
                    ↓ 否
              检测路由库依赖 + 入口文件数量 + router 使用 → 综合判定

构建产物检测

根目录有 index.html?
├── 没有 → unknown(不存在回源目标)
└── 有 → 扫描 HTML + JS → 判定
信号SPASSGMPA
应用 HTML 数1多个多个
HTML body空壳有预渲染内容有各自内容
JS 含路由代码✅✅❌
多 HTML 共享 JS—✅❌

路由代码只统计页面实际加载的 JS:HTML 中的 <script src> / <link rel="modulepreload">,以及这些文件通过静态 import ... from / export ... from 引用到的 chunk。没有被页面引用的懒加载 chunk 不参与判定,只会出现在 details.unreferencedRouterJsFiles 里,便于排查。

关键词按标识符边界匹配,避免 onpopstate 这类字符串被语法高亮数据表误命中;onpopstate 仅在赋值场景(window.onpopstate = ...)才视为路由实现。

产物根目录存在静态 404.html(不含 JS 引用)时,认为作者已经声明了 404 语义,不再自动开启回退。如果 404.html 本身是带 JS 的应用页面(如 Vue CLI / SvelteKit 生成的辅助页),仍按原逻辑判定。

needsFallback 自动检测

传入目录 → 判断是源码还是产物
├── 有 package.json(含 dependencies)或 src/ → 源码检测
└── 否则 → 产物检测
主模式结果 unknown(low) → 回退另一种模式(仅采纳 high 置信度)
构建产物模式:只有 high 置信度、且没有静态 404.html 时才返回 true

测试

npm test            # 源码检测(24 个测试项目)
npm run test:dist   # 构建产物检测(24 个测试项目)
npm run test:edge   # 产物检测边界用例
npm run test:all    # 全部运行

测试覆盖 24 个项目:CRA、Vite+React、Vite+Vue、Angular、Vue CLI(SPA/MPA/Hybrid)、Next.js、Nuxt(SSG/SPA)、SvelteKit(SSG/SPA)、Remix(SSR/SPA)、React Router Framework(SPA)、TanStack Router、wouter、svelte-routing、svelte-spa-router、page.js、navigo、universal-router、原生 HTML(单页/多页)。

License

MIT

版本与发布记录

@edgeone/is-spa 共发布 4 个版本,首次发布于 2026/04/13;过去 12 个月发布了 4 个版本。

版本发布日期距今
0.0.4latest2026/10/2618 天前
0.0.32026/04/236 个月前
0.0.22026/04/137 个月前
0.0.12026/04/137 个月前

关于 @edgeone/is-spa 的常见问题

@edgeone/is-spa 是什么?

检测前端项目是SPA、MPA、Hybrid还是SSG。 确定是否需要 Nginx/ CDN 回落到index.html .

如何安装 @edgeone/is-spa?

在项目目录运行 npm install @edgeone/is-spa,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 is-spa,可以用 npx is-spa 直接运行。

@edgeone/is-spa 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/edgeone__is-spa 是否存在。

@edgeone/is-spa 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@edgeone/is-spa 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=14.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@edgeone/is-spa 可以商用吗?

@edgeone/is-spa 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@edgeone/is-spa 的下载量有多少?

根据 npm 官方下载统计,@edgeone/is-spa 在 2026/10/13 – 2026/11/11 这 30 天内被下载 15,849 次,日均约 528 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@edgeone/is-spa 还在维护吗?

最新版本 0.0.4 发布于 2026/10/26(18 天前);至今共发布 4 个版本,其中过去 12 个月发布了 4 个;首次发布于 2026/04/13。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。