O melhor portal de Marketing e Vendas para a sua empresa
O objetivo do Micro frontends é capacitar a construção, teste e implantação de peças do front-end de forma independente. Saiba mais!
Os aplicativos web estão se tornando cada vez mais complexos. Torna-se um desafio lançar softwares de maneira ágil sem sacrificar a qualidade. Como solução para essas situações, surgiu o Micro frontend. O objetivo dele é capacitar a construção, teste e implantação de peças do front-end de forma independente.
Este padrão arquitetural de micro-frontends diminui a complexidade de grandes projetos front-end, onde é possível separar um projeto extenso em partes menores com tecnologias diferentes, funcionando de forma parcialmente independente.
Essa solução é muito útil em cenários onde temos um projeto frontend com muitos times responsáveis trabalhando em apenas uma base de código. Diversos problemas podem surgir quando temos um monolito, como:
Nesses cenários, faz sentido utilizar a arquitetura para ter vantagens como:
Para exemplificar como funciona esta dinâmica de micro-frontends, iremos criar 4 aplicações rodando de forma independente e trabalhando em conjunto.
Este projeto é baseado na live “Micro Frontends com single-spa e react”, com Rodrigo Branas (arquiteto de software, professor, autor, palestrante) e Carlos Sempé (Tech Leader na ZENVIA).
Veja o vídeo completo sobre o tutorial:
Para construir nossos micro-frontends vamos utilizar o framework Single SPA. Este framework javascript permite o desenvolvimento de micro-frontends onde é possível escolher qualquer uma grande quantidade de frameworks Javascript, como React, Vue e Angular, com toda a compatibilidade de integração.
1. Será necessário ter o create-single-spa configurado.
npm install --global create-single-spa
# or
yarn global add create-single-spa
Caso você não opte por utilizar o create-single-spa globalmente, utilize um dos comandos abaixo:
npm init single-spa#
ou
npx create-single-spa#
ou
yarn create single-spa
2. Com o comando yarn create single-spa utilize as seguintes configurações para ser criado nosso projeto root.
3. Agora vamos adicionar mais uma aplicação frontend separada, que será o nosso navbar, com o comando yarn create single-spa . Adicione as seguintes configurações:
Ao clicar no link é possível ver este código, responsável por gerar a página web do projeto (entry point).
4. Agora vamos configurar o navbar no projeto root.
5. Em index.ejs no projeto root, em imports , adicione a url de entry point da navbar com o nome do projeto “@mfe/navbar”: “//localhost:8080/mfe-navbar.js:
6. Configure o arquivo mfe-root-config.ts dentro de src no projeto root, para ser integrado ao projeto navbar e apague o registerApliccation que existe. Dentro do arquivo mfe-root-config.ts definimos quando e qual projeto será utilizado em determinada rota. As tags que utilizamos são as seguintes:
import { registerApplication, start } from "single-spa";
registerApplication({
name: "@mfe/navbar",
app: () => System.import("@mfe/navbar"),
activeWhen: ["/app1"]
});
start({
urlRerouteOnly: true,
});
7. Agora vamos criar mais uma aplicação em React, rode o comando yarn create single-spa e adicione as seguintes configurações:
8. Em index.ejs dentro de src no projeto root em imports adicione a url de configuração do app1 “@mfe/app1”: “//localhost:8081/mfe-app1.js”:
9. Configure o arquivo mfe-root-config.ts dentro de src no projeto root, para ser integrado ao projeto app1.
import { registerApplication, start } from "single-spa";
registerApplication({
name: "@mfe/navbar",
app: () => System.import("@mfe/navbar"),
activeWhen: ["/app1"]
});
registerApplication({
name: "@mfe/app1",
app: () => System.import("@mfe/app1"),
activeWhen: ["/app2"],
});
start({ urlRerouteOnly: true, });
10. Para exemplificar como é feita a renderização dos componentes em tela e seu ciclo de vida (lifecycles), no arquivo mfe-app1.tsx crie uma função bootstrap, mount e unmount com o seguinte código:
import React from "react";
import ReactDOM from "react-dom";
import singleSpaReact from "single-spa-react";
import Root from "./root.component";
const lifecycles = singleSpaReact({
React,
ReactDOM,
rootComponent: Root,
errorBoundary(err, info, props) {
// Customize the root error boundary for your microfrontend here.
return null;
},
});
const { bootstrap: _bootstrap, mount: _mount, unmount: _unmount } = lifecycles;
export function bootstrap(props) {
return Promise.resolve().then(() => {
console.log(props.name, " bootstraped");
_bootstrap(props);
});
}
export function mount(props) {
return Promise.resolve().then(() => {
console.log(props.name, "mounted");
_mount(props);
});
}
export function unmount(props) {
return Promise.resolve().then(() => {
console.log(props.name, "unmonted");
_unmount(props);
});
}
11. Faça o mesmo na aplicação navbar, alterando o arquivo mfe-navbar.tsx:
import React from "react";
import ReactDOM from "react-dom";
import singleSpaReact from "single-spa-react";
import Root from "./root.component";
const lifecycles = singleSpaReact({
React,
ReactDOM,
rootComponent: Root,
errorBoundary(err, info, props) {
// Customize the root error boundary for your microfrontend here.
return null;
},
});
const { bootstrap: _bootstrap, mount: _mount, unmount: _unmount } = lifecycles;
export function bootstrap(props) {
return Promise.resolve().then(() => {
console.log(props.name, " bootstraped");
_bootstrap(props);
});
}
export function mount(props) {
return Promise.resolve().then(() => {
console.log(props.name, "mounted");
_mount(props);
});
}
export function unmount(props) {
return Promise.resolve().then(() => {
console.log(props.name, "unmonted");
_unmount(props);
});
}
12. Agora vamos criar mais um micro-frontend em vuejs chamado app2. Rode o comando yarn create single-spa e adicione as seguintes configurações:
13. Em index.ejs , no projeto root em imports, adicione a url de configuração do app2 “@mfe/app2”: “//localhost:8082/js/app.js”:
14. Configure o arquivo mfe-root-config.ts dentro de src no projeto root para ser integrado ao projeto app2 em Vuejs:
Obs. Veja que no código abaixo também alteramos para a navbar estar sempre presenta na aplicação colocando () => true
import { registerApplication, start } from "single-spa";
registerApplication({
name: "@mfe/navbar",
app: () => System.import("@mfe/navbar"),
activeWhen: () => true
});
registerApplication({
name: "@mfe/app1",
app: () => System.import("@mfe/app1"),
activeWhen: ["/app1"],
});
registerApplication({
name: "@mfe/app2",
app: () => System.import("@mfe/app2"),
activeWhen: ["/app2"],
});
start({ urlRerouteOnly: true, });
15. Entre no projeto navbar e instale a biblioteca material-ui com o comando seguinte:
yarn add @material-ui/core
16. No projeto navbar da pasta src crie um arquivo chamado App.tsx, adicione a navbar do material-ui como o seguinte código:
import React from 'react';
//@ts-ignore
import * as singleSpa from 'single-spa';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
import Typography from '@material-ui/core/Typography';
import Box from '@material-ui/core/Box';
function TabPanel(props) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
{value === index && (
<Box p={3}>
<Typography>{children}</Typography>
</Box>
)}
</div>
);
}
TabPanel.propTypes = {
children: PropTypes.node,
index: PropTypes.any.isRequired,
value: PropTypes.any.isRequired,
};
function a11yProps(index) {
return {
id: `simple-tab-${index}`,
'aria-controls': `simple-tabpanel-${index}`,
};
}
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
backgroundColor: theme.palette.background.paper,
},
}));
export default function SimpleTabs() {
const classes = useStyles();
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
switch (newValue) {
case 0:
singleSpa.navigateToUrl('app1');
break;
case 1:
singleSpa.navigateToUrl('app2');
break;
default:
break;
}
};
return (
<div className={classes.root}>
<AppBar position="static">
<Tabs value={value} onChange={handleChange} aria-label="simple tabs example">
<Tab label="App React" {...a11yProps(0)} />
<Tab label="App Vue" {...a11yProps(1)} />
</Tabs>
</AppBar>
</div>
);
}
17. Em navbar na pasta src no arquivo root.component.tsx adicione a seguinte configuração:
import SimpleTabs from "./App";
export default function Root(props) {
return SimpleTabs();
}
18. Abra seu navegador e em http://localhost:9000/, agora é possível ter acesso ao navbar com a estilização do material-ui e navegar entre os micro-frontends em React e Vuejs.
Neste tutorial aprendemos como utilizar o single-spa para a criação de micro-frontends e conseguimos ter quatro projetos front-ends rodando separadamente, com frameworks diferentes e trabalhando em conjunto de forma independente. O repositório deste projeto está disponível aqui. Continue acompanhando nosso Blog Developers e descubra novos conteúdos.
Acompanhe também o canal Dev Sempé!
*Carlos Sempé é Tech Leader na ZENVIA | Canal Dev Sempé, LinkedIn e Instagram.