# @equinor/fusion-framework-vite-plugin-spa 中文文档

规范地址：https://npmcn.com/package/%40equinor/fusion-framework-vite-plugin-spa/

版本：5\.2\.5
npm 元数据更新时间：2026-11-12T10:00:00.772Z
中文译文更新时间：2026-11-13T20:22:18.621Z
软件包许可：ISC

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40equinor/fusion-framework-vite-plugin-spa
原文对照：https://npmcn.com/package/%40equinor/fusion-framework-vite-plugin-spa/?lang=original
源码仓库：https://github.com/equinor/fusion-framework

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：7.6 MB，67 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：14 个
- 首次发布：2025-05-27T15:15:30.402Z
- 最新版本发布：2026-11-12T10:00:00.464Z
- 近 30 天下载量：9228（2026-10-14 至 2026-11-12，npm 官方下载统计）
- 已发布版本数：87（近 12 个月 61 个）

## 中文简介

用于 SPA 开发的 Vite 插件

## 安装

```sh
npm install @equinor/fusion-framework-vite-plugin-spa
```

也可以使用：`pnpm add @equinor/fusion-framework-vite-plugin-spa`、`yarn add @equinor/fusion-framework-vite-plugin-spa`、`bun add @equinor/fusion-framework-vite-plugin-spa`

## README

* * *

标题: Vite SPA 插件 说明: > 用于构建Fusion框架单页应用程序的Vite插件. 自动生成 HTML 模板、 MSAL 认证拖曳, 服务发现接线、门户清单装入和认证 API通过服务员代理. 标记 :

-   聚变框架
-   维特-插件
-   语气
-   应用开发
-   门户开发
-   dev 服务器
-   认证
-   服务发现
-   服务人员
-   等值
-   非生产 关键词 :
-   '@equinor/suplic-framework-vite-plugin-spa' (英语)
-   聚变框架
-   维特
-   温泉
-   插件
-   发展
-   非生产
-   毫萨尔
-   服务人员
-   门户

* * *

# @ equinor/ 聚变框架- vite- plugin- spa

[![npm version](https://img.shields.io/npm/v/@equinor/fusion-framework-vite-plugin-spa.svg?style=flat)](https://www.npmjs.com/package/@equinor/fusion-framework-vite-plugin-spa) [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://npmcn.com/package/%40equinor/fusion-framework-vite-plugin-spa/LICENSE)

用于构建Fusion框架单页应用程序(SPA)的Vite插件. 它生成一个 HTML 外壳, 靴子陷阱 MSAL 认证和服务发现, 通过列表加载一个传送门, 并注册一个服务员, 将 Bearer 令牌注入向外的 API 请求中.

> \[叹息\] 此插件用于 **非生产发展环境** 只有这个.

> \[尖叫声\] 此插件设计用于 [`@equinor/fusion-framework-cli`](https://github.com/equinor/fusion-framework/tree/main/packages/cli)。 CLI 脚手架自动设置所有所需的配置.
> 
> 独立使用是需要深入了解融合框架内部的高级设想。 以下文件涵盖了需要者的全部配置表面.

## 它会做什么

| 责任 | 说明 |
| --- | --- |
| **组合框架** | 初始化 MSAL 认证、服务发现和遥测模块 |
| **调整已配置的门户** | 获取以 ID 显示的门户并加载其切入点 |
| **登记服务人员** | 截取请求, 重写 URL, 并附加 OAuth 接取符 |
| **配置 Dev 环境** | 与 `@equinor/fusion-framework-vite-plugin-api-service` 用于开发过程中的代理认证请求 |

> \[TIP\] 需要渲染的门户来源于:
> 
> -   A 类 **本地 npm 软件包** (例如:. `@equinor/fusion-framework-dev-portal`, CLI 使用的默认值)
> -   这个 **融合门户服务** (使用门户标识符)
> -   任意 **自定义门户** 执行 `render` 函数

## 插件是如何工作的

```mermaid
flowchart
  A[Vite HTML request] -->|index.html| B[Plugin serve SPA]
  B -->|bootstrap.js| C[Initialize Fusion Framework]
  C --> D[Register Service Worker]
  C -->|"/portals/{portalId}@${portalTag}"| E[Fetch Portal Manifest]
  E -->|manifest.build.config| F[Fetch Portal Configuration]
  F -->|manifest.build.entrypoint| G[Import Portal Source]
  G -->|"Fusion Instance"| H[Render Portal]

  style A fill:#F00,stroke:#333,stroke-width:1px
  style H fill:#00F,stroke:#333,stroke-width:1px
```

**流程解释:**

1.  **Vite HTML 请求**:插件会钩入Vite dev-server并截取SPA请求.
2.  **服务于SPA**: 该插件通过返回 `index.html` 文档.
3.  **初始化融合框架**数字 : `bootstrap.js` 已装入
    -   配置框架(例如 MSAL、服务发现)
    -   初始化框架
    -   登记服务人员(与聚变框架的联系)
4.  **获取端口声明**:框架获取描述要加载的门户的运算表.
5.  **获取端口配置**: 获取门户的额外配置.
6.  **装入端口源文件**: 传送门的主要条目文件根据"通货单"加载.
7.  **传送门户**: 将"融合"框架的"传送"传送出门户.

## 开始

> \[尖叫声\] 此插件主要设计为与 [融合框架CLI](https://github.com/equinor/fusion-framework-cli)。 CLI 脚手架所有所需的配置和接线自动.

独立使用需要您自己提供认证,服务发现,门户加载,服务人员配置. 见 [配置选项](https://npmcn.com/package/%40equinor/fusion-framework-vite-plugin-spa/#readme-configuration-options) 见下文.

### 安装

```sh
pnpm add -D @equinor/fusion-framework-vite-plugin-spa
```

### 最小维特配置

```ts
// vite.config.ts
import { defineConfig } from 'vite';
import { fusionSpaPlugin } from '@equinor/fusion-framework-vite-plugin-spa';

export default defineConfig({
  plugins: [
    fusionSpaPlugin({
      generateTemplateEnv: () => ({
        title: 'My App',
        portal: { id: 'my-portal' },
        serviceDiscovery: {
          url: 'https://my-server.com/service-discovery',
          scopes: ['api://my-app/scope'],
        },
        msal: {
          tenantId: 'my-tenant-id',
          clientId: 'my-client-id',
          redirectUri: 'http://localhost:3000/auth-callback',
          requiresAuth: 'true',
        },
      }),
    }),
  ],
});
```

## 配置选项

这个 `fusionSpaPlugin` (也导出为 `plugin`) 接受一个 `PluginOptions` 具有下列属性的对象:

| 选项 | 类型 | 默认 | 说明 |
| --- | --- | --- | --- |
| `template` | `string` | 内建的 HTML | 自定义 HTML 模板字符串 `%VAR%` 占位符 |
| `templateEnvPrefix` | `string` | `'FUSION_SPA_'` | 环境可变名称的前缀 |
| `generateTemplateEnv` | `(env: ConfigEnv) => Partial<TemplateEnv>` | —— 说 | 生产环境价值的工厂 |
| `logger` | `Pick<Console, 'debug'|'info'|'warn'|'error'>` | —— 说 | 插件诊断的可选日志 |

### 模板环境( E)`generateTemplateEnv`(中文(简体) )

这个 `generateTemplateEnv` 回调返回形状匹配的对象 `FusionTemplateEnv`所有属性被平整为 `FUSION_SPA_*` 构建时的环境变量.

以下是一个全面的例子:

```ts
fusionSpaPlugin({
  generateTemplateEnv: () => ({
    // HTML page title
    title: 'My App',

    // Portal configuration: specify which portal to load
    portal: {
      id: 'my-portal', // Portal ID to load and render
      // Can be:
      //   1. A package name (e.g. '@equinor/fusion-framework-dev-portal', default for CLI)
      //   2. An ID from the Fusion Portal Service
      //   3. Any other configured portal ID
      tag: 'latest', // (Optional) Version tag (defaults to 'latest')
      proxy: false, // (Optional) Whether to proxy portal requests through /portal-proxy (defaults to false)
    },

    // Service Discovery configuration
    serviceDiscovery: {
      url: 'https://my-server.com/service-discovery',
      scopes: ['api://my-app/scope'],
    },

    // MSAL (Microsoft Authentication Library) configuration
    msal: {
      tenantId: 'my-tenant-id',
      clientId: 'my-client-id',
      redirectUri: 'https://my-app.com/auth-callback',
      requiresAuth: 'true',
      mock: 'true', // (Optional) Use mock authentication for CI/Playwright
    },

    // Service Worker configuration for API proxying and authentication
    serviceWorker: {
      resources: [
        {
          url: '/app-proxy',
          rewrite: '/@fusion-api/app',
          scopes: ['xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/.default'],
        },
      ],
    },
  })
});
```

### 门户代理

门户代理功能允许您通过一个 `/portal-proxy` 路径前缀。 启用时, 插件将尝试从 URL 前缀装入门户代码 `/portal-proxy/`,这在与需要截取和路由门户请求的代理服务器或开发环境合作时可能有用.

**行为:**

-   `proxy: true` • 门户负荷 `/portal-proxy/{assetPath}/{templateEntry}` (允许代理拦截)
-   `proxy: false` • 门户负荷 `{assetPath}/{templateEntry}` (直接装入)

**配置选项 :**

-   `proxy`: 当设定为 `true`,门户入口点将使用 `/portal-proxy`

**何时使用门户代理 :**

-   需要通过代理服务门户资产的开发环境
-   需要通过特定路径传送门户的部署设想
-   使用 API 服务插件进行高级门户加载时

**示例**

```ts
portal: {
  id: 'my-portal',
  tag: 'latest',
  proxy: true, // Portal will be loaded from /portal-proxy/{assetPath}/{templateEntry}
}
```

见 [@equinor/ inform-framework-vite-plugin-api-service (英语)](https://github.com/equinor/fusion-framework/tree/main/packages/vite-plugins/api-service) 用于高级 API 代理.

### 服务发现

配置Fusion框架用于在运行时发现后端服务URL的端点.

-   `url` ——服务发现配置的端点 URL
-   `scopes` ——认证请求到服务发现端点所需的OAuth范围

### MSAL 认证

通过微软认证库(MSAL)配置 Azure AD认证.

-   `tenantId` - Azure AD租户身份识别符
-   `clientId` - 在Azure AD注册的申请(客户)ID
-   `redirectUri` —— 认证后重定向到 URL
-   `requiresAuth` _(可选,字符串)_ 何时 `'true'`,自动提示登录第一个负载
-   `mock` _(可选,字符串)_ 何时 `'true'`,使用模拟认证而不是 Entra ID

### 服务工作者

服务员截取输出的取取请求, 与配置匹配 `ResourceConfiguration` 模式,可选地重写 URL,并附加一个 Bearer 符号.

#### 如何运作

```mermaid
sequenceDiagram
  participant App as Application
  participant SW as Service Worker
  participant Main as Fusion Framework
  participant API as API Server

  App->>SW: fetch('/app-proxy/assets/some-app/resource.json')
  alt Route matches a registered resource
    SW->>Main: Request auth tokens for scopes
    Main-->>SW: Return tokens
    SW->>SW: Rewrite URL to /@fusion-api/app/assets/some-app/resource.json
    SW->>API: fetch with auth headers
    API-->>SW: Response
    SW-->>App: Return response
  else Route does not match any resource
    SW-->>App: Let request pass through (no interception)
  end
```

服务员拦截网络请求,可以:

1.  附加 OAuth 守护符以匹配请求
2.  重写代理请求的 URL
3.  通过未修改的请求传递未匹配的请求

#### 资源配置

表格中的每个条目 `resources` 数组为 a `ResourceConfiguration` 对象 :

| 财产 | 类型 | 说明 |
| --- | --- | --- |
| `url` | `string` | 匹配获取请求的路径前缀 |
| `rewrite` | `string?` | 匹配请求的替换路径前缀 |
| `scopes` | `string[]?` | 为匹配的请求获取接头符的授权范围 |

#### 完整示例

以下是服务工作者在行动中的详细例子:

```ts
// Service Worker configuration example
const serviceWorker = {
  resources: [
    {
      url: '/app-proxy',
      rewrite: '/@fusion-api/app',
      scopes: [
        '2bed749c-843b-413d-8b17-e7841869730f/.default',
        '8c24cf81-de7a-435b-ab74-e90b1a7bda0a/.default',
      ],
    },
  ],
};

// Example: Making a request in your application code
fetch('/app-proxy/assets/some-app/resource-path/resource.json');
```

#### 请求处理流程

当上面 `fetch` 提出以下要求:

1.  服务员截取符合 `/app-proxy` 模式
2.  它向主线程发送一个消息, 请求为指定的范围提供认证符
3.  主线程生成必要的认证符
4.  服务工作者重写 URL 从 `/app-proxy/assets/some-app/resource-path/resource.json` 改为 `/@fusion-api/app/assets/some-app/resource-path/resource.json`
5.  它在请求中添加认证头并针对重写的 URL 执行
6.  回复返回到应用程序中, 如原 URL 被调用

> \[TIP\] 这个 `url` 路径不需要对应一个实际终点——它只是一个用于匹配请求的图案. 这使得您可以在生产环境中模拟代理服务而无需更改您的应用程序代码.

> \[TIP\] 为增强发展能力,考虑使用 `@equinor/fusion-framework-vite-plugin-api-service` 插件 。 此插件创建了动态代理服务, 可以处理请求到 `/@fusion-api/app` 通过在dev-server中截取它们并基于服务发现配置进行路由.

## 遥测

插件通过配置控制台遥测 `@equinor/fusion-framework-module-telemetry`。相位图到整数:

| 职等 | 数值 | 说明 |
| --- | --- | --- |
| 调试 | 0 个 | 详细调试信息 |
| 资料 | 1个 | 一般业务资料 |
| 3⁄4 ̄ ̧漯B | 2个 | 非关键问题的潜在问题 |
| 错误 | 3个 | 无法阻止继续运行的错误 |
| 关键 | 页:1 | 可能停止功能的严重错误 |

### 控制控制台输出

设定 `FUSION_SPA_TELEMETRY_CONSOLE_LEVEL` 到显示的最小关卡。 默认是 `1` (资料).

```sh
FUSION_SPA_TELEMETRY_CONSOLE_LEVEL=2  # Warning and above
```

对于高级遥测(如应用透视),提供a [自定义拖曳文件](https://npmcn.com/package/%40equinor/fusion-framework-vite-plugin-spa/#readme-providing-custom-bootstrap)。 。 。 .

使用时 `@equinor/fusion-framework-dev-server`,默认的靴子陷阱也支持 OTLP通过遥测模块的公用日志 `OtlpAdapter`外加标准的 OpenTelection 浏览器请求跟踪和W3C传播. 设定 `FUSION_DEV_SERVER_OTLP_ENDPOINT` 在应用程序的 dev-server 进程中;不需要更改应用程序代码. Dev服务器拥有环境桥和同源的收集路径. 鞋带 只检查端点是否配置; 仅服务 dev- server 桥接控制 启动 明确配置的应用程序适配器和现有的全球跟踪器供应商 优先级。 见 [dev-server 遥测配置](https://npmcn.com/package/dev-server/docs/configuration.md#send-telemetry-to-an-otlp-endpoint)。 。 。 .

## 通过配置 `.env` 文件

插件读取环境变量 `.env` 文件( 通过 Vite ) `loadEnv`和 **将它们合并到** 来自 `generateTemplateEnv`。这使得您可以将机密和每个环境的值从源代码中保留出来.

### 命名公约

1.  前缀所有变量 `FUSION_SPA_` (或您的习惯) `templateEnvPrefix`) (中文(简体) ).
2.  将嵌入对象路径转换为 `UPPER_SNAKE_CASE` (例如:. `serviceDiscovery.url` → `FUSION_SPA_SERVICE_DISCOVERY_URL`) (中文(简体) ).
3.  将数组和对象序列化为JSON字符串.

### 映射示例

```ts
// JavaScript configuration
{
  serviceWorker: {
    resources: [...],
  },
}

// Becomes this environment variable
FUSION_SPA_SERVICE_WORKER_RESOURCES=[...]

// And can be accessed in your code as
import.meta.env.FUSION_SPA_SERVICE_WORKER_RESOURCES
```

### 完成 `.env` 示例

```sh
# Page title
FUSION_SPA_TITLE=My App

# Portal manifest
FUSION_SPA_PORTAL_ID=my-portal
FUSION_SPA_PORTAL_TAG=latest
FUSION_SPA_PORTAL_PROXY=false

# Service Discovery
FUSION_SPA_SERVICE_DISCOVERY_URL=https://my-server.com/service-discovery
FUSION_SPA_SERVICE_DISCOVERY_SCOPES=[api://my-app/scope]

# MSAL
FUSION_SPA_MSAL_TENANT_ID=my-tenant-id
FUSION_SPA_MSAL_CLIENT_ID=my-client-id
FUSION_SPA_MSAL_REDIRECT_URI=https://my-app.com/auth-callback
FUSION_SPA_MSAL_REQUIRES_AUTH=true
# Set to skip Entra ID and sign in a mock user instead — use together with a mock server (see below)
FUSION_SPA_MSAL_MOCK=true
# Optional: standalone mock-server origin used for session-scoped token acquisition
FUSION_SPA_MSAL_MOCK_SERVER_URL=http://localhost:4010

# Telemetry
FUSION_SPA_TELEMETRY_CONSOLE_LEVEL=2

# Service Worker (JSON string)
FUSION_SPA_SERVICE_WORKER_RESOURCES=[{"url":"/app-proxy","rewrite":"/@fusion-api/app","scopes":["xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/.default"]}]
```

> \[TIP\] 使用 `generateTemplateEnv` 在开发类型安全和更容易调试的过程中。 使用 `.env` 用于 CI/CD 和部署的文档.

> \[大 这个 `.env` 文件必须是在工程根中(或由 Vite 指定的目录) `envDir`) (中文(简体) ). 值来自 `.env` 文件覆盖匹配值从 `generateTemplateEnv`。 。 。 .

## 运行针对 Mock 客户端( CI / Playwright)

运行 CI 和 Playwright 套房对接独立模拟服务器,所以认证和 服务发现留在本地 :

```sh
ffc mock-server ./mocks --port 4010
ffc app dev --mock http://localhost:4010
```

设置 `FUSION_SPA_MSAL_MOCK=true` 将真实的 MSAL 客户端交换为 `@equinor/fusion-framework-module-msal/mock`,在默认的模拟用户中标出 Entra ID重定向或弹出. 混音符号没有签名,所以真正的"融合"服务拒绝了它们. `ffc app dev` 财务报告和审定财务报表 `ffc app serve` 因此,还将服务发现发送给模拟服务器 每当嘲笑的真主来临的时候 `FUSION_SPA_MSAL_MOCK_SERVER_URL`,或 `http://localhost:4010` 何时 仅限 `FUSION_SPA_MSAL_MOCK` 已经设定.

```sh
FUSION_SPA_MSAL_MOCK=true
```

> \[大 一个直接的 Vite 设置必须指向 `FUSION_SPA_SERVICE_DISCOVERY_URL` (或dev服务器的) 服务发现 URL)在模拟服务器上也. 否则,每个页面加载都会发出一个模拟符号 到真正的服务发现并失败 `401`。 。 。 .

默认为通用的模拟符号 `Test User`。要在运行时选择和切换用户,启动 带有浏览器来源的独立的模拟服务器明确允许,然后将应用程序指向它:

```sh
ffc mock-server ./mocks --port 4010 --allow-origin http://localhost:3000
ffc app dev --mock http://localhost:4010
```

这个 `--mock` 选项允许模拟认证,并向SPA提供模拟服务器 URL。 A 类 直接 Vite 设置可以通过 `FUSION_SPA_MSAL_MOCK=true` 财务报告和审定财务报表 `FUSION_SPA_MSAL_MOCK_SERVER_URL=http://localhost:4010`。 。 。 .

Playwright 和其他 cookie-aware HTTP 客户端可以通过 `createMockAuth` 从 `@equinor/fusion-openapi-mock-server`。独立模拟服务器存储用户/浏览器 为Fusion SAML要求的每套范围,上下文和发出一个未签名的OBO式符号。 这个 支持不重新启动应用程序或dev服务器而切换和平行人物;见 [剧作家指南](https://npmcn.com/package/utils/openapi-mock-server/docs/testing-with-playwright.md)。 。 。 .

模拟认证并不嘲弄API的其余表面——服务发现和 任何后端的呼号,门户网站仍然会点击真实的URL,除非您也覆盖它们. 使用 dev 服务器的 `api.routes`编号 :`api.processServices` 选项(参见 [`@equinor/fusion-framework-dev-server`](https://npmcn.com/package/dev-server/README.md) 要截取的文件 这些请求有固定的答复.

## 高级自定义

### 提供自定义模板

通过通过一个 `template` 字符串到插件中。 占位符使用 `%VAR%` 语法来源 [Vite 的 HTML 常数替换](https://vite.dev/guide/env-and-mode.html#html-constant-replacement)。 。 。 .

> \[尖叫声\] 自定义模板绕过默认结构. 您负责加载脚本, 并确保正确的文档结构 .

#### 示例自定义模板

```ts
// Define your custom HTML template
const template = `
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>%MY_CUSTOM_TITLE%</title>
    <script type="module" src="./src/my-custom-bootloader"></script>
  </head>
  <body>
    <h1>%MY_CUSTOM_PROPERTY%</h1>
    <div id="app"></div>
  </body>
</html>
`;

// Configure Vite with your custom template
import { defineConfig } from 'vite';
import { createViteSPAPlugin } from '@equinor/fusion-framework-vite-plugin-spa';

// Custom prefix for environment variables
const templateEnvPrefix = 'MY_CUSTOM_';

export default defineConfig({
  // Define environment variables to inject into the template
  define: {
    [`import.meta.env.${templateEnvPrefix}PROPERTY`]: '"my-custom-value"',
    [`import.meta.env.${templateEnvPrefix}TITLE`]: '"My Application"',
  },
  // Use the custom template with the plugin
  plugins: [createViteSPAPlugin({ template, templateEnvPrefix })],
});
```

> \[TIP\] 关于HTML模板变量替换如何在Vite工作的更详细信息,请参见: [虚拟文档](https://vite.dev/guide/env-and-mode.html#html-constant-replacement)。 。 。 .

### 提供自定义靴子

对于更多的控制,您可以指定一个处理应用程序初始化的自定义的靴子陷阱文件:

```ts
fusionSpaPlugin({
  generateTemplateEnv: () => {
    return {
      // Points to your custom bootstrap file
      bootstrap: 'src/my-custom-bootloader.ts',
    }
  }
});
```

#### 执行您的自定义启动程序

使用自定义的启动器时,您需要处理通常由默认启动器管理的所有初始化逻辑,包括服务人员注册:

```ts
// custom-bootloader.ts
import { registerServiceWorker } from '@equinor/fusion-framework-vite-plugin-spa/html';
import initializeFramework from './my-custom-framework.js';

// Initialize your framework and register the service worker
const app = await initializeFramework();
registerServiceWorker(app);

// Additional custom initialization code
document.addEventListener('DOMContentLoaded', () => {
  console.log('Application fully loaded');
});
```

> \[尖叫声\] 在使用自定义的启动器时,默认的服务工人注册会被绕过. 您必须明确打电话 `registerServiceWorker()` 如上例所示,您可以在自定义的启动器中维护此功能.

## 实例

### 基本 SPA 有反应

```ts
// vite.config.ts
import { defineConfig } from 'vite';
import { plugin as fusionSpaPlugin } from '@equinor/fusion-framework-vite-plugin-spa';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [
    react(),
    fusionSpaPlugin({
      generateTemplateEnv: () => ({
        title: 'My React App',
        portal: { id: 'my-portal' },
        serviceDiscovery: {
          url: 'https://dev-server.com/service-discovery',
          scopes: ['api://my-app/user.read'],
        },
        msal: {
          tenantId: process.env.TENANT_ID,
          clientId: process.env.CLIENT_ID,
          redirectUri: 'http://localhost:3000/auth-callback',
          requiresAuth: 'true',
        },
        telemetry: {
          consoleLevel: 2, // Show Warning, Error, and Critical events
        },
      }),
    }),
  ],
});
```

### 使用 API 服务插件

```ts
// vite.config.ts
import { defineConfig } from 'vite';
import { plugin as fusionSpaPlugin } from '@equinor/fusion-framework-vite-plugin-spa';
import { plugin as apiServicePlugin } from '@equinor/fusion-framework-vite-plugin-api-service';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [
    react(),
    fusionSpaPlugin({
      generateTemplateEnv: () => ({
        title: 'API Service Example',
        // Portal to load
        portal: {
          id: 'my-portal',
          tag: 'latest',
        },
        serviceDiscovery: {
          url: 'https://dev-server.com/service-discovery',
          scopes: ['api://my-app/user.read'],
        },
        serviceWorker: {
          resources: [
            {
              url: '/api-proxy',
              rewrite: '/@fusion-api/service',
              scopes: ['api://backend-service/.default'],
            },
          ],
        },
      }),
    }),
    // API Service plugin enables portal loading from service discovery
    apiServicePlugin(),
  ],
});
```

见 [API 服务插件文件](https://github.com/equinor/fusion-framework/tree/main/packages/vite-plugins/api-service) 更多细节.

## 解决问题

### 共同问题

| 症状 | 可能的原因是 | 修补 |
| --- | --- | --- |
| 认证失败 | 错误 `tenantId` 或者说 `clientId` | 验证 Azure AD 应用程序注册和范围配置 |
| 服务人员不拦截 | 未登记或不控制的工人 | 检查浏览器显示注册错误; 确保 `registerServiceWorker` 名为 |
| `.env` 被忽略的值 | 错误的前缀或缺少重启 | 确认 `FUSION_SPA_*` 命名; 重新启动 dev 服务器 |

### 已知问题

| 问题 | 影响 | 说明 |
| --- | --- | --- |
| [3266号](https://github.com/equinor/fusion-framework/issues/3266) | **代理资产上丢失的无记名证** | 在装入使用资产或代码分割的远程应用程序时,服务人员可能无法在请求这些资源时附加所需的Bearer令牌. 因为服务员重写 `import.url`,可以干扰资产请求的适当象征性注入。 因此,在某些情况下,受保护资产可能无法正确装载. |

### 最佳做法

-   将秘密排除在源代码之外——使用 `.env` 文件或 CI/CD 变量.
-   使用 [API 服务插件](https://github.com/equinor/fusion-framework/tree/main/packages/vite-plugins/api-service) 用于开发期间的高级代理路由.
-   在使用自定义模板或靴子拖放文件时,总是核查服务人员注册和认证流程.

## 捐款

欢迎投稿、错误报告和特性请求! 见 [捐款额](https://npmcn.com/CONTRIBUTING.md) 准则.

## 常见问题

### @equinor/fusion-framework-vite-plugin-spa 是什么？

用于 SPA 开发的 Vite 插件

### 如何安装 @equinor/fusion-framework-vite-plugin-spa？

在项目目录运行 npm install @equinor/fusion-framework-vite-plugin-spa，或使用 pnpm add / yarn add / bun add。

### @equinor/fusion-framework-vite-plugin-spa 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @equinor/fusion-framework-vite-plugin-spa 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @equinor/fusion-framework-vite-plugin-spa 可以商用吗？

@equinor/fusion-framework-vite-plugin-spa 使用 ISC 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @equinor/fusion-framework-vite-plugin-spa 的下载量有多少？

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

### @equinor/fusion-framework-vite-plugin-spa 还在维护吗？

最新版本 5\.2\.5 发布于 2026/11/12（1 天前）；至今共发布 87 个版本，其中过去 12 个月发布了 61 个；首次发布于 2025/05/27。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

