微前端架構上-概念篇

微前端架構上-概念篇

如何實現多個應用之間的資源共享javascript

以前比較多的處理方式是npm包形式抽離和引用,好比多個應用項目之間,可能有某業務邏輯模塊或者其餘是可複用的,便抽離出來以npm包的形式進行管理和使用。但這樣卻帶來了如下幾個問題:html

  • 發佈效率低下。若是須要迭代npm包內的邏輯業務,須要先發布npm包以後,再每一個使用了該npm包的應用都更新一次npm包版本,再各自構建發佈一次,過程繁瑣。若是涉及到的應用更多的話,花費的人力和精力就更多了。
  • 多團隊協做容易不規範。包含通用模塊的npm包做爲共享資產,「每一個人」擁有它,但在實踐中,這一般意味着沒有人擁有它。它很快就會充滿雜亂風格不一致的代碼,沒有明確的約定或技術願景。

這些問題讓咱們意識到,擴展前端開發規模以便於多個團隊能夠同時開發一個大型且複雜的產品是一個重要但又棘手的難題。前端

所以,早在2016年,微前端概念誕生了。vue

第1章 什麼是微前端?

1-1 微前端的概念

Micro Frontends: https://micro-frontends.org/ 官網定義了微前端概念:java

Techniques, strategies and recipes for building a modern web app with multiple teams that can ship features independently.node

image-20210420104426857.png

從 Micro Frontends 官網能夠了解到,微前端概念是從微服務概念擴展而來的,摒棄大型單體方式,將前端總體分解爲小而簡單的塊,這些塊能夠獨立開發、測試和部署,同時仍然聚合爲一個產品出如今客戶面前。能夠理解微前端是一種將多個可獨立交付的小型前端應用聚合爲一個總體的架構風格。react

image-20210420140312733.png

值得留意的幾個點:webpack

  • 微前端不是一門具體的技術,而是整合了技術、策略和方法,可能會以腳手架、輔助插件和規範約束這種生態圈形式展現出來,是一種宏觀上的架構。這種架構目前有多種方案,都有利弊之處,但只要適用當前業務場景的就是好方案。
  • 微前端並沒有技術棧的約束。每一套微前端方案的設計,都是基於實際需求出發。若是是多團隊統一使用了react技術棧,可能對微前端方案的跨技術棧使用並無要求;若是是多團隊同時使用了react和vue技術棧,可能就對微前端的跨技術棧要求比較高。

微前端的使用場景

  1. 拆分巨型應用,使應用變得更加可維護
  2. 兼容歷史應用,實現增量開發

1-2 微前端的優點

同步更新

對比了npm包方式抽離,讓咱們意識到更新流程和效率的重要性。微前端因爲是多個子應用的聚合,若是多個業務應用依賴同一個服務應用的功能模塊,只須要更新服務應用,其餘業務應用就能夠立馬更新,從而縮短了更新流程和節約了更新成本。git

增量升級

遷移是一項很是耗時且艱難的任務,好比有一個管理系統使用 AngularJS 開發維護已經有三年時間,可是隨時間的推移和團隊成員的變動,不管從開發成本仍是用人需求上,AngularJS 已經不能知足要求,因而團隊想要更新技術棧,想在其餘框架中實現新的需求,可是現有項目怎麼辦?直接遷移是不可能的,在新的框架中徹底重寫也不太現實。github

使用微前端架構就能夠解決問題,在保留原有項目的同時,能夠徹底使用新的框架開發新的需求,而後再使用微前端架構將舊的項目和新的項目進行整合。這樣既可使產品獲得更好的用戶體驗,也可使團隊成員在技術上獲得進步,產品開發成本也降到的最低。

獨立部署與發佈

在目前的單頁應用架構中,使用組件構建用戶界面,應用中的每一個組件或功能開發完成或者bug修復完成後,每次都須要對整個產品從新進行構建和發佈,任務耗時操做上也比較繁瑣。

在使用了微前端架構後,能夠將不能的功能模塊拆分紅獨立的應用,此時功能模塊就能夠單獨構建單獨發佈了,構建時間也會變得很是快,應用發佈後不須要更改其餘內容應用就會自動更新,這意味着你能夠進行頻繁的構建發佈操做了。

獨立團隊決策

由於微前端構架與框架無關,當一個應用由多個團隊進行開發時,每一個團隊均可以使用本身擅長的技術棧進行開發,也就是它容許適當的讓團隊決策使用哪一種技術,從而使團隊協做變得再也不僵硬。

1-3 微前端落地方案

自組織模式:經過約定進行互調,但會遇處處理第三方依賴等問題。

基座模式:經過搭建基座、配置中心來管理子應用。如基於SIngle Spa的偏通用的乾坤方案,也有基於自己團隊業務量身定製的方案。

去中心模式:脫離基座模式,每一個應用之間均可以彼此分享資源。如基於Webpack 5 Module Federation實現的EMP微前端方案,能夠實現多個應用彼此共享資源分享。

其中,目前值得關注是去中心模式中的EMP微前端方案,既能夠實現跨技術棧調用,又能夠在相同技術棧的應用間深度定製共享資源,若是剛開始調研微前端的話,能夠先嚐試瞭解一下EMP微前端方案,或許會給你帶來不錯的使用體驗

第2章 Systemjs模塊化解決方案

Systemjs:https://github.com/systemjs/systemjs

在微前端架構中,微應用被打包爲模塊,但瀏覽器不支持模塊化,須要使用 systemjs 實現瀏覽器中的模塊化。

systemjs 是一個用於實現模塊化的 JavaScript 庫,有屬於本身的模塊化規範。

在開發階段咱們可使用 ES 模塊規範,而後使用 webpack 將其轉換爲 systemjs 支持的模塊。

案例:經過 webpack 將 react 應用打包爲 systemjs 模塊,在經過 systemjs 在瀏覽器中加載模塊

npm install webpack@5.17.0 webpack-cli@4.4.0 webpack-dev-server@3.11.2 html-webpack-plugin@4.5.1 @babel/core@7.12.10 @babel/cli@7.12.10 @babel/preset-env@7.12.11 @babel/preset-react@7.12.10 babel-loader@8.2.2

package.json

{
  "name": "systemjs-react",
  "scripts": {
    "start": "webpack serve"
  },
  "dependencies": {
    "@babel/cli": "^7.12.10",
    "@babel/core": "^7.12.10",
    "@babel/preset-env": "^7.12.11",
    "@babel/preset-react": "^7.12.10",
    "babel-loader": "^8.2.2",
    "html-webpack-plugin": "^4.5.1",
    "webpack": "^5.17.0",
    "webpack-cli": "^4.4.0",
    "webpack-dev-server": "^3.11.2"
  }
}
複製代碼

webpack.config.js

const path = require("path")
const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
  mode: "development",
  entry: "./src/index.js", // 入口
  output: { // 出口
    // 打包目錄及文件
    path: path.join(__dirname, "build"), 
    filename: "index.js",
    // 指定構建時所須要的庫
    libraryTarget: "system"
  },
  devtool: "source-map",
  // 服務器運行配置
  devServer: {
    port: 9000, // 端口
    // 靜態資源文件夾
    contentBase: path.join(__dirname, "build"),
    historyApiFallback: true
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            // 對應語法轉換
            presets: ["@babel/preset-env", "@babel/react"]
          }
        }
      }
    ]
  },
  plugins: [ // 插件
    new HtmlWebpackPlugin({
      /* 打包時,不須要自動引入JS文件(<script> 標籤) */
      inject: false, 
      /* 使用微前端的方式,咱們須要本身加載對應的 JS 文件 */ 

      template: "./src/index.html"
    })
  ],
  // 添加打包排除選項,微前端中須要使用公共的 React ,打包是不須要的
  externals: ["react", "react-dom", "react-router-dom"]
}
複製代碼

src/index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>systemjs-react</title>
    <!-- 按照 systemjs 模塊化的方式引入React框架應用 -->
    <script type="systemjs-importmap"> { "imports": { "react": "https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js", "react-dom": "https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.production.min.js", "react-router-dom": "https://cdn.jsdelivr.net/npm/react-router-dom@5.2.0/umd/react-router-dom.min.js" } } </script>
    <!-- systemjs 庫 -->
    <script src="https://cdn.jsdelivr.net/npm/systemjs@6.8.0/dist/system.min.js"></script>
  </head>
  <body>
    <div id="root"></div>
    <script> // 按照 systemp 的方式,引入具體應用 System.import("./index.js") </script>
  </body>
</html>
複製代碼

src/index.js

import React from "react"
import ReactDom from "react-dom"

import App from './App.js'

ReactDom.render(<App />, document.getElementById("root")) 
複製代碼

src/App.js

import React from "react"

export default function App(){
    return <div>React micro for systemjs</div>
}
複製代碼
相關文章
相關標籤/搜索