Reputation: 65
Does any build tool support this loading strategy, such as webpack or rollup.js.
Build every dependency to a single bundle, and when loading these dependencies, firstly search it in window['package'], if exist, use it. Otherwise dynamic load dependencies bundle to use.
Such app dependency is React, ReactDOM and UiLib.
The built result is:
React -> a.js
ReactDOM -> b.js
UiLib -> c.js
my code -> d.js
if window.React exist but window.ReactDOM and window.UiLib does not exist. d.js should dynamically load b.js and c.js and use window.React.
I know I can config React to externals, but this is a microapp used in many different apps, I'm not sure which packages exist in every global.
Upvotes: 0
Views: 142
Reputation: 21030
Nope. It is not possible directly. For a bundler, it is a binary choice between bundle or not to bundle.
Why? When a bundler encounters a library via import statements like - import React from 'react'
, it needs to know what global object it should substitute whenever it encounters react
package across the entire application dependency graph. This must happen at compile-time. Additionally, loading a library with dynamic decision at runtime means you are introducing an asynchronous behavior in your code which your components or application cannot handle readily.
There are two form factors - a library and application. As far as library is considered, this is the only way to teach bundler (either bundle it or leave it via externals
).
At an application level, you can write your own code to partially achieve what you seek with help of CDN. For this, you use externals and tell Webpack, for example, that react
will be available as global React
object on window
namespace.
Now before your library is getting consumed, you have to add a dynamic code where to check for presence of React
object.
function async initialize() {
if (!window.React) {
const React = await import(/* webpackIgnore: true */ 'https://unpkg.com/react@18/umd/react.development.js')
window.React = React;
initializeMicroapp();
} else {
initializeMicroapp();
return Promise.resolve();
}
}
Your initialize
function for microapp is async and returns a promise. This is usually the pattern to go ahead with shell + micro-frontends.
On a side note, you can use module federation approach which is actually meant to solve exactly similar use-case. With module federation, you can teach Webpack that if the host/shell provides a library, then Webpack should simply ignore its bundled copy of that library while serving only other necessary code. However, I advice caution as it is a very specific pattern and neither de-facto nor de-jure at this point. It is recommended when you are having sufficient scale and many independent teams working on same product space.
Upvotes: 1