Build and Module Federation

The rspack entry point connects an Rslib or Rsbuild compilation to the TAP package descriptor.

Use one target-specific compilation per runtime. Then assemble the outputs into one physical package.

Stable Federation Baseline

Use exact 2.8.0 versions for the Module Federation build plugin, runtime tools, and any directly installed manifest package. Mixed versions can produce a graph that builds successfully but reports an incompatible remote-entry type or manifest shape.

pnpm add -D @module-federation/rsbuild-plugin@2.8.0 @module-federation/runtime-tools@2.8.0

Keep the SDK version within the descriptor's compatibility.tapSdk range and the SDK's peer dependency ranges.

Rslib Targets with tapLib

tapLib returns an Rslib library configuration. Important options are:

  • manifest: source descriptor path, defaulting to manifest.tap.json;
  • packageTarget: descriptor target being compiled;
  • packageOutputRoot: isolated staging root for that compilation; and
  • federation: Module Federation name, exposes, and manifest settings.
rslib.config.ts
import { defineConfig } from '@rslib/core';
import { tapLib } from '@theaiplatform/miniapp-sdk/rspack';

const target = process.env.TAP_PACKAGE_TARGET;
if (target !== 'desktop' && target !== 'mobile') {
  throw new Error('Set TAP_PACKAGE_TARGET to desktop or mobile.');
}

const settings = {
  desktop: {
    name: 'example_catalog_desktop',
    expose: './ui/desktop',
    source: './src/ui/desktop.ts',
  },
  mobile: {
    name: 'example_catalog_mobile',
    expose: './ui/mobile',
    source: './src/ui/mobile.ts',
  },
}[target];

const library = tapLib({
  manifest: './manifest.tap.json',
  packageTarget: target,
  packageOutputRoot: `.tap-build/${target}`,
  federation: {
    name: settings.name,
    filename: 'remoteEntry.mjs',
    manifest: true,
    library: { type: 'module' },
    dts: false,
    exposes: {
      [settings.expose]: settings.source,
    },
  },
});

export default defineConfig({ lib: [library] });

Build each target separately:

TAP_PACKAGE_TARGET=desktop pnpm rslib build
TAP_PACKAGE_TARGET=mobile pnpm rslib build

Rsbuild Bundles with pluginTap

pluginTap is the Rsbuild integration for a supported bundle manifest or a target-specific Federation build. Pass the same manifest and Federation identity rules you would use with tapLib.

Use tapLib for an Rslib package and pluginTap for an Rsbuild application. Do not install both into the same compilation.

Assemble the Package

assembleTapPackage verifies the descriptor and every supplied target before replacing the output:

import { assembleTapPackage } from '@theaiplatform/miniapp-sdk/rspack';

await assembleTapPackage({
  manifest: './manifest.tap.json',
  output: './dist',
  targets: {
    desktop: './.tap-build/desktop',
    mobile: './.tap-build/mobile',
  },
});

The supplied target keys must exactly equal the descriptor target keys. Target roots must not overlap one another or the final output.

Assembly verifies remote entries, Federation manifests, exposes, target asset locks, shared presentation files, and final descriptor integrity. It uses a recoverable transaction so a failed or interrupted assembly does not publish half a package.

Verify Portability

Scan the final bytes before publication:

import { assertPortableTapPackageArtifacts } from '@theaiplatform/miniapp-sdk/rspack';

await assertPortableTapPackageArtifacts({
  output: './dist',
  forbiddenRoots: [process.cwd()],
});

The scan rejects symbolic links, local file URLs, and embedded checkout paths. Run it on the assembled output rather than only on source code.

Build Invariants

Before publishing, verify that:

  • each remote entry uses an ESM module library;
  • every contribution expose exists in its selected target;
  • the generated lock covers every emitted asset;
  • the descriptor contains final integrity values and one content digest;
  • no source map or debug artifact exposes a local path unless intentionally shipped; and
  • a clean project can install and build with the public SDK alone.