@appshell/webpack-plugin

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

Webpack plugin used to generate a global Appshell configuration for micro-frontends built with Module Federation

原始使用文档
文档目录7 节
  1. Getting Started
  2. A remote's configuration: appshellRemote()
  3. Publishing on build
  4. Sample output
  5. Options
  6. Options
  7. License

Appshell CI

@appshell/webpack-plugin

Emits an appshell manifest template for building micro-frontends with Appshell and Webpack Module Federation. The appshell manifest template is subseqently processed to generate an appshell manifest.

Working examples can be found here.

Getting Started

To begin, you'll need to install @appshell/webpack-plugin:

npm install @appshell/webpack-plugin --save-dev

or

yarn add -D @appshell/webpack-plugin

or

pnpm add -D @appshell/webpack-plugin

Then add the plugin to the webpack config of each remote package. For example:

webpack.config.js

const { AppshellPlugin } = require('@appshell/webpack-plugin');

module.exports = {
  plugins: [
    new AppshellPlugin({
      config: './path/to/appshell.config.yaml',
    }),
  ],
};

A remote's configuration: appshellRemote()

Most of a remote's webpack configuration isn't the author's choice: the registry and @appshell/react-shell require it of every remote. appshellRemote() returns that part, and you extend it with your own loaders, usually with webpack-merge. It needs @module-federation/enhanced installed beside it.

const { merge } = require('webpack-merge');
const { appshellRemote } = require('@appshell/webpack-plugin');
const { dependencies } = require('./package.json');

module.exports = (_env, { mode }) =>
  merge(
    appshellRemote({
      name: 'PackagesModule',
      exposes: { './Packages': './src/Packages' },
      port: 7302,
      mode,
      react: true,
      dependencies,
    }),
    {
      resolve: { extensions: ['.js', '.ts', '.tsx'] },
      module: {
        rules: [
          /* your transpiler, your CSS */
        ],
      },
    },
  );

What it sets, and what requires it:

SettingRequired by
Source maps without eval in developmentThe registry serves the shell page under a CSP that forbids eval, so development's default source maps throw before the remote runs.
publicPath: 'auto'The registry serves a remote's files under /p/<scope>/<name>/<version>/ on the application's own origin, and an overlay serves them from a dev server: the path is known only once the entry loads.
Content-hashed chunks, an unhashed remoteEntry.jsA chunk's name names its bytes, so nothing pairs a fresh entry with a stale chunk. The entry is the file the published manifest names.
A dev server with CORS, allowedHosts, and a reload socket on localhostOverlays: the page is on the application's origin and the code on localhost. The server binds every interface and would otherwise bake 0.0.0.0, which no browser can dial, into its client.
ModuleFederationPlugin with appshellShared@appshell/react-shell is the federation host and shares appshell's runtime, and with react, React and its bindings, as singletons.
AppshellPluginWrites the manifest a publish sends.

Defaults you can override:

  • The dev server covers the page only for build errors: warnings stay in the terminal, and an error thrown by something else on the page, such as a browser extension, isn't the remote's.
  • allowedHosts is 'all', since the dev server already answers every origin with CORS. Name your applications' hosts to narrow it, for example ['.appshell.org'].
  • The one warning @appshell/react's bundle causes, from its federation runtime's dynamic import, is ignored.

Not included, because they're yours: a transpiler, CSS and testing. A container's own contract isn't included either. The workspace's react-router singleton, for example, is added through shared by the remotes that contribute to it:

appshellRemote({ …, shared: { 'react-router': { singleton: true, requiredVersion: dependencies['react-router'] } } });
OptionDefaultMeaning
nameThe federation container's name, the scope its manifest names.
exposesWhat it exposes, as ModuleFederationPlugin takes it.
portThe dev server's port, for an overlay to point at.
modewebpack's mode, as its CLI passes it to a config function.
reactfalseShare React and appshell's React bindings.
dependencies{}Usually package.json's dependencies, which pin the shared ranges.
shared{}Shared beyond appshell's preset, merged last.
entrythe first exposed moduleThe build's entry.
uniqueNamenameoutput.uniqueName, which keeps two remotes' chunks apart.
allowedHosts'all'The hosts allowed to open the dev server's reload socket.
pluginOptions for AppshellPlugin.

Publishing on build

The plugin can publish the generated manifest to an Appshell registry after every successful build, so a running --watch keeps an application current as you work. Development builds publish by default — you never toggle it per project — while production builds never publish on their own.

new AppshellPlugin({
  config: './path/to/appshell.config.yaml',
  // registry / application are usually omitted — see below.
  registry: 'https://registry.example.com', // optional override
  application: 'acme/my-dev', // optional: activate the published version here
});

By default the plugin defers to your CLI context — the registry, application, and token you set with appshell config set and appshell login (stored in ~/.appshell). That's the same context the CLI uses, so one machine-level setting drives both; a project needs no per-repo configuration.

Resolution precedence, per field: explicit plugin option → APPSHELL_* env var → ~/.appshell context → default. When an option or env var points somewhere other than your persisted context, the plugin warns that it is overriding it.

FieldOptionEnv varNotes
publishpublishAPPSHELL_PUBLISH_ON_BUILDDefaults to true in development mode; set 0/false to opt out
registryregistryAPPSHELL_REGISTRYFrom CLI context by default
applicationapplicationAPPSHELL_APPLICATIONscope/name (or joined with APPSHELL_SCOPE_ID); omit to publish without activating
forceforce—Overwrite a changed version; defaults to true in dev mode
token—APPSHELL_TOKENOtherwise from ~/.appshell/credentials; never a plugin option

In CI there is no ~/.appshell, so APPSHELL_REGISTRY, APPSHELL_APPLICATION, and APPSHELL_TOKEN are the whole story. If publishing defaults on in development but no registry is resolvable, the build still succeeds — publishing is skipped with a warning.

The package is published under its npm name and version, unscoped — the registry takes the scope from your token. Publishing the same content twice is a no-op, so a watch loop that rebuilds without a version bump is harmless. Publishing different content under an existing version is normally rejected; in development mode the plugin asks the registry to overwrite it, which a local (unauthenticated) registry honors by default and a real registry refuses unless configured with ALLOW_FORCE_PUBLISH.

A failed publish is reported as a compilation error rather than thrown, so --watch reports it and keeps running.

What is appshell.config.yaml?

A configuration file consumed by the plugin to provide additional information and context to the Appshell host about remote entrypoints, routing, display names, etc.

Sample appshell.config.yaml

remotes:
  TestModule/Foo: # Must match the scope/module defined in ModuleFederationPlugin
    url: ${APPS_TEST_URL}/remoteEntry.js # Application variables will be expanded when the global runtime manifest is generated.
    metadata: # Use metadata to provide additional information
      route: ${FOO_ROUTE}
      displayName: Foo App
      displayGroup: primary
      order: 10
      icon: ViewList

  TestModule/Bar:
    url: ${APPS_TEST_URL}/remoteEntry.js
    metadata:
      route: /bar
      displayName: Bar App
      displayGroup: primary
      order: 20
      icon: ViewList

  BizModule/Biz:
    url: http://localhost:4040/remoteEntry.js
    metadata:
      route: /biz
      displayName: Biz App
      displayGroup: utility
      order: 30
      icon: ViewList

vars:
  RUNTIME_ARG_1: ${RUNTIME_ARG_1}
  RUNTIME_ARG_2: ${RUNTIME_ARG_2}
  RUNTIME_ARG_3: ${RUNTIME_ARG_3}

Note the variable expansion syntax ${CRA_MFE_URL}. When the appshell manifest is generated the actual runtime environment values are injected.

Note the vars section defines runtime configuration values a package reads with getVars() from @appshell/runtime/vars once it is loaded. The package must share @appshell/runtime as a singleton to receive them. See the examples for a use case.

What happens at build time?

The plugin emits a manifest template file that is subsequently used to generate the appshell manifest at runtime.

Sample output

{
  "remotes": {
    "CraModule/App": {
      "url": "${CRA_MFE_URL}",
      "metadata": {
        "route": "/cra",
        "displayName": "Example App",
        "displayGroup": "${CRA_MFE_DISPLAY_GROUP}",
        "order": 10,
        "icon": "ViewList"
      },
      "id": "3eb81a0c"
    }
  },
  "module": {
    "exposes": {
      "./App": "./src/App"
    },
    "filename": "remoteEntry.js",
    "name": "CraModule",
    "shared": {
      "react": {
        "singleton": true,
        "requiredVersion": "^18.2.0"
      },
      "react-dom": {
        "singleton": true,
        "requiredVersion": "^18.2.0"
      }
    }
  }
}

How do I generate the appshell manifest?

Use @appshell/cli in a startup script:

appshell generate manifest --template appshell.template.json

Sample appshell manifest:

{
  "remotes": {
    "CraModule/App": {
      "id": "3eb81a0c",
      "url": "http://localhost:3000/remoteEntry.js",
      "scope": "CraModule",
      "module": "./App",
      "metadata": {
        "route": "/cra",
        "displayName": "Example App",
        "displayGroup": "primary",
        "order": 10,
        "icon": "ViewList"
      }
    },
    "VanillaModule/Vanilla": {
      "id": "8232ce86",
      "url": "http://localhost:5000/remoteEntry.js",
      "scope": "VanillaModule",
      "module": "./Vanilla",
      "metadata": {
        "route": "/vanilla",
        "displayName": "Example React App",
        "displayGroup": "primary",
        "order": 10,
        "icon": "ViewList"
      }
    }
  },
  "modules": {
    "Appshell": {
      "name": "Appshell",
      "shared": {
        "react": {
          "singleton": true,
          "requiredVersion": "^18.2.0"
        },
        "react-dom": {
          "singleton": true,
          "requiredVersion": "^18.2.0"
        }
      }
    },
    "CraModule": {
      "exposes": {
        "./App": "./src/App"
      },
      "filename": "remoteEntry.js",
      "name": "CraModule",
      "shared": {
        "react": {
          "singleton": true,
          "requiredVersion": "^18.2.0"
        },
        "react-dom": {
          "singleton": true,
          "requiredVersion": "^18.2.0"
        }
      }
    },
    "VanillaModule": {
      "exposes": {
        "./Vanilla": "./src/App"
      },
      "filename": "remoteEntry.js",
      "name": "VanillaModule",
      "shared": {
        "react": {
          "singleton": true,
          "requiredVersion": "^18.2.0"
        },
        "react-dom": {
          "singleton": true,
          "requiredVersion": "^18.2.0"
        }
      }
    }
  },
  "vars": {
    "CraModule": {
      "RUNTIME_ARG_1": "Foo",
      "RUNTIME_ARG_2": "Biz"
    },
    "VanillaModule": {
      "RUNTIME_ARG_1": "Bar"
    }
  }
}

Options

The plugin's signature:

webpack.config.js

const { AppshellPlugin } = require('@appshell/webpack-plugin');

module.exports = {
  plugins: [
    new AppshellPlugin({
      config: './path/to/appshell.config.yaml',
    }),
  ],
};

Options

OptionTypeDefaultPurpose
configstringappshell.config.yamlLocation of the config file
registrystringCLI contextRegistry to publish to
applicationstringCLI contextApplication to activate the published version in
publishbooleantrue in developmentPublish after every successful build
forcebooleantrue in developmentAsk the registry to overwrite an existing version whose content differs

registry and application are usually omitted — see Publishing on build for the resolution order.

License

MIT

版本与发布记录

@appshell/webpack-plugin 共发布 140 个版本,首次发布于 2026/08/18;过去 12 个月发布了 140 个版本。最新版本附带 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/webpack-plugin 的常见问题

@appshell/webpack-plugin 是什么?

Webpack plugin used to generate a global Appshell configuration for micro-frontends built with Module Federation

如何安装 @appshell/webpack-plugin?

在项目目录运行 npm install @appshell/webpack-plugin,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:webpack(^5.106.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@appshell/webpack-plugin 支持 TypeScript 吗?

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

@appshell/webpack-plugin 支持 ESM 还是 CommonJS?

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

@appshell/webpack-plugin 可以商用吗?

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

@appshell/webpack-plugin 的下载量有多少?

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

@appshell/webpack-plugin 还在维护吗?

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