<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    微前端 從 0到 1搭建

    共 9534字,需瀏覽 20分鐘

     ·

    2022-04-08 05:33

    在這里插入圖片描述

    微前端

    微前端

    Single-SPA

    ?

    微服務(wù)是面向服務(wù)架構(gòu)(SOA)的一種變體,把應(yīng)用程序設(shè)計(jì)成一系列松耦合的細(xì)粒度服務(wù),并通過(guò)輕量級(jí)的通信協(xié)議組織起來(lái) 具體地,將應(yīng)用構(gòu)建成一組小型服務(wù)。這些服務(wù)都能夠獨(dú)立部署、獨(dú)立擴(kuò)展,每個(gè)服務(wù)都具有穩(wěn)固的模塊邊界,甚至允許使用不同的編程語(yǔ)言來(lái)編寫不同服務(wù),也可以由不同的團(tuán)隊(duì)來(lái)管理

    ?
    image-20220405155852230

    概念

    官網(wǎng) :

    2018年 Single-SPA誕生了, single-spa是一個(gè)用于前端微服務(wù)化的JavaScript前端解決方案 ?(本身沒(méi)有處理樣式隔離、js執(zhí)行隔離) ?實(shí)現(xiàn)了路由劫持和應(yīng)用加載;

    Alibaba -

    springboot

    - sofaboot

    Single-SPA 搞了個(gè)入口 ?--> ?qiankun

    2019年 qiankun基于Single-SPA, 提供了更加開(kāi)箱即用的 API ?(single-spa + sandbox + import-html-entry),它 做到了技術(shù)棧無(wú)關(guān),并且接入簡(jiǎn)單(有多簡(jiǎn)單呢,像iframe一樣簡(jiǎn)單)。

    總結(jié):子應(yīng)用可以獨(dú)立構(gòu)建,運(yùn)行時(shí)動(dòng)態(tài)加載,主子應(yīng)用完全解耦,并且技術(shù)棧無(wú)關(guān),靠的是協(xié)議接入(這里提前強(qiáng)調(diào)一下:子應(yīng)用必須導(dǎo)出 bootstrap、mount、unmount三個(gè)方法)。

    micro front ends single spot

    應(yīng)用量龐大,

    實(shí)現(xiàn)上,關(guān)鍵問(wèn)題在于:

    • 多個(gè) Bundle 如何集成?

    • 子應(yīng)用之間怎樣隔離影響?

    • 公共資源如何復(fù)用?

    • 子應(yīng)用間怎樣通信?

    • 如何測(cè)試?

    • 當(dāng)然,這種架構(gòu)模式并非百益而無(wú)一害,一些問(wèn)題也隨之而來(lái):

      • 導(dǎo)致依賴項(xiàng)冗余,增加用戶的流量負(fù)擔(dān)

      • 團(tuán)隊(duì)自治程度的增加,可能會(huì)破壞協(xié)作

        「.....」

    簡(jiǎn)單來(lái)講,微前端的理念類似于微服務(wù):

    ?

    In short, micro frontends are all about slicing up big and scary things into smaller, more manageable pieces, and then being explicit about the dependencies between them.

    ?

    將龐大的整體拆成可控的小塊,并明確它們之間的依賴關(guān)系。關(guān)鍵優(yōu)勢(shì)在于:

    • 代碼庫(kù)更小,更內(nèi)聚、可維護(hù)性更高
    • 松耦合、自治的團(tuán)隊(duì)可擴(kuò)展性更好
    • 「漸進(jìn)地升級(jí)、更新甚至重寫部分前端功能成為了可能」

    微前端

    微前端到底是什么?
    img
    微前端架構(gòu)實(shí)戰(zhàn)中-single-spa 篇
    微前端

    微前端就是將不同的功能按照不同的維度拆分成多個(gè)子應(yīng)用。通過(guò)主應(yīng)用來(lái)加載這些子應(yīng)用。

    image-20220403073941748

    微前端的核心在于「拆」, 拆完后再「合」!

    今天來(lái)一塊聊聊微前端 技術(shù)

    img
    • 一門前端語(yǔ)言的基礎(chǔ) Vue React

    SingleSpa 實(shí)戰(zhàn)

    • 構(gòu)建子應(yīng)用

    首先創(chuàng)建一個(gè)vue子應(yīng)用,并通過(guò)single-spa-vue來(lái)導(dǎo)出必要的生命周期:

    vue?create?spa-vue??
    npm?install?single-spa-vue??
    import?singleSpaVue?from?'single-spa-vue';
    const?appOptions?=?{
    ???el:?'#vue',
    ???router,
    ???render:?h?=>?h(App)
    }
    //?在非子應(yīng)用中正常掛載應(yīng)用
    if(!window.singleSpaNavigate){
    ?delete?appOptions.el;
    ?new?Vue(appOptions).$mount('#app');
    }
    const?vueLifeCycle?=?singleSpaVue({
    ???Vue,
    ???appOptions
    });
    //?子應(yīng)用必須導(dǎo)出以下生命周期:bootstrap、mount、unmount
    export?const?bootstrap?=?vueLifeCycle.bootstrap;
    export?const?mount?=?vueLifeCycle.mount;
    export?const?unmount?=?vueLifeCycle.unmount;
    export?default?vueLifeCycle;
    const?router?=?new?VueRouter({
    ??mode:?'history',
    ??base:?'/vue',???//改變路徑配置
    ??routes
    })
    • 配置庫(kù)打包

      //vue.config.js
      module.exports?=?{
      ????configureWebpack:?{
      ????????output:?{
      ????????????library:?'singleVue',
      ????????????libraryTarget:?'umd'
      ????????},
      ????????devServer:{
      ????????????port:10000
      ????????}
      ????}
      }
    • 主應(yīng)用搭建

    ?

    將子應(yīng)用掛載到id="vue"標(biāo)簽中

    ?
    import?Vue?from?'vue'
    import?App?from?'./App.vue'
    import?router?from?'./router'
    import?ElementUI?from?'element-ui';
    import?'element-ui/lib/theme-chalk/index.css';
    Vue.use(ElementUI);
    const?loadScript?=?async?(url)=>?{
    ??await?new?Promise((resolve,reject)=>{
    ????const?script?=?document.createElement('script');
    ????script.src?=?url;
    ????script.onload?=?resolve;
    ????script.onerror?=?reject;
    ????document.head.appendChild(script)
    ??});
    }
    import?{?registerApplication,?start?}?from?'single-spa';
    registerApplication(
    ????'singleVue',
    ????async?()=>{
    ????????//這里通過(guò)協(xié)議來(lái)加載指定文件
    ????????await?loadScript('http://localhost:10000/js/chunk-vendors.js');
    ????????await?loadScript('http://localhost:10000/js/app.js');
    ????????return?window.singleVue
    ????},
    ????location?=>?location.pathname.startsWith('/vue')
    )
    start();
    new?Vue({
    ??router,
    ??render:?h?=>?h(App)
    }).$mount('#app')
    ?
    • 動(dòng)態(tài)設(shè)置子應(yīng)用
    if(window.singleSpaNavigate){
    ??__webpack_public_path__?=?'http://localhost:10000/'
    }

    前置條件

    npm?install?-g?yarn
    yarn?init
    • 安裝 官方 React

    Create React App是FaceBook的React團(tuán)隊(duì)官方出的一個(gè)構(gòu)建React單頁(yè)面應(yīng)用的腳手架工具。它本身集成了Webpack,并配置了一系列內(nèi)置的loader和默認(rèn)的npm的腳本,可以很輕松的實(shí)現(xiàn)零配置就可以快速開(kāi)發(fā)React的應(yīng)用。

    # 全局安裝
    npm install -g create-react-app
    # 構(gòu)建一個(gè)my-app的項(xiàng)目
    npx create-react-app my-app
    cd my-app

    # 啟動(dòng)編譯當(dāng)前的React項(xiàng)目,并自動(dòng)打開(kāi) http://localhost:3000/
    npm start
    • 構(gòu)建 React項(xiàng)目

      • npm

        npm?init?react-app?my-app
      • Yarn

        #?yarn?create?is?available?in?Yarn?0.25+
        yarn?create?react-app?my-app

    使用 qiankun 微前端構(gòu)建

    官方文檔: https://qiankun.umijs.org/zh

    ?

    首先我們需要?jiǎng)?chuàng)建 3個(gè) 前端應(yīng)用, 微前端 ,就是 代表 一個(gè)小型應(yīng)用的獨(dú)立部署,獨(dú)立交互,需要 應(yīng)用之間進(jìn)行通信,這里我們使用qiankun來(lái)完成 微前端 應(yīng)用

    ?
    • 創(chuàng)建 ?3 個(gè) react app

      yarn?create?react-app?qiankun-base??--template?typescript
      yarn?create?react-app?qiankun-micro-app1??--template?typescript
      yarn?create?react-app?qiankun-micro-app2??--template?typescript
      • app2
      • app1
      • 基座
    • 在 react app 應(yīng)用中 ?安裝 qiankun ?依賴

      $?yarn?add?qiankun??#?or?npm?i?qiankun?-S
    • 分別創(chuàng)建 .env 文件來(lái)指定 項(xiàng)目 運(yùn)行的端口號(hào)

    PORT=3010
    PORT=3011
    PORT=3012
    image-20220405201705407

    在主應(yīng)用中index.tsx ? 注冊(cè)子應(yīng)用

    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import App from './App';
    import reportWebVitals from './reportWebVitals';


    import { registerMicroApps, start } from 'qiankun';

    registerMicroApps([
    {
    name: 'react app one', // app name registered
    entry: '//localhost:3011',
    container: '#micro-app2',
    activeRule: '/micro-app2',
    props:{
    nickname: "全棧小劉",
    age:19
    }
    },
    {
    name: 'react app two', // app name registered
    entry: '//localhost:3012',
    container: '#micro-app1',
    activeRule: '/micro-app1',
    props:{
    nickname: "全棧小劉",
    age:18
    }
    },
    ]);

    start();

    ReactDOM.render(


    ,
    document.getElementById('root')
    );

    // If you want to start measuring performance in your app, pass a function
    // to log results (for example: reportWebVitals(console.log))
    // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
    reportWebVitals();

    ?

    :子應(yīng)用加載進(jìn)來(lái) ,需要有主應(yīng)用進(jìn)行掛載,現(xiàn)在我們已經(jīng)將 子應(yīng)用注冊(cè)在 了 主應(yīng)用當(dāng)中

    ?
    • name 應(yīng)用名稱
    • entry ?端口號(hào)
    • container 掛載容器
    • activeRule 激活的規(guī)則
    • props: 父子屬性之間傳參

    api文檔 : https://qiankun.umijs.org/zh/api

    • 在 App.tsx 中創(chuàng)建掛載點(diǎn)
    import React from 'react';
    import logo from './logo.svg';
    import './App.css';

    function App() {
    return (

    );
    }

    export default App;

    「所有」應(yīng)用中 添加 public-path.js 用于 加載靜態(tài) 資源


    if?(window.__POWERED_BY_QIANKUN__)?{
    ????__webpack_public_path__?=?window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
    ??}

    在子應(yīng)用中 添加 webpack 重寫項(xiàng)

    • 添加
    yarn?add?react-app-rewired??-D
    • 「設(shè)置 子應(yīng)用」啟動(dòng),在 scripts
    ??"scripts":?{
    ????"start":?"react-app-rewired?start",
    ????"build":?"react-scripts?build",
    ????"test":?"react-scripts?test",
    ????"eject":?"react-scripts?eject"
    ??},

    在webpack 中 進(jìn)行 overrides 重寫,重寫的 目的是 允許跨域

    • config-overrides.js
    const?{?name?}?=?require('./package');

    module.exports?=?{
    ??webpack:?(config)?=>?{
    ????config.output.library?=?`${name}-[name]`;
    ????config.output.libraryTarget?=?'umd';
    ????//?config.output.jsonpFunction?=?`webpackJsonp_${name}`;
    ????config.output.globalObject?=?'window';

    ????return?config;
    ??},

    ??devServer:?(_)?=>?{
    ????const?config?=?_;

    ????config.headers?=?{
    ??????'Access-Control-Allow-Origin':?'*',
    ????};
    ????config.historyApiFallback?=?true;
    ????config.hot?=?false;
    ????config.watchContentBase?=?false;
    ????config.liveReload?=?false;

    ????return?config;
    ??},
    };

    在不同的子應(yīng)用當(dāng)中 去加載 tsx 生命周期

    app1 ?、app2 、 index.tsx

    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import App from './App';
    import reportWebVitals from './reportWebVitals';

    export async function bootstrap() {
    console.log('[react] react app bootstraped');
    }

    // @ts-ignore
    export async function mount(props) {
    console.log(props)
    ReactDOM.render(
    ,
    props.container
    ? props.container.querySelector('#root')
    : document.getElementById('root'));
    }
    // @ts-ignore
    export async function update(props){
    console.log("update props",props)
    }

    // @ts-ignore
    export async function unmount(props) {
    ReactDOM.unmountComponentAtNode(
    props.container
    ? props.container.querySelector('#root')
    : document.getElementById('root'));
    }
    // @ts-ignore
    if (!window.__POWERED_BY_QIANKUN__) {
    ReactDOM.render(,document.getElementById("root"))
    }




    // If you want to start measuring performance in your app, pass a function
    // to log results (for example: reportWebVitals(console.log))
    // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
    reportWebVitals();

    在 index.tsx 引入 public-path.js 解決靜態(tài)資源

    import './public-path.js'

    在 主 應(yīng)用 添加 訪問(wèn)

    import React from 'react';
    import logo from './logo.svg';
    import './App.css';

    function App() {
    return (

    );
    }

    export default App;

    • 在 主 應(yīng)用 index.tsx 中 傳遞 數(shù)據(jù)
     props:{

    nickname: "全棧小劉",

    age:19

    }


    • 在 子應(yīng)用 ?周期中進(jìn)行打印
    export async function mount(props) {
    console.log(props)
    ReactDOM.render(
    ,
    props.container
    ? props.container.querySelector('#root')
    : document.getElementById('root'));
    }
    image-20220402075342284
    • 在 主應(yīng)用中 監(jiān)聽(tīng)事件改變
    import { initGlobalState, MicroAppStateActions } from 'qiankun';

    const state ={
    nickname: "全棧小劉"
    }

    // 初始化

    const actions: MicroAppStateActions = initGlobalState(state);

    actions.onGlobalStateChange((state,prev)=>{
    console.log(state,prev)
    })
    // 2秒鐘后 改變
    setTimeout(()=>{
    actions.setGlobalState({...state,age:19})
    },2000)

    • 在子應(yīng)用中 監(jiān)聽(tīng)改變
    export async function mount(props) {


    console.log(props)
    // @ts-ignore

    props.onGlobalStateChange((state,prev)=>{
    console.log(state,prev)
    setTimeout(()=>{
    props.setGlobalState({ ...state, age:20 });
    },2000)

    })
    // @ts-ignore


    ReactDOM.render(
    ,
    props.container
    ? props.container.querySelector('#root')
    : document.getElementById('root'));
    }
    • 安裝 NPM SCRIPT 插件 ,分別 啟動(dòng) 運(yùn)行
    image-20220402073016755

    接入 Vue3

    ?

    通用 vue3

    ?
    • 安裝最新的腳手架
    npm?install?-g?@vue/cli
    • 創(chuàng)建 項(xiàng)目 ?es6 js 模塊
    vue?create?qiankun-vue-micro-app3
    • 添加typescript ,轉(zhuǎn)換 ts ? ?-Y
    • yes
    vue?add?typescript
    • 依次加入 public-path.js
    /*?eslint-disable?*/?
    if?(window.__POWERED_BY_QIANKUN__)?{
    ????__webpack_public_path__?=?window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
    ??}
    • 安裝 qiankun
    ?yarn?add?qiankun
    • 參考qiankun官網(wǎng)的示例main.js ,完成生命周期的鉤子函數(shù)

    • base 中 進(jìn)行注冊(cè) ?index.tsx

    • vue-config.js 設(shè)置啟動(dòng)端口

    • vue-config.js

    /*?eslint-disable?*/?
    const?{?name?}?=?require('./package');

    module.exports?=?{
    ????devServer:{
    ???????port:?3013,
    ???????headers:{
    ????????'Access-Control-Allow-Origin':?'*',
    ???????}
    ????},
    ????configureWebpack:{
    ??????output:?{
    ????????library:?`${name}-[name]`,
    ????????libraryTarget:?'umd'
    ??????}
    ????}
    ??
    };

    微前端項(xiàng)目 實(shí)戰(zhàn)

    https://github.com/a1029563229/micro-front-template

    效果圖
    • Reference Document :
      • https://juejin.cn/post/6844903943873675271
      • https://zhuanlan.zhihu.com/p/96464401
      • https://single-spa.js.org/


    瀏覽 75
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)
    評(píng)論
    圖片
    表情
    推薦
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    婷婷三级| 亚洲成人人人爽av电影 | 色婷婷综合在线 | 国产精品视频免费在线观看 | 日韩www在线 |