單體應用對比前端微服務化
普通的前端單體應用

微前端架構

1.基本概念
實現一套微前端架構,可以把其分成四部分(參考:https://alili.tech/archive/11052bf4/)
加載器:也就是微前端架構的核心,主要用來調度子應用,決定何時展示哪個子應用, 可以把它理解成電源。
包裝器:有了加載器,可以把現有的應用包裝,使得加載器可以使用它們,它相當於電源適配器。
主應用:一般是包含所有子應用公共部分的項目—— 它相當於電器底座
子應用:眾多展示在主應用內容區的應用—— 它相當於你要使用的電器
所以是這么個概念:電源(加載器)→電源適配器(包裝器)→️電器底座(主應用)→️電器(子應用)️
總的來說是這樣一個流程:用戶訪問index.html后,瀏覽器運行加載器的js文件,加載器去配置文件,然后注冊配置文件中配置的各個子應用后,首先加載主應用(菜單等),再通過路由判定,動態遠程加載子應用。
2.預備知識
2.1 SystemJs
SystemJS提供通用的模塊導入途徑,支持傳統模塊和ES6的模塊。
SystemJs有兩個版本,6.x版本是在瀏覽器中使用的,0.21版本的是在瀏覽器和node環境中使用的,兩者的使用方式不同。(參考:https://github.com/systemjs/systemjs)
在微服務中主要充當加載器的角色。
2.2 singleSpa
single-spa是一個在前端應用程序中將多個javascript應用集合在一起的框架。主要充當包裝器的角色。(參考:https://single-spa.js.org/docs/getting-started-overview.html)
3.微服務實踐
3.1 創建應用
首先創建一個主應用iframe,這個主應用只需要簡單的起一個服務訪問靜態資源即可。
用npm init初始化,創建一個index.html,簡單寫個hello world,安裝依賴 npm i serve --s。
在package.json中的scripts中增加啟動命令"serve": "serve -s -l 7000"。運行后可以看到hello world。
然后在創建3個子應用,我用的是vue-cli2.0,分別創建navbar應用(用來寫路由),program1(應用1),program2(應用2)。
navbar應用中只放兩個鏈接就好了,如圖:

子應用program1和program2的路由都相應的加上項目名稱前綴,都增加一個about路由來作為子應用的路由切換,大致如下:


3.2 改造子應用
首先包裝子應用,各個子應用都需要安裝依賴 npm i single-spa-vue systemjs-webpack-interop,修改入口文件main.js如下:

其中 single-spa-vue是針對vue項目的包裝器,systemjs-webpack-interop是社區維護的npm庫,它可以幫助您使webpack和systemjs一起正常工作。
除此之外還需要在webpack配置中的output中增加設置

3.3 修改主應用文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<meta name="importmap-type" content="systemjs-importmap">
<script type="systemjs-importmap">
{
"imports": {
"navbar": "http://localhost:8080/app.js",
"program1": "http://localhost:8081/app.js",
"program2": "http://localhost:8082/app.js",
"single-spa": "https://cdnjs.cloudflare.com/ajax/libs/single-spa/4.3.7/system/single-spa.min.js"
}
}
</script>
<link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/single-spa/4.3.7/system/single-spa.min.js" as="script" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/system.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/amd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/named-exports.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/named-register.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/use-default.min.js"></script>
</head>
<body>
<script>
(function(){
System.import('single-spa')
.then((res)=>{
var singleSpa=res;
singleSpa.registerApplication('navbar',()=>System.import('navbar'),location=>true);
singleSpa.registerApplication('program1',()=>System.import('program1'),(location)=>{
return location.hash.startsWith(`#/program1`);
});
singleSpa.registerApplication('program2',()=>System.import('program2'),(location)=>{
return location.hash.startsWith(`#/program2`);
});
singleSpa.start();
})
})()
</script>
</body>
</html>
4.項目整合
以上只是在開發環境中使用,接下來嘗試不分別啟動服務,只啟用一個服務來跑項目。大體思路是使用express搭建一個服務,將子應用全部打包到項目上作為靜態資源訪問,入口html使用ejs模板來實現項目配置,而不再寫死。
4.1 使用express生成器生成項目
4.2 修改子應用打包配置

這樣子應用就全部打包到express應用中作為靜態資源使用了。
4.3 增加應用配置文件
將iframe的index.html的內容復制到express的入口ejs中。增加配置文件apps.config.json和apps.config.js。

apps.config.js作用就是根據apps.config.json在靜態資源文件夾下生成一份新的配置文件,將配置文件中的資源名稱通過正則匹配成完整的資源路徑。並且監聽文件變化來更新靜態資源文件夾下的配置文件。
生成的配置文件

4.4根據這個生成的配置文件去修改ejs,將項目注冊過程循環出來,而不再是寫死的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<meta name="importmap-type" content="systemjs-importmap">
<script type="systemjs-importmap">
{
"imports": {
<%for(var i=0;i<apps.length;i++){%>
"<%= apps[i].name %>":"<%= apps[i].server %><%=apps[i].resourceEntryUrl %>",
<%}%>
"single-spa": "https://cdnjs.cloudflare.com/ajax/libs/single-spa/4.3.7/system/single-spa.min.js"
}
}
</script>
<link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/single-spa/4.3.7/system/single-spa.min.js" as="script" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/system.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/amd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/named-exports.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/named-register.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/6.1.1/extras/use-default.min.js"></script>
</head>
<body>
<script>
(function(){
Promise.all([
System.import('single-spa'),
System.import('./apps.config.json')
])
.then((res)=>{
var singleSpa=res[0];
var configs=res[1].default;
configs.apps.forEach( project => {
if(project.resource.length>0){
Promise.all(project.resource.map(i=>{
return System.import(project.server+i)
})).then(function(){
singleSpa.registerApplication(project.name,()=>System.import(project.name),(location)=>{
return project.base?true:location.hash.startsWith(`#/${project.name}`);
});
})
}else{
singleSpa.registerApplication(project.name,()=>System.import(project.name),(location)=>{
return project.base?true:location.hash.startsWith(`#/${project.name}`);
});
}
});
singleSpa.start();
})
})()
</script>
</body>
</html>
實際渲染出來是

4.5 優化打包配置
因為三個子項目都用到了相同的一部分依賴,可以考慮將公用的依賴不打包進去,改為在主項目主引入來提高打包效率
修改子應用的webpack.base.config.js,增加配置項

在主應用中引入依賴

4.5 增加react應用
同樣是使用webpack打包,不同是包裝器不一樣。其他基本上是一樣的思路即可。

最終demo

轉載 https://www.cnblogs.com/scdisplay/p/11648701.html#4391495

