I'm trying to use import maps with React and Vite. I have a React Vite application called app1 with the following vite.config.ts:
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { resolve } from "node:path";
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
build: {
target: "esnext",
manifest: true,
rollupOptions: {
input: {
[process.env.npm_package_name!]: resolve(__dirname, "src/main.tsx"),
},
external: ["react", "react-dom"],
output: {
globals: {
react: "React",
"react-dom": "React-dom",
"react/jsx-runtime": "react/jsx-runtime",
},
},
},
},
});
This configuration generates the JavaScript and CSS files, as well as the manifest. After building, I upload the files to a local CDN server. When I navigate to http://localhost:8080/app1-D0fBYSKJ.js, I can correctly see the built code.
I also have a shell application that loads this app. To import the import map, I use the following code in the index.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<script type="module">
async function loadAndApplyImportMap() {
const response = await fetch(`${import.meta.env.VITE_SERVER_URL}/get-import-map`);
if (!response.ok) {
throw new Error(`Response status: ${response.status}`);
}
const importMap = await response.json();
const script = document.createElement("script");
script.type = "importmap";
script.textContent = JSON.stringify(importMap);
document.head.prepend(script);
}
try {
await loadAndApplyImportMap();
import("./src/main.tsx");
} catch (error) {
console.error(error.message);
}
</script>
</head>
<body>
<div id="root"></div>
</body>
</html>
When I call get-import-map, I receive the apps in this format:
{
"imports": {
"app1": "http://localhost:8080/app1-D0fBYSKJ.js",
"app2": "http://localhost:8080/app2-nsuvAHz_.js"
}
}
I then attempt to load the application using the following code:
const RemoteComponentLoader = ({ packageName }: { packageName: string }) => {
const Component = lazy(() => import(packageName));
return (
<Suspense fallback={<div>Loading...</div>}>
<Component />
</Suspense>
);
};
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<RemoteComponentLoader packageName="app1" />
</React.StrictMode>
);
However, I am encountering the following error:
Uncaught TypeError: Failed to resolve module specifier 'app1'
What else am I missing? What are the steps to make import maps work with React and Vite? I couldn't find an example of this approach, where I can build and import my applications using import maps.
I found this article: You Might Not Need Module Federation: Orchestrate your Microfrontends at Runtime with Import Maps | Mercedes-Benz.io, which is exactly what I want but it uses Vue and it didn't seem to work using React and Vite.