Резервный вариант Webpack5 Module Federation при сбое сетевого вызова
Недавно я сделал узел объединенного модуля, который объединяет верхний и нижний колонтитулы сайта. Все работает, как ожидалось, но я пытаюсь добавить несколько резервных вариантов, если запрос к федеративному хосту не удастся.
new ModuleFederationPlugin({
name: 'app',
remotes: {
app2: 'app2@https:/example.com/remoteEntry.js',
},
shared: { react: { singleton: true, eager: true }, 'react-dom': { singleton: true, eager: true } },
}),
Если я заблокирую запрос на https:/example.com/remoteEntry.js, я получу ошибку webpack, указанную ниже. В идеале я хотел бы загрузить базовый резервный заголовок или просто без заголовка, чем страница полностью умирает
(error: https://example.com/remoteEntry.js1)
while loading "./Footer" from webpack/container/reference/app2
2 ответа
Я нашел решение.
Ознакомьтесь с этой статьей https://habr.com/ru/post/554682/ - статья на русском языке, но вы можете воспользоваться переводчиком.
Обратите внимание на хук - useDynamicScript и обработчики onload и onerror
Дело в том, чтобы самостоятельно проверить, доступен ли remoteEntry.js с удаленного хоста. Если remoteEntry.js недоступен, не загружайте удаленный компонент, в противном случае попробуйте загрузить. Вероятность того, что компонент загрузится в этом случае, очень высока.
Но если при загрузке remoteEntry.js возникнет ошибка, мы ее обработаем, и ошибка в консоль не будет выкинута.
Я знаю, что это немного поздно, но я разработал это решение, и, возможно, оно может помочь кому-то еще с [защищенной электронной почтой] и федерацией модулей. Он также основан на Dynamic Remotes.
https://webpack.js.org/concepts/module-federation/#promise-based-dynamic-remotes
new ModuleFederationPlugin({
name: "app",
remotes: {
app2: `promise new Promise(resolve => {
// This part depends on how you plan on hosting and versioning your federated modules
const remoteUrlWithVersion = 'https:/example.com/remoteEntry.js'
const script = document.createElement('script')
script.src = remoteUrlWithVersion
script.onload = () => {
// the injected script has loaded and is available on window
// we can now resolve this Promise
const proxy = {
get: (request) => {
// Note the name of the module
return window.app2.get(request);
},
init: (arg) => {
try {
// Note the name of the module
return window.app2.init(arg)
} catch(e) {
console.log('remote container already initialized')
}
}
}
resolve(proxy)
}
script.onerror = (error) => {
console.error('error loading remote container')
const proxy = {
get: (request) => {
// If the service is down it will render this content
return Promise.resolve(() => () => "I'm dead");
},
init: (arg) => {
return;
}
}
resolve(proxy)
}
// inject this script with the src set to the versioned remoteEntry.js
document.head.appendChild(script);
})
`
},
exposes: {},
shared: {
...deps,
react: {
singleton: true,
eager: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
eager: true,
requiredVersion: deps["react-dom"],
},
},
}),