bluebell
v0.0.19
Published
A micro-frontend framework inspired by and compatible with single-spa
Downloads
52
Maintainers
Readme
bluebell
English | 简体中文
A high concurrency micro-frontend framework inspired by and compatible with single-spa.
features
- [x] Compatible with single-spa
- [x] Support multiple instances
- [x] Support router & manual modes
- [x] Support safe destroying
- [x] Support safe nested
- [x] Support async navigation cancelation
- [x] Fast reaction in concurrency
- [x] Multiple types of application entry
- [x] Support built-in ESM loading
- [x] Support unified resources management
- [x] Support more chances for retry
- [x] Support keep alive
- [x] Support preload(intelligent optional)
- [x] Support dead loop detect
- [ ] Support sandbox
- [ ] Support shadow DOM
- [ ] Support iframe
usage
router mode
const { RouterContainer } from 'bluebell';
const container = new RouterContainer({
name: 'top',
root: '#app',
fallbackUrl: '/foo',
fallbackOnlyWhen: loc => loc.pathname === '/',
cancelActivateApp: (app) => Promise.resolve(false),
});
const [fooApp, barApp, bazApp] = container.registerApps([
{
// use entry
name: 'foo',
entry: '/foo-config/assets.json',
activeWhen: '/foo',
},
{
// use assetsMap
name: 'bar',
entry: '/foo-config/assets.json',
assetsMap: { module: 'esm', initial: {}, async: {} },
activeWhen: (location: Location) => location.pathname.startsWith('/foo'),
},
{
// use lifecycle
name: 'baz',
lifecycle: {
mount: async () => {},
unmount: async () => {},
bootstrap: async () => {},
},
activeWhen: ['/baz', '/bas'],
}
]);
container.on('appactivating', ({ appname }) => {});
container.on('appactivated', ({ appname }) => {});
container.on('appactivateerror', ({ appname, error }) => {});
container.on('noappactivated', ({ error }) => {}); // No emitted if fallback.
container.run();
await container.destroy();💡 Once a RouterContainer starts running, a popstate event will be dispatched after
pushStateorreplaceStatecalled, which changes the default behavior of browser.
manual mode
const { ManualContainer } from 'bluebell';
const container = new ManualContainer({
name: 'top',
root: '#app',
});
const [fooApp, barApp, bazApp] = container.registerApps([
{
// use entry
name: 'foo',
entry: '/foo-config/assets.json',
},
{
// use assetsMap
name: 'bar',
entry: '/foo-config/assets.json',
assetsMap: { module: 'esm', initial: {}, async: {} },
},
{
// use lifecycle
name: 'baz',
lifecycle: {
mount: async () => {},
unmount: async () => {},
bootstrap: async () => {},
},
}
]);
container.on('appactivating', ({ appname }) => {});
container.on('appactivated', ({ appname }) => {});
container.on('appactivateerror', ({ appname, error }) => {});
container.on('noappactivated', ({ error }) => {});
await container.activateApp('foo');
await container.destroy();events
fooApp.on('beforestart', () => {});
fooApp.on('afterstart', () => {});
fooApp.on('starterror', ({ error: AppError; prevState: AppState }) => {});
fooApp.on('beforestop', () => {});
fooApp.on('afterstop', () => {});
fooApp.on('stoperror', ({ error: AppError; prevState: AppState }) => {});
fooApp.on('beforeupdate', () => {});
fooApp.on('afterupdate', () => {});
fooApp.on('updateerror', ({ error: AppError; prevState: AppState }) => {});
fooApp.on('beforeunload', () => {});
fooApp.on('afterunload', () => {});
fooApp.lifecycle.on('beforeload'), () => {});
fooApp.lifecycle.on('afterload'), () => {});
fooApp.lifecycle.on('loaderror'), ({ error: AppError }) => {});
fooApp.lifecycle.on('beforebootstrap'), () => {});
fooApp.lifecycle.on('afterbootstrap'), () => {});
fooApp.lifecycle.on('bootstraperror'), ({ error: AppError }) => {});
fooApp.lifecycle.on('beforemount'), () => {});
fooApp.lifecycle.on('aftermount'), () => {});
fooApp.lifecycle.on('mountinterrupted'), ({ error: AppError }) => {});
fooApp.lifecycle.on('mounterror'), ({ error: AppError }) => {});
fooApp.lifecycle.on('beforeunmount'), () => {});
fooApp.lifecycle.on('afterunmount'), () => {});
fooApp.lifecycle.on('unmounterror'), ({ error: AppError }) => {});
fooApp.lifecycle.on('beforeupdate'), () => {});
fooApp.lifecycle.on('afterupdate'), () => {});
fooApp.lifecycle.on('updateinterrupted'), ({ error: AppError }) => {});
fooApp.lifecycle.on('updateerror'), ({ error: AppError}) => {});strict vs loose
container.registerApps([
{
name: 'foo',
strict: true,
// HTML entry
entry: 'http://localhost:9000',
},
]);In loose mode, app tries to load CSS and JavaScript by creating HTML tags, otherwise by loading and evalating source code.
App is in loose mode by default.
