1. 微前端 從 0到 1搭建

        共 9534字,需瀏覽 20分鐘

         ·

        2022-04-08 05:33

        在這里插入圖片描述

        微前端

        微前端

        Single-SPA

        ?

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

        ?
        image-20220405155852230

        概念

        官網(wǎng) :

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

        Alibaba -

        springboot

        - sofaboot

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

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

        總結(jié):子應(yīng)用可以獨(dú)立構(gòu)建,運(yùn)行時(shí)動(dòng)態(tài)加載,主子應(yīng)用完全解耦,并且技術(shù)棧無關(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)鍵問題在于:

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

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

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

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

        • 如何測試?

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

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

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

            「.....」

        簡單來講,微前端的理念類似于微服務(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)勢在于:

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

        微前端

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

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

        image-20220403073941748

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

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

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

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

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

        首先創(chuàng)建一個(gè)vue子應(yīng)用,并通過single-spa-vue來導(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
        })
        • 配置庫打包

          //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?()=>{
        ????????//這里通過協(xié)議來加載指定文件
        ????????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īng)用的腳手架工具。它本身集成了Webpack,并配置了一系列內(nèi)置的loader和默認(rèn)的npm的腳本,可以很輕松的實(shí)現(xiàn)零配置就可以快速開發(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)打開 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來完成 微前端 應(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 文件來指定 項(xiàng)目 運(yùn)行的端口號(hào)

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

        在主應(yīng)用中index.tsx ? 注冊子應(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)來 ,需要有主應(yīng)用進(jìn)行掛載,現(xiàn)在我們已經(jīng)將 子應(yīng)用注冊在 了 主應(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)用 添加 訪問

        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)聽事件改變
        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)聽改變
        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)行注冊 ?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)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 亚洲天堂男人网 | 做爱小视频 免费 | 亚洲无码四区 | 欧美操逼逼 | 啪啪啪av |