@appshell/runtime

中文文档
1.0.0-alpha.148发布于 2026/10/30MITTypeScriptCommonJS零依赖构建来源已验证近 30 天下载 6884

The shared singleton that delivers a package's runtime configuration to it

原始使用文档
文档目录5 节
  1. @appshell/runtime/vars
  2. Contract
  3. The composition: getRemotes and getBasePath
  4. What this does and does not fix
  5. Setup

@appshell/runtime

The store that delivers a package's runtime configuration (vars) to it.

This is a shared singleton. There is exactly one instance per page, held in the module federation share scope, and both the host and every package must declare it as such. It replaced window.__appshell_vars__<scope>.

Most packages should not import this directly — use @appshell/runtime/vars below, which supplies the scope for you.

@appshell/runtime/vars

The accessor most packages actually want. It reads this package's vars, with no scope to pass and no way to name someone else's:

import { getVars } from '@appshell/runtime/vars';

const { BACKGROUND_COLOR } = getVars<{ BACKGROUND_COLOR: string }>();

It is a subpath rather than a main-entry export for a reason. AppshellPlugin compiles the package's own scope into whatever imports it, and the main entry is the shared module — one instance for the whole page — so a scope baked in there would be one package's, and every other package would read the wrong vars.

The exact-match share key '@appshell/runtime' does not catch '@appshell/runtime/vars', so each package bundles its own copy of the accessor with its own scope, while the store they all reach stays the single shared instance.

getVars throws MissingScopeError when the package was built without AppshellPlugin, since nothing substituted the scope.

Contract

setVars(scope, vars); // the host, immediately before loading a remote
readVars(scope); // a package, reading its own configuration
hasVars(scope); // branch instead of catch

@appshell/loader calls setVars before it loads a remote, so a package's vars are in place before its modules evaluate — including a read at module-eval time.

The first write for a scope wins and is frozen. Re-delivering the identical vars is a no-op, because the same remote can be mounted more than once; replacing them throws VarsConflictError.

readVars throws MissingVarsError rather than returning an empty object. A package that silently renders with no configuration is the failure this replaced.

The composition: getRemotes and getBasePath

What a container needs from the page to lay an application out. The workspace, for one, builds its navigation and its routes from them:

import { getBasePath, getRemotes } from '@appshell/runtime';

// Every activated remote, keyed as RemoteSlot mounts it (`scope/package/Component`),
// with the metadata its package published.
const remotes = getRemotes<{ route?: string; displayName?: string }>();

// The path the application is served under, for the router's base.
const basename = getBasePath();

They read the composition the registry inlines into the page, and expose those two parts only: a package's vars come through @appshell/runtime/vars, and the rest of the payload is the shell's.

Appshell never reads metadata, so its keys are whatever the container reading them defines. The type you pass getRemotes is not checked, so validate what you read.

Both throw MissingCompositionError on a page with no composition, rather than returning an empty list that would render a navigation with nothing in it. In a test, set window.__appshell_config__ to the composition you want.

What this does and does not fix

Against the global it replaced, it fixes: unbounded, never-cleaned-up keys; silent cross-package overwrite; the load-order coupling between host and remote; and being untyped and undiscoverable.

It does not make a scope's vars private. Any code on the page can call readVars('SomeOtherScope'), and a package that loads early can squat on a scope that has not been delivered yet. Nothing short of a separate realm — an iframe, a worker — would change that, and none of this is a security boundary. Do not put a secret in vars; the registry serves them to the browser in the composition either way.

Setup

Both sides declare it, or each ends up with its own empty store:

new ModuleFederationPlugin({
  shared: {
    '@appshell/runtime': { singleton: true },
  },
});

AppshellPlugin fails the build when a package omits it.

版本与发布记录

@appshell/runtime 共发布 131 个版本,首次发布于 2026/08/27;过去 12 个月发布了 131 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.0.0-alpha.148latest2026/10/309 天前
1.0.0-alpha.1472026/10/2910 天前
1.0.0-alpha.1462026/10/2810 天前
1.0.0-alpha.1452026/10/2810 天前
1.0.0-alpha.1442026/10/2712 天前
1.0.0-alpha.1432026/10/2613 天前

关于 @appshell/runtime 的常见问题

@appshell/runtime 是什么?

The shared singleton that delivers a package's runtime configuration to it

如何安装 @appshell/runtime?

在项目目录运行 npm install @appshell/runtime,或使用 pnpm add / yarn add / bun add。

@appshell/runtime 支持 TypeScript 吗?

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

@appshell/runtime 支持 ESM 还是 CommonJS?

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

@appshell/runtime 可以商用吗?

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

@appshell/runtime 的下载量有多少?

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

@appshell/runtime 还在维护吗?

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