Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
0573749
feat: add import map entry support
cursoragent Feb 8, 2026
4c9e132
docs: add import map optimization flag
cursoragent Feb 8, 2026
ce7f19c
docs: document import map optimization
cursoragent Feb 8, 2026
578bd15
chore: disable import map in bundle-size config
cursoragent Feb 8, 2026
0895e94
chore: add changeset for import map support
cursoragent Feb 8, 2026
afe5b54
feat: default disable import map in plugins
cursoragent Feb 9, 2026
5613323
feat: add import map demo apps
cursoragent Feb 9, 2026
ce45596
feat: use script-based build for import map apps
cursoragent Feb 9, 2026
10578b3
chore: drop nx cypress config for import-map app
cursoragent Feb 9, 2026
ee9d68e
Merge remote-tracking branch 'origin/main' into cursor/runtime-core-f…
ScriptedAlchemy Feb 9, 2026
a3d9ed1
Merge remote-tracking branch 'origin/main' into cursor/runtime-core-f…
ScriptedAlchemy Feb 9, 2026
343be8b
feat: support shared import specifiers
cursoragent Feb 9, 2026
bbc68a2
fix(runtime-core): avoid implicit any in importmap getter
ScriptedAlchemy Feb 9, 2026
fc8d9eb
Merge remote-tracking branch 'origin/main' into cursor/runtime-core-f…
ScriptedAlchemy Feb 12, 2026
ad9a9f4
chore(core): add changeset coverage for pr #4390
ScriptedAlchemy Feb 12, 2026
02b682f
chore(runtime-core): remove redundant auto changeset
ScriptedAlchemy Feb 12, 2026
9ad3668
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Feb 14, 2026
62aca2a
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Feb 14, 2026
b0c892e
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Feb 15, 2026
c16e603
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Feb 15, 2026
9c88a4c
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Feb 16, 2026
3b8b7cb
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Feb 19, 2026
e05fb33
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Feb 19, 2026
e278538
Merge remote-tracking branch 'origin/main' into cursor/runtime-core-f…
ScriptedAlchemy Feb 24, 2026
324c01b
fix(dts-plugin): align workspace entrypoints and RawSource typing
ScriptedAlchemy Feb 24, 2026
7c45ef8
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Feb 25, 2026
7fea2f4
fix(bundle-size): restore valid webpack config closure
ScriptedAlchemy Feb 25, 2026
8332782
fix(sdk): align package entrypoints with emitted artifacts
ScriptedAlchemy Feb 25, 2026
75eaa63
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Feb 25, 2026
1d651bf
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Feb 26, 2026
0667f2f
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Feb 26, 2026
08bc3bb
chore: merge main into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Feb 27, 2026
b575b3d
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Feb 27, 2026
7859277
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Feb 28, 2026
64cd97f
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Feb 28, 2026
e22855d
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Mar 2, 2026
63bf4be
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Mar 3, 2026
076b165
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Mar 5, 2026
148cd34
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Mar 9, 2026
0a0c44c
Merge branch 'main' into cursor/runtime-core-federation-importmaps-556d
ScriptedAlchemy Mar 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .changeset/clean-cobras-rest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"@module-federation/runtime-core": patch
"@module-federation/enhanced": patch
"@module-federation/rspack": patch
"@module-federation/sdk": patch
---

Add import map remote entry support in runtime-core with a tree-shakeable
`FEDERATION_OPTIMIZE_NO_IMPORTMAP` flag, and expose `disableImportMap`
in Module Federation plugin optimization options (defaulting to `true`
in build plugins).

Shared modules now honor the `import` field to load shared dependencies
via dynamic import (including bare specifiers resolved by import maps).
26 changes: 26 additions & 0 deletions apps/import-map/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Import Map Runtime Demo

This example demonstrates using `@module-federation/runtime-core` with an
import map. The host (app1) loads the remote (app2) by using a bare specifier
mapped in the import map.

## Running the demo

Start both apps in separate terminals:

```bash
pnpm --filter import-map-app2 run build
pnpm --filter import-map-app2 run serve

pnpm --filter import-map-app1 run build
pnpm --filter import-map-app1 run serve
```

- Host: http://127.0.0.1:3101
- Remote entry (import map target): http://127.0.0.1:3102/remoteEntry.js

## E2E

```bash
pnpm --filter import-map-app1 run test:e2e
```
9 changes: 9 additions & 0 deletions apps/import-map/app1/cypress.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const { defineConfig } = require('cypress');

module.exports = defineConfig({
e2e: {
specPattern: 'cypress/e2e/**/*.cy.{js,ts,jsx,tsx}',
supportFile: 'cypress/support/e2e.ts',
},
defaultCommandTimeout: 20000,
});
10 changes: 10 additions & 0 deletions apps/import-map/app1/cypress/e2e/import-map.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
describe('import-map runtime host', () => {
beforeEach(() => cy.visit('/'));

it('loads the remote module via import map', () => {
cy.get('[data-test="status"]').contains('Loaded');
cy.get('[data-test="remote-message"]').contains(
'Hello from import map remote',
);
});
});
3 changes: 3 additions & 0 deletions apps/import-map/app1/cypress/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "import-map"
}
14 changes: 14 additions & 0 deletions apps/import-map/app1/cypress/support/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/// <reference types="cypress" />

// eslint-disable-next-line @typescript-eslint/no-namespace
declare namespace Cypress {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Chainable<Subject> {
login(email: string, password: string): void;
}
}

Cypress.Commands.add('login', (email, password) => {
void email;
void password;
});
6 changes: 6 additions & 0 deletions apps/import-map/app1/cypress/support/e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// ***********************************************************
// This example support/e2e.ts is processed and
// loaded automatically before your test files.
// ***********************************************************

import './commands';
20 changes: 20 additions & 0 deletions apps/import-map/app1/cypress/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"allowJs": true,
"outDir": "../../../dist/out-tsc",
"module": "commonjs",
"types": ["cypress", "node"],
"sourceMap": false
},
"include": [
"**/*.ts",
"**/*.js",
"../cypress.config.js",
"../**/*.cy.ts",
"../**/*.cy.tsx",
"../**/*.cy.js",
"../**/*.cy.jsx",
"../**/*.d.ts"
]
}
15 changes: 15 additions & 0 deletions apps/import-map/app1/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "import-map-app1",
"private": true,
"version": "0.0.0",
"scripts": {
"build": "webpack --config ./webpack.config.js --mode=development",
"build:prod": "webpack --config ./webpack.config.js --mode=production",
"serve": "node ../serve-static.js --root ./dist --port 3101",
"e2e": "cypress run --config-file ./cypress.config.js --config baseUrl=http://127.0.0.1:3101 --browser chrome",
"test:e2e": "concurrently -k \"pnpm --filter import-map-app2 run build\" \"pnpm --filter import-map-app1 run build\" \"pnpm --filter import-map-app2 run serve\" \"pnpm --filter import-map-app1 run serve\" \"wait-on http://127.0.0.1:3102/remoteEntry.js http://127.0.0.1:3101 && pnpm --filter import-map-app1 run e2e\""
},
"devDependencies": {
"@module-federation/runtime-core": "workspace:*"
}
}
21 changes: 21 additions & 0 deletions apps/import-map/app1/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Import Map Runtime Host</title>
<script type="importmap">
{
"imports": {
"import_map_remote": "http://127.0.0.1:3102/remoteEntry.js"
}
}
</script>
</head>
<body>
<main id="root">
<h1>Import Map Runtime Host</h1>
<p data-test="status">Idle</p>
<p data-test="remote-message">Waiting for remote...</p>
</main>
</body>
</html>
48 changes: 48 additions & 0 deletions apps/import-map/app1/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { ModuleFederation } from '@module-federation/runtime-core';

const statusEl = document.querySelector('[data-test="status"]');
const messageEl = document.querySelector('[data-test="remote-message"]');

const setStatus = (message: string) => {
if (statusEl) {
statusEl.textContent = message;
}
};

const setMessage = (message: string) => {
if (messageEl) {
messageEl.textContent = message;
}
};

const federation = new ModuleFederation({
name: 'import-map-host',
remotes: [
{
name: 'import_map_remote',
entry: 'import_map_remote',
type: 'module',
entryFormat: 'importmap',
},
],
shared: {},
});

const loadRemoteMessage = async () => {
try {
setStatus('Loading remote...');
const remoteModule = await federation.loadRemote<{
default?: () => string;
}>('import_map_remote/hello');

const message =
remoteModule?.default?.() ?? 'Remote module did not return a message.';
setMessage(message);
setStatus('Loaded');
} catch (error) {
setStatus('Failed');
setMessage(`Error loading remote: ${String(error)}`);
}
};

void loadRemoteMessage();
16 changes: 16 additions & 0 deletions apps/import-map/app1/tsconfig.app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"types": ["node"]
},
"exclude": [
"jest.config.ts",
"**/*.spec.ts",
"**/*.test.ts",
"**/*.spec.js",
"**/*.test.js",
"dist/**"
],
"include": ["**/*.ts"]
}
19 changes: 19 additions & 0 deletions apps/import-map/app1/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": "./",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"files": [],
"references": [
{
"path": "./tsconfig.app.json"
}
]
}
50 changes: 50 additions & 0 deletions apps/import-map/app1/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
entry: path.resolve(__dirname, 'src/index.ts'),
devtool: false,
experiments: {
outputModule: true,
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js',
publicPath: 'http://127.0.0.1:3101/',
module: true,
scriptType: 'module',
clean: true,
},
resolve: {
extensions: ['.ts', '.js'],
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: {
loader: 'swc-loader',
options: {
jsc: {
parser: {
syntax: 'typescript',
},
target: 'es2021',
},
},
},
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'src/index.html'),
scriptLoading: 'module',
}),
],
optimization: {
runtimeChunk: false,
splitChunks: false,
},
};
13 changes: 13 additions & 0 deletions apps/import-map/app2/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "import-map-app2",
"private": true,
"version": "0.0.0",
"scripts": {
"build": "webpack --config ./webpack.config.js --mode=development",
"build:prod": "webpack --config ./webpack.config.js --mode=production",
"serve": "node ../serve-static.js --root ./dist --port 3102"
},
"devDependencies": {
"@module-federation/enhanced": "workspace:*"
}
}
3 changes: 3 additions & 0 deletions apps/import-map/app2/src/hello.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const hello = () => 'Hello from import map remote';

export default hello;
10 changes: 10 additions & 0 deletions apps/import-map/app2/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Import Map Remote</title>
</head>
<body>
<main id="root">Import Map Remote</main>
</body>
</html>
5 changes: 5 additions & 0 deletions apps/import-map/app2/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const root = document.getElementById('root');

if (root) {
root.textContent = 'Import Map Remote is running.';
}
16 changes: 16 additions & 0 deletions apps/import-map/app2/tsconfig.app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"types": ["node"]
},
"exclude": [
"jest.config.ts",
"**/*.spec.ts",
"**/*.test.ts",
"**/*.spec.js",
"**/*.test.js",
"dist/**"
],
"include": ["**/*.ts"]
}
19 changes: 19 additions & 0 deletions apps/import-map/app2/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": "./",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"files": [],
"references": [
{
"path": "./tsconfig.app.json"
}
]
}
Loading
Loading