Tutustu JavaScript Module Federationin ajoaikaisen jaon ominaisuuksiin, sen etuihin skaalautuvien, ylläpidettävien ja yhteistyöhön perustuvien globaalien sovellusten rakentamisessa sekä käytännön toteutusstrategioihin.
JavaScript Module Federation: Ajoaikaisen jaon tehon hyödyntäminen globaaleissa sovelluksissa
Nykypäivän nopeasti kehittyvässä digitaalisessa maailmassa skaalautuvien, ylläpidettävien ja yhteistyöhön perustuvien verkkosovellusten rakentaminen on ensiarvoisen tärkeää. Kehitystiimien kasvaessa ja sovellusten monimutkaistuessa tarve tehokkaalle koodin jakamiselle ja riippuvuuksien purkamiselle kasvaa yhä kriittisemmäksi. JavaScript Module Federation, Webpack 5:n myötä esitelty mullistava ominaisuus, tarjoaa tehokkaan ratkaisun mahdollistamalla koodin ajonaikaisen jakamisen itsenäisesti julkaistujen sovellusten välillä. Tämä blogikirjoitus syventyy Module Federationin ydinajatuksiin, keskittyen sen ajoaikaisen jaon ominaisuuksiin, ja tutkii, kuinka se voi mullistaa tavan, jolla globaalit tiimit rakentavat ja hallinnoivat verkkosovelluksiaan.
Verkkokehityksen muuttuva maisema ja jakamisen tarve
Historiallisesti verkkokehitys perustui usein monoliittisiin sovelluksiin, joissa kaikki koodi sijaitsi yhdessä koodikannassa. Vaikka tämä lähestymistapa voi sopia pienempiin projekteihin, se muuttuu nopeasti hankalaksi sovellusten kasvaessa. Riippuvuudet kietoutuvat toisiinsa, käännösajat pitenevät ja päivitysten julkaiseminen voi olla monimutkainen ja riskialtis tehtävä. Mikroserviisiarkkitehtuurin nousu backend-kehityksessä tasoitti tietä vastaaville arkkitehtuurimalleille frontendissä, mikä johti mikrofrontendien syntyyn.
Mikrofrontendien tavoitteena on pilkkoa suuret, monimutkaiset frontend-sovellukset pienemmiksi, itsenäisiksi ja julkaistaviksi yksiköiksi. Tämä antaa eri tiimeille mahdollisuuden työskennellä sovelluksen eri osien parissa autonomisesti, mikä nopeuttaa kehityssyklejä ja parantaa tiimien itsenäisyyttä. Merkittävä haaste mikrofrontend-arkkitehtuureissa on kuitenkin aina ollut tehokas koodin jakaminen. Yhteisten kirjastojen, käyttöliittymäkomponenttien tai aputoimintojen kopioiminen useiden mikrofrontendien välillä johtaa:
- Suurempiin pakettikokoihin: Jokainen sovellus sisältää oman kopionsa jaetuista riippuvuuksista, mikä kasvattaa käyttäjien latauskokoa.
- Epäyhtenäisiin riippuvuuksiin: Eri mikrofrontendit saattavat käyttää saman kirjaston eri versioita, mikä johtaa yhteensopivuusongelmiin ja ennalta-arvaamattomaan käyttäytymiseen.
- Ylläpitokustannuksiin: Jaetun koodin päivittäminen vaatii muutoksia useisiin sovelluksiin, mikä lisää virheiden riskiä ja hidastaa julkaisuja.
- Hukattuihin resursseihin: Saman koodin lataaminen useita kertoja on tehotonta sekä asiakkaalle että palvelimelle.
Module Federation vastaa suoraan näihin haasteisiin esittelemällä mekanismin koodin todelliseen jakamiseen ajon aikana.
Mitä on JavaScript Module Federation?
JavaScript Module Federation, joka on toteutettu pääasiassa Webpack 5:n kautta, on käännöstyökalun ominaisuus, joka antaa JavaScript-sovellusten ladata dynaamisesti koodia muista sovelluksista ajon aikana. Se mahdollistaa useiden itsenäisten sovellusten luomisen, jotka voivat jakaa koodia ja riippuvuuksia ilman monorepoa tai monimutkaista käännösaikaista integraatioprosessia.
Ydinideana on määritellä "remote"-sovelluksia (sovelluksia, jotka tarjoavat moduuleja) ja "host"-sovelluksia (sovelluksia, jotka käyttävät moduuleja remote-sovelluksista). Nämä remote- ja host-sovellukset voidaan julkaista itsenäisesti, mikä tarjoaa merkittävää joustavuutta monimutkaisten sovellusten hallintaan ja mahdollistaa monipuoliset arkkitehtuurimallit.
Ajoaikaisen jaon ymmärtäminen: Module Federationin ydin
Ajoaikainen jako on Module Federationin voiman kulmakivi. Toisin kuin perinteiset koodin pilkkomis- tai jaettujen riippuvuuksien hallintatekniikat, jotka usein tapahtuvat käännösaikana, Module Federation antaa sovellusten löytää ja ladata moduuleja muista sovelluksista suoraan käyttäjän selaimessa. Tämä tarkoittaa, että yhteinen kirjasto, jaettu käyttöliittymäkomponenttikirjasto tai jopa ominaisuusmoduuli voidaan ladata kerran yhden sovelluksen toimesta ja asettaa sitten saataville muille sitä tarvitseville sovelluksille.
Käydään läpi, miten tämä toimii:
Avainkäsitteet:
- Exposes: Sovellus voi 'paljastaa' (expose) tiettyjä moduuleja (esim. React-komponentti, aputoiminto), joita muut sovellukset voivat käyttää. Nämä paljastetut moduulit niputetaan säiliöön (container), joka voidaan ladata etänä.
- Remotes: Moduuleja tarjoavaa sovellusta pidetään 'remotena'. Se tarjoaa moduulinsa jaetun konfiguraation kautta.
- Consumes: Sovellus, joka tarvitsee moduuleja remotelta, on 'kuluttaja' (consumer) tai 'host'. Se konfiguroidaan tietämään, mistä remote-sovellukset löytyvät ja mitkä moduulit ladataan.
- Jaetut moduulit: Module Federation mahdollistaa jaettujen moduulien määrittelyn. Kun useat sovellukset käyttävät samaa jaettua moduulia, vain yksi instanssi kyseisestä moduulista ladataan ja jaetaan niiden kesken. Tämä on kriittinen osa pakettikokojen optimointia ja riippuvuusristiriitojen ehkäisyä.
Mekanismi:
Kun host-sovellus tarvitsee moduulin remotelta, se pyytää sitä remoten säiliöstä. Remoten säiliö lataa sitten dynaamisesti pyydetyn moduulin. Jos toinen kuluttava sovellus on jo ladannut moduulin, se jaetaan. Tämä dynaaminen lataus ja jakaminen tapahtuvat saumattomasti ajon aikana, tarjoten erittäin tehokkaan tavan hallita riippuvuuksia.
Module Federationin hyödyt globaalissa kehityksessä
Module Federationin käyttöönoton edut globaalien sovellusten rakentamisessa ovat merkittäviä ja kauaskantoisia:
1. Parannettu skaalautuvuus ja ylläpidettävyys:
Pilkomalla suuren sovelluksen pienemmiksi, itsenäisiksi mikrofrontend-osioiksi Module Federation edistää luonnostaan skaalautuvuutta. Tiimit voivat työskennellä yksittäisten mikrofrontendien parissa vaikuttamatta muihin, mikä mahdollistaa rinnakkaisen kehityksen ja itsenäiset julkaisut. Tämä vähentää massiivisen koodikannan hallintaan liittyvää kognitiivista kuormitusta ja tekee sovelluksesta paremmin ylläpidettävän ajan myötä.
2. Optimoidut pakettikoot ja suorituskyky:
Ajoaikaisen jaon merkittävin hyöty on yleisen latauskoon pieneneminen. Sen sijaan, että jokainen sovellus kopioisi yleisiä kirjastoja (kuten React, Lodash tai oma käyttöliittymäkomponenttikirjasto), nämä riippuvuudet ladataan kerran ja jaetaan. Tämä johtaa:
- Nopeampiin alkuperäisiin latausaikoihin: Käyttäjät lataavat vähemmän koodia, mikä nopeuttaa sovelluksen ensimmäistä renderöintiä.
- Parempiin myöhempiin siirtymiin: Siirryttäessä riippuvuuksia jakavien mikrofrontendien välillä, jo ladattuja moduuleja käytetään uudelleen, mikä tekee käyttökokemuksesta nopeamman.
- Pienempään palvelimen kuormitukseen: Palvelimelta siirretään vähemmän dataa, mikä voi alentaa hosting-kustannuksia.
Ajatellaan globaalia verkkokauppa-alustaa, jolla on erilliset osiot tuotelistoille, käyttäjätileille ja kassalle. Jos jokainen osio on erillinen mikrofrontend, mutta ne kaikki tukeutuvat yhteiseen käyttöliittymäkomponenttikirjastoon painikkeiden, lomakkeiden ja navigoinnin osalta, Module Federation varmistaa, että tämä kirjasto ladataan vain kerran, riippumatta siitä, mihin osioon käyttäjä ensimmäisenä siirtyy.
3. Lisääntynyt tiimien autonomia ja yhteistyö:
Module Federation antaa eri tiimeille, jotka voivat sijaita eri puolilla maailmaa, mahdollisuuden työskennellä itsenäisesti omien mikrofrontend-osiensa parissa. He voivat valita omat teknologiapinonsa (kohtuuden rajoissa, ylläpitääkseen tiettyä yhtenäisyyttä) ja julkaisuaikataulunsa. Tämä autonomia edistää nopeampaa innovaatiota ja vähentää viestintäkustannuksia. Kyky jakaa yhteistä koodia kuitenkin myös kannustaa yhteistyöhön, sillä tiimit voivat osallistua ja hyötyä jaetuista kirjastoista ja komponenteista.
Kuvitellaan globaali rahoituslaitos, jolla on erilliset tiimit Euroopassa, Aasiassa ja Pohjois-Amerikassa vastuussa eri tuotetarjonnasta. Module Federation antaa jokaiselle tiimille mahdollisuuden kehittää omia erityispiirteitään samalla kun hyödynnetään yhteistä todennuspalvelua tai keskitetyn tiimin kehittämää jaettua kaaviokirjastoa. Tämä edistää uudelleenkäytettävyyttä ja varmistaa yhtenäisyyden eri tuotelinjojen välillä.
4. Teknologia-agnostisuus (varauksin):
Vaikka Module Federation perustuu Webpackiin, se sallii tietynasteisen teknologia-agnostisuuden eri mikrofrontendien välillä. Yksi mikrofrontend voisi olla rakennettu Reactilla, toinen Vue.js:llä ja kolmas Angularilla, kunhan ne sopivat siitä, miten moduuleja tarjotaan ja käytetään. Kuitenkin monimutkaisten kehysten, kuten Reactin tai Vuen, todellisessa ajonaikaisessa jakamisessa on kiinnitettävä erityistä huomiota siihen, miten nämä kehykset alustetaan ja jaetaan, jotta vältetään useiden instanssien lataaminen ja ristiriitojen syntyminen.
Globaalilla SaaS-yrityksellä saattaa olla ydinjärjestelmä, joka on kehitetty yhdellä kehyksellä, ja sen lisäksi erikoistuneita ominaisuusmoduuleja, joita eri alueelliset tiimit kehittävät muilla kehyksillä. Module Federation voi helpottaa näiden erillisten osien integrointia, edellyttäen että jaetut riippuvuudet hallitaan huolellisesti.
5. Helpompi versiohallinta:
Kun jaettu riippuvuus on päivitettävä, vain sitä tarjoava remote-sovellus on päivitettävä ja julkaistava uudelleen. Kaikki sitä käyttävät sovellukset ottavat automaattisesti uuden version käyttöön seuraavan latauksen yhteydessä. Tämä yksinkertaistaa jaetun koodin hallintaa ja päivittämistä koko sovellusmaisemassa.
Module Federationin toteutus: Käytännön esimerkkejä ja strategioita
Katsotaan, miten Module Federation otetaan käyttöön ja hyödynnetään käytännössä. Käytämme yksinkertaistettuja Webpack-konfiguraatioita havainnollistamaan ydinajatuksia.
Skenaario: UI-komponenttikirjaston jakaminen
Oletetaan, että meillä on kaksi sovellusta: 'Tuotekatalogi' (remote) ja 'Käyttäjän hallintapaneeli' (host). Molempien on käytettävä jaettua 'Button'-komponenttia erillisestä 'Shared UI' -kirjastosta.
1. 'Shared UI' -kirjasto (Remote):
Tämä sovellus tarjoaa 'Button'-komponenttinsa.
webpack.config.js
'Shared UI':lle (Remote):
const { ModuleFederationPlugin } = require('webpack');
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'remoteEntry.js',
path: path.resolve(__dirname, 'dist'),
publicPath: 'http://localhost:3001/dist/', // URL where the remote will be served
},
plugins: [
new ModuleFederationPlugin({
name: 'sharedUI',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/components/Button.js', // Expose Button component
},
shared: {
// Define shared dependencies
react: {
singleton: true, // Ensure only one instance of React is loaded
},
'react-dom': {
singleton: true,
},
},
}),
],
// ... other webpack configurations (babel, devServer, etc.)
};
src/components/Button.js
:
import React from 'react';
const Button = ({ onClick, children }) => (
);
export default Button;
Tässä asetelmassa 'Shared UI' tarjoaa Button
-komponenttinsa ja määrittelee react
ja react-dom
jaetuiksi riippuvuuksiksi asetuksella singleton: true
varmistaakseen, että niitä käsitellään yhtenä instanssina kaikissa kuluttavissa sovelluksissa.
2. 'Tuotekatalogi'-sovellus (Remote):
Tämän sovelluksen on myös käytettävä jaettua Button
-komponenttia ja jaettava omat riippuvuutensa.
webpack.config.js
'Tuotekatalogille' (Remote):
const { ModuleFederationPlugin } = require('webpack');
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'remoteEntry.js',
path: path.resolve(__dirname, 'dist'),
publicPath: 'http://localhost:3002/dist/', // URL where this remote will be served
},
plugins: [
new ModuleFederationPlugin({
name: 'productCatalog',
filename: 'remoteEntry.js',
exposes: {
'./ProductList': './src/components/ProductList.js', // Expose ProductList
},
remotes: {
// Define a remote it needs to consume from
sharedUI: 'sharedUI@http://localhost:3001/dist/remoteEntry.js',
},
shared: {
// Shared dependencies with the same version and singleton: true
react: {
singleton: true,
},
'react-dom': {
singleton: true,
},
},
}),
],
// ... other webpack configurations
};
'Tuotekatalogi' tarjoaa nyt ProductList
-komponenttinsa ja määrittelee omat remote-sovelluksensa, osoittaen erityisesti 'Shared UI' -sovellukseen. Se myös määrittelee samat jaetut riippuvuudet.
3. 'Käyttäjän hallintapaneeli' -sovellus (Host):
Tämä sovellus käyttää Button
-komponenttia 'Shared UI':sta ja ProductList
-komponenttia 'Tuotekatalogista'.
webpack.config.js
'Käyttäjän hallintapaneelille' (Host):
const { ModuleFederationPlugin } = require('webpack');
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
publicPath: 'http://localhost:3000/dist/', // URL where this app's bundles are served
},
plugins: [
new ModuleFederationPlugin({
name: 'userDashboard',
remotes: {
// Define the remotes this host application needs
sharedUI: 'sharedUI@http://localhost:3001/dist/remoteEntry.js',
productCatalog: 'productCatalog@http://localhost:3002/dist/remoteEntry.js',
},
shared: {
// Shared dependencies that must match the remotes
react: {
singleton: true,
import: 'react', // Specify the module name for import
},
'react-dom': {
singleton: true,
import: 'react-dom',
},
},
}),
],
// ... other webpack configurations
};
src/index.js
'Käyttäjän hallintapaneelille':
import React, { Suspense } from 'react';
import ReactDOM from 'react-dom';
// Dynamically import the shared Button component
const RemoteButton = React.lazy(() => import('sharedUI/Button'));
// Dynamically import the ProductList component
const RemoteProductList = React.lazy(() => import('productCatalog/ProductList'));
const App = () => {
const handleClick = () => {
alert('Button clicked from shared UI!');
};
return (
User Dashboard
Loading Button... }>
Click Me
Products
Loading Products...