Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: module federation #61

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions mf-vite/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
dist
12 changes: 12 additions & 0 deletions mf-vite/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Experimenting with [Module Federation](https://module-federation.io)

```sh
pnpm dev
```

## links

- https://module-federation.io/guide/basic/runtime.html
- https://github.com/module-federation/core
- https://github.com/module-federation/vite/pull/34
- https://github.com/MadaraUchiha-314/rollup-plugin-module-federation
9 changes: 9 additions & 0 deletions mf-vite/biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "https://biomejs.dev/schemas/1.8.1/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"linter": { "enabled": false }
}
11 changes: 11 additions & 0 deletions mf-vite/examples/host/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main"></script>
</body>
</html>
10 changes: 10 additions & 0 deletions mf-vite/examples/host/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "example-host",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
7 changes: 7 additions & 0 deletions mf-vite/examples/host/src/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function App() {
return (
<div>
<h4>Host App</h4>
</div>
);
}
67 changes: 67 additions & 0 deletions mf-vite/examples/host/src/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { init, loadRemote } from "@module-federation/runtime";
import React from "react";
import ReactDOMClient from "react-dom/client";
import { App } from "./app";

async function main() {
init({
name: "host",
remotes: [
{
name: "simple-esm",
entry: "http://localhost:5000/simple-esm/entry.js",
// RemoteEntryType
// https://github.com/module-federation/core/blob/b90fa7ded8786022d900081dd7c871f317c5e4b9/packages/runtime/src/type/config.ts#L17
type: "module",
},
{
name: "simple-manifest",
entry: "http://localhost:5000/simple-manifest/mf-manifest.json",
},
{
name: "simple-shared",
entry: "http://localhost:5000/simple-shared/entry.js",
type: "module",
},
{
name: "simple-vite",
entry: "http://localhost:5000/src/simple-vite/mf-manifest.json",
type: "module",
},
],
shared: {
react: {
lib: () => React,
},
},
});

const remoteSimpleEsm = await loadRemote<any>("simple-esm");
const remoteSimpleManifest = await loadRemote<any>("simple-manifest");
const remoteSimpleShared = await loadRemote<any>("simple-shared");
const remoteSimpleVite = await loadRemote<any>("simple-vite");

const el = document.getElementById("app")!;
ReactDOMClient.createRoot(el).render(
<>
<App />
<pre>remoteSimpleEsm.add(1, 2) = {remoteSimpleEsm.add(1, 2)}</pre>
<pre>
remoteSimpleManifest.mul(2, 3) = {remoteSimpleManifest.mul(2, 3)}
</pre>
<pre>
remoteSimpleShared.Component:{" "}
{<remoteSimpleShared.Component test="hello" />}
</pre>
<pre>remoteSimpleVite.App: {<remoteSimpleVite.App test="hello" />}</pre>
</>,
);
}

main().catch((e) => {
const el = document.createElement("pre");
el.style.color = "red";
el.textContent = e.stack;
document.body.appendChild(el);
throw e;
});
5 changes: 5 additions & 0 deletions mf-vite/examples/host/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"extends": "../../tsconfig.json",
"include": ["src", "*.ts"],
"compilerOptions": {}
}
8 changes: 8 additions & 0 deletions mf-vite/examples/host/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { defineConfig } from "vite";

export default defineConfig({
server: {
port: 4000,
strictPort: true,
},
});
11 changes: 11 additions & 0 deletions mf-vite/examples/remote/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main"></script>
</body>
</html>
10 changes: 10 additions & 0 deletions mf-vite/examples/remote/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "example-host",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
13 changes: 13 additions & 0 deletions mf-vite/examples/remote/public/simple-esm/entry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RemoteEntryExports
// https://github.com/module-federation/core/blob/b90fa7ded8786022d900081dd7c871f317c5e4b9/packages/runtime/src/type/config.ts#L138-L144
// https://github.com/module-federation/core/blob/b90fa7ded8786022d900081dd7c871f317c5e4b9/packages/runtime/src/module/index.ts#L85-L91

export async function init(shareScope, initScope, remoteEntryInitOptions) {}

export function get(id) {
return async () => ({ add });
}

function add(x, y) {
return x + y;
}
9 changes: 9 additions & 0 deletions mf-vite/examples/remote/public/simple-manifest/entry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export async function init(shareScope, initScope, remoteEntryInitOotions) {}

export function get(id) {
return () => ({ mul });
}

function mul(x, y) {
return x * y;
}
24 changes: 24 additions & 0 deletions mf-vite/examples/remote/public/simple-manifest/mf-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"// based on https://github.com/module-federation/core/blob/b90fa7ded8786022d900081dd7c871f317c5e4b9/packages/runtime/__tests__/resources/snapshot/remote1/federation-manifest.json": "",
"id": "simple-manifest",
"name": "simple-manifest",
"metaData": {
"name": "simple-manifest",
"publicPath": "http://localhost:5000/",
"buildInfo": {
"buildVersion": "custom"
},
"remoteEntry": {
"name": "entry.js",
"path": "simple-manifest",
"type": "module"
},
"types": {
"name": "index.d.ts",
"path": "./"
}
},
"remotes": [],
"shared": [],
"exposes": []
}
25 changes: 25 additions & 0 deletions mf-vite/examples/remote/public/simple-shared/entry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// RemoteEntryExports
// https://github.com/module-federation/core/blob/b90fa7ded8786022d900081dd7c871f317c5e4b9/packages/runtime/src/type/config.ts#L138-L144
// https://github.com/module-federation/core/blob/b90fa7ded8786022d900081dd7c871f317c5e4b9/packages/runtime/src/module/index.ts#L85-L91

/** @type {import("react")} */
let React;

/** @type {import("@module-federation/runtime/types").RemoteEntryExports['init']} */
export async function init(shareScope, initScope, remoteEntryInitOptions) {
React = (await shareScope.react[0].get())();
}

/** @type {import("@module-federation/runtime/types").RemoteEntryExports['get']} */
export function get(id) {
return () => ({ Component });
}

function Component(props) {
return React.createElement(
React.Fragment,
null,
`\n props = ${JSON.stringify(props)}`,
`\n import.meta.url = ${import.meta.url}`,
);
}
7 changes: 7 additions & 0 deletions mf-vite/examples/remote/src/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function App() {
return (
<div>
<h4>Remote App</h4>
</div>
);
}
9 changes: 9 additions & 0 deletions mf-vite/examples/remote/src/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import ReactDOMClient from "react-dom/client";
import { App } from "./app";

function main() {
const el = document.getElementById("app")!;
ReactDOMClient.createRoot(el).render(<App />);
}

main();
34 changes: 34 additions & 0 deletions mf-vite/examples/remote/src/simple-vite/entry.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import * as runtime from "@module-federation/runtime";
import type { RemoteEntryExports } from "@module-federation/runtime/types";

export const init: RemoteEntryExports["init"] = async (shareScope) => {
const host = runtime.init({
name: "remote-vite",
remotes: [],
shared: {
react: {
get: () => import("react").then((lib) => () => lib),
},
},
});
host.initShareScopeMap("default", shareScope);
};

export const get: RemoteEntryExports["get"] = (_id) => async () => {
const shared = await runtime.loadShare<typeof import("react")>("react");
const shared_ = shared && shared();
if (!shared_) throw new Error("no react from loadShare");

const React = shared_;

function App(props: {}) {
return React.createElement(
React.Fragment,
null,
`\n props = ${JSON.stringify(props)}`,
`\n import.meta.url = ${import.meta.url}`,
);
}

return { App };
};
24 changes: 24 additions & 0 deletions mf-vite/examples/remote/src/simple-vite/mf-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"// based on https://github.com/module-federation/core/blob/b90fa7ded8786022d900081dd7c871f317c5e4b9/packages/runtime/__tests__/resources/snapshot/remote1/federation-manifest.json": "",
"id": "simple-vite",
"name": "simple-vite",
"metaData": {
"name": "simple-vite",
"publicPath": "http://localhost:5000/",
"buildInfo": {
"buildVersion": "custom"
},
"remoteEntry": {
"name": "entry.tsx",
"path": "src/simple-vite",
"type": "module"
},
"types": {
"name": "index.d.ts",
"path": "./"
}
},
"remotes": [],
"shared": [],
"exposes": []
}
5 changes: 5 additions & 0 deletions mf-vite/examples/remote/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"extends": "../../tsconfig.json",
"include": ["src", "*.ts"],
"compilerOptions": {}
}
8 changes: 8 additions & 0 deletions mf-vite/examples/remote/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { defineConfig } from "vite";

export default defineConfig({
server: {
port: 5000,
strictPort: true,
},
});
25 changes: 25 additions & 0 deletions mf-vite/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "@hiogawa/mf-vite",
"private": true,
"type": "module",
"scripts": {
"tsc": "tsc -b",
"tsc-dev": "pnpm tsc --watch --preserveWatchOutput",
"lint": "biome check --write .",
"lint-check": "biome check .",
"dev": "pnpm --filter 'example-*' dev"
},
"devDependencies": {
"@biomejs/biome": "^1.8.3",
"@module-federation/runtime": "^0.5.1",
"@module-federation/sdk": "^0.5.1",
"@types/react": "^18.3.4",
"@types/react-dom": "^18.3.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"tsup": "^8.2.4",
"typescript": "^5.5.4",
"vite": "^5.4.2"
},
"packageManager": "pnpm@9.8.0+sha512.8e4c3550fb500e808dbc30bb0ce4dd1eb614e30b1c55245f211591ec2cdf9c611cabd34e1364b42f564bd54b3945ed0f49d61d1bbf2ec9bd74b866fcdc723276"
}
4 changes: 4 additions & 0 deletions mf-vite/packages/plugin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "mf-vite-plugin",
"private": true
}
1,796 changes: 1,796 additions & 0 deletions mf-vite/pnpm-lock.yaml

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions mf-vite/pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
packages:
- examples/*
- packages/*
16 changes: 16 additions & 0 deletions mf-vite/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"exclude": ["node_modules"],
"compilerOptions": {
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"verbatimModuleSyntax": true,
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ESNext",
"lib": ["ESNext", "DOM", "DOM.Iterable", "ESNext.AsyncIterable"],
"types": ["vite/client"],
"jsx": "react-jsx",
"noEmit": true
}
}