Skip to content
/ navspa Public

bibliotek for eksportering og importering av hele apper som react-komponenter

License

Notifications You must be signed in to change notification settings

navikt/navspa

Repository files navigation

navspa

npm version

Hjelpe-bibliotek for å bygge opp micro-frontends

Bruk

Antar ett system som består av tre ulike systemer; parent-app, child1-app og child2-app.

I childXX-app;

import NAVSPA from '@navikt/navspa';

interface Props {
  data: string;
}

function Application(props: Props) {
  return (
    <h1>Hei fra ChildX-app; {props.data}</h1>
  );
}

NAVSPA.eksporter('childX', Application);

I parent-app kan man så gjøre følgende;

import NAVSPA from '@navikt/navspa';
const Child1 = NAVSPA.importer<ChildProps>('child1');
const Child2 = NAVSPA.importer<ChildProps>('child2', {
    wrapperClassName: 'wrapper-classname',
    feilmelding: <Alertstripe>Feil ved innlasting av child2</Alertstripe>
});

function Wrapper() {
  return (
    <>
      <Child1 data="Data til child1" />
      <Child2 data="Data til child2" />
    </>
  );
}

Det er også mulig å importere inn child applikasjoner asynkront ved bruk av AsyncNavspa.importer. Hvis en applikasjon importeres inn async så trengs det ikke å laste inn css/js gjennom tags i html-filen til parent-appen. Istedenfor så vil async-navspa lese asset-manifest.json og finne ut hvilken filer den trenger å hente derfra. Som default så må manifestet være på samme format som det som blir opprettet av CRA, men det er mulig å overskrive parsingen av manifestet ved behov.

import { AsyncNavspa } from '@navikt/navspa';

const AsyncChild1 = AsyncNavspa.importer<ChildProps>({
    appName: 'child-1',
    appBaseUrl: 'https://url-to-microfrontend1.com/'
});

const AsyncChild2 = AsyncNavspa.importer<ChildProps>({
    appName: 'child-2',
    appBaseUrl: 'https://url-to-microfrontend2.com/',
    assetManifestParser:  (manifest: { [k: string]: any }) => {/*...*/},
    config: {
        wrapperClassName: 'wrapper-classname',
        feilmelding: <Alertstripe>Feil ved innlasting av child-2</Alertstripe>
    },
    loader: (<div>Laster child 2...</div>),
});

function Wrapper() {
  return (
    <>
        <AsyncChild1 data="Data til child1" />
        <AsyncChild2 data="Data til child2" />
    </>
  );
}

Når man bruker AsyncNavspa.importer så starter innhentingen av ressursene når komponenten først mountes. Dette vil som regel kun medføre 1 kall for å hente asset-manifestet og 1 pr ressurs (er som regel cachet ganske bra). For å gjøre innlasting raskere så er det mulig å bruke AsyncNavspa.preload. Da vil ressursene bli lastet inn asynkront slik at child appen kan rendres raskere.

import { AsyncNavspa } from '@navikt/navspa';

const config: AsyncSpaConfig = {
    appName: 'child-1',
    appBaseUrl: 'https://url-to-microfrontend1.com/',
    loader: <div>loading</div>
}

// Do the preloading somewhere before child-1 needs to be rendered
AsyncNavspa.preload(config);

const AsyncChild1 = AsyncNavspa.importer<ChildProps>(config);

function Wrapper() {
  return (
    <>
        <AsyncChild1 data="Data til child1" />
    </>
  );
}

NB Distribuering av PropTypes er ikke en del av dette biblioteket.

Bruk med create-react-app

Siden vi fjerner kallet til ReactDOM.render og heller kaller NAVSPA.eksporter så må vi gjøre noen endringer i public/index.html for å få utvikler-miljø til å fungere. Brukere kommer ikke til å komme direkte til noen av barne-appene, så endringer er kun for å gjøre utvikling av løsningen enklere.

public/index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <meta name="theme-color" content="#000000"/>
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
    <title>React App</title>
</head>
<body>
<div id="root"></div>
<script>
    NAVSPA.childXX(document.getElementById('root'), { data: 'Data til bruk under utvikling' });
</script>
</body>

Bruk med vitejs

Om man bruker vitejs for eksportering av applikasjonen sin må man passe på at manifestet blir gitt riktig navn, e.g asset-manifest.json. Dette kan gjøres ved hjelp av følgende config:

// vite.config.ts
export default defineConfig({
    build: {
        manifest: 'asset-manifest.json'
    }
});

For konsumering av applikasjoner eksportert med vitejs bør man sikre at man har @navikt/navspa >= 5.0.1, og huske å definere en assetManifestParser om man laster applikasjonen asynkront.

const asyncViteApp: AsyncSpaConfig = {
    appName: 'async-vite-app',
    appBaseUrl: 'http://url.to.your.app',
    assetManifestParser(manifest: Manifest) {
        const { file, css } = manifest['index.html'];
        const baseUrl = 'http://url.to.your.app';
        
        const script = { type: 'module', path: `${baseUrl}/${file}` };
        const styles = css.map((path) => ({ path: `${baseUrl}/${path}` }));
        
        return [ script, ...styles ];
    }
}

NB!! basert på applikasjonen man laster inn så kan det være behov for å lage en mer generisk assetmanifestparser.

Bruk av react@<18.0.0

[email protected] innførte en endring i api for rendering, som påvirker dette biblioteket. Som default antar NAVSPA at applikasjonen bruker react-dom@^18. Om man skal eksportere en applikasjon som bruker en react versjon eldre enn dette må man manuelt konfigurere NAVSPA til å håndtere dette.

import { ReactElement } from "react";
import ReactDOM from 'react-dom';

NAVSPA.setAdapter({
    render<P>(component: ReactElement<P>, element: HTMLElement) {
        ReactDOM.render(component, element);
    },
    unmount(element: HTMLElement) {
        ReactDOM.unmountComponentAtNode(element);
    }
});

Eventuelt kan man bruke pakken @navikt/navspa-react-17-adapter og følgende konfigurasjon:

NAVSPA.setAdapter(new React17Adapter());

Henvendelser

Spørsmål knyttet til koden eller prosjektet kan rettes mot:

Team Personoversikt

About

bibliotek for eksportering og importering av hele apper som react-komponenter

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Languages