Explore alternatives to iframes when embedding applications as widgets in another application which serves as a host for the rest.
In order to provide more features and functionalities, some large applications allow extending them in form of an extensions, plugins, integrations or modules. Often these are just external applications embedded in the host application using iframes. This approach is widely used but it has his pros and cons. We are starting to get some, arguably, better alternatives when using modern technologies. Find more about the problem and the suggested solution on this page.
- If you have existing application with routing and everything and you don't want to change much in its setup, better use iframe
- If you have existing application but you want to expose specific functionality from it, you could consider this approach or event better, publish custom web component - e.g. (Google maps)[https://mapsplatform.google.com/resources/blog/build-maps-faster-web-components/]
- If you starting from scratch you could consider this approach
- Node - 20.10.0
- NPM - 10.2.3
The host and all embedded applications are placed at the root directory of the project for ease of use but each of them could have separate repository and has his own build setup.
Every application have to build and served separately, if you want everything to work together.
# Navigate to the folder of the application you want to run
$ cd host
# Build the application
$ npm run build
# Serve the application
$ npm run preview
# Run the application in dev mode for local development
$ npm run dev
Port | Name |
---|---|
30100 | app-vanilla |
30200 | app-react |
30300 | stores |
- Shadow DOM (could be declarative or over JS API) to encapsulate the application and to isolate styles
- Importmap - Allows using bare module names for dependency and microfrontends imports
- URL ESM imports in the host - Helps with loading remote ES modules
- App as ESM export (bundled as a Library) using Vite
- esm.sh CDN for the shared dependencies
- Bundle to ESM (as library)
- Host the child application with CORS origin set to the host application URL
- Use static port which is inline with the host setup and don't conflict with other embedded apps
- Define shared packages as peerDependencies and copy them to devDependencies as well
- Use absolute URLs for linking static assets
- Each application has reserved element in host where it will be running. The selector for this element is used to add a Shadow DOM and to know where to insert styles
- Element selector/ID from the host should be provided to the embedded application for using in the import styles script (build setup)
- E.g.
data-embedded-app-name="app-react"
,#app-react
- Vite Plugin and custom setup is used for inserting the remote styles in the host Shadow DOM
- E.g.
- Each application should export bootstrap function which takes care initialization
- Each application should limit its interactions with
document
,body
orwindow
because it is going to be placed in a Shadow DOM - Each application should limit the styles it puts on
html
andbody
because it is going to be placed in a Shadow DOM