I have a task.
To have Micro Frontends with single-spa framework.
- portal/main application (which load all other js code by url)
- Micro Frontend 1 (react based)
- Micro Frontend 2 (react based)
So my problem just one: I don't want to duplicate vendor libraries like react, react-dom (any others). And I want to make them shared among other Micro Frontends (which is bundled with webpack)
I know what is the bad practice to have some global stuff (it's violate the whole idea of bundeling with webpack). But how to solve the problem of duplication of vendor libraries?
I found one solution just load decencies with SystemJs like separated tags in html, but I just wonder maybe there is another solutuion for that.
Thank you.
SystemJs approach to load dependencies by demand but from CDN, I just want do the same but load all dependencies from "shared" webpack bundle with react and other stuff.
window.SystemJS = window.System
function insertNewImportMap(newMapJSON) {
const newScript = document.createElement('script')
newScript.type = 'systemjs-importmap'
newScript.text = JSON.stringify(newMapJSON)
const allMaps = document.querySelectorAll('script[type="systemjs-importmap"]')
allMaps[allMaps.length - 1].insertAdjacentElement(
'afterEnd',
newScript
)
}
const devDependencies = {
imports: {
react: 'https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.development.js',
'react-dom': 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.development.js',
'react-dom/server': 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom-server.browser.development.js',
'single-spa': 'https://unpkg.com/single-spa@4.3.2/lib/umd/single-spa.min.js',
lodash: 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js',
rxjs: 'https://unpkg.com/rxjs@6.4.0/bundles/rxjs.umd.js',
}
}
const prodDependencies = {
imports: {
react: 'https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js',
'react-dom': 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js',
'react-dom/server': 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom-server.browser.production.min.js',
'single-spa': 'https://unpkg.com/single-spa@4.3.2/lib/umd/single-spa.min.js',
lodash: 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js',
rxjs: 'https://unpkg.com/rxjs@6.4.0/bundles/rxjs.umd.min.js',
}
}
const devMode = true // you will need to figure out a way to use a set of production dependencies instead
if (devMode) {
insertNewImportMap(devDependencies)
} else {
insertNewImportMap(prodDependencies)
}
Update:
Just realized, that your question is directed at Micro Frontends (not only micro services) and therefore is not about sharing libraries with Webpack in general. Added Micro Frontend to your tags/title and updated the answer to be more focused on this topic.
What you can do is exclude dependencies from the output bundle of your Micro Frontends by adding a Webpack externals property to the config.
webpack config of your Micro Frontends:
Above config would exclude
react
andreact-dom
and expect them in the global variablesReact
andReactDOM
. You can then share those dependencies by including the libraries in a script insideindex.html
of your root applicationn aka stitching layer:If you have other common components to share, you can also integrate the library scripts in a component library.
The reason for the include as script is: We do not want that our container has to require/import the Micro Frontends at build time in order to avoid a coupling of build/release/version management between all apps. Instead one purpose of Micro Frontends is to achieve fully independent deployment of the parts, which include continuous delivery steps from build, test to release.
Of course, you create some form of coupling between the apps. But if you have a mature, stable and common library shared by all parts, it is a reasonable decision.
Hope, it helps (now)!