大型中后臺項目一般包括10個以上的子項目,如果維護在一個單頁面應用中,項目就會越來越大,而且不利于版本的迭代,微前端就很好的解決了這些問題。
這篇文章主要來體驗下螞蟻的微前端:qiankun,雖然比較成熟了,但在體驗過程中還是有一些問題,記錄總結下,項目代碼
實踐項目以react單頁面應用為主應用,然后構建了三個微應用:react、vue3、node靜態頁面
微前端要求多個前端服務,所以我們先準備幾個應用,使用不同的技術棧,體驗微前端的強大
mirco-front-demo
作為整個服務的根目錄,為了便于實踐,主應用和微應用將放在一起。
主應用:
my-app
port: 10000
create-react-app
微應用:
micro-reat-1
port: 10100
create-react-app
micro-vue-2
port: 10200
vue3
micro-static-3
port: 10300
node + html
需要提前安裝create-react-app:
sudo npx install create-react-app
通過create-react-app
創建主應用my-app
,其他的微應用都會掛載到主應用。
# 在根目錄 mkdir mirco-front-demo cd mirco-front-demo # 新建主應用my-app npx create-react-app my-app cd my-app # 通過.env文件修改啟動端口 echo "PORT=10000" > .env yarn start 復制代碼
cd micro-front-demo npx create-react-app micro-react-1 復制代碼
同主應用一樣創建一個React應用,命名micro-react-1
,并修改啟動端口號(也可以使用.env文件修改)
修改啟動端口號:
{ "scripts": { "start": "PORT=10100 react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test", "eject": "react-app-rewired eject" } } 復制代碼
使用vue3.0,提前安裝vue-cli:
yarn global add @vue/cli
,官方文檔
vue create micro-vue-2 cd micro-vue-2 touch vue.config.js 復制代碼
除了微應用1和微應用2修改啟動端口號的方法,這里也可以對webpack進行覆蓋
vue-config.js
const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({ transpileDependencies: true, devServer: { // 監聽端口 port: 10200, // 配置跨域請求頭,解決開發環境的跨域問題 headers: { "Access-Control-Allow-Origin": "*", } } } 復制代碼
啟動微應用yarn serve
# 新建微應用項目3 mkdir micro-static-3 cd micro-static-3 npm init yarn add express cors # 新建項目文件 mkdir static touch index.js cd static touch index.html 復制代碼
index.js
const express = require('express') const cors = require('cors') const app = express() const port = 10300 app.use(cors()) app.use(express.static('static')); app.listen(port, () => { console.log(`Example app listening on port ${port}`) }) 復制代碼
啟動微應用node index.js
cd mirco-front-demo npm init yarn add npm-run-all -D 復制代碼
修改當前目錄下package.json
{ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "npm-run-all --parallel start:*", "start:main": "cd my-app && yarn start", "start:micro-react": "cd micro-react-1 && yarn start", "start:micro-vue": "cd micro-vue-2 && yarn serve", "start:micro-static": "cd micro-static-3 && node index.js" } } 復制代碼
執行命令
cd micro-front-demo yarn start 復制代碼
這樣就同時啟動了四個前端服務
改造下主應用樣式,整個頂部導航欄和側邊欄屬于主應用,而中間空白的部分可以展示主應用或子應用的頁面。
主應用路由安裝react-router-dom
,通過history
模式渲染。
在側邊欄點擊不同的鏈接會加載不同的子應用,樣式和路由具體可以看示例代碼
修改單頁面應用渲染根節點root
為main-root
,防止和微應用中渲染節點沖突。
并且增加一個通過id標記的DIV,用來嵌入微應用,接著引入qiankun
,這里id=subApp
用來掛載微應用
yarn add qiankun 復制代碼
在src/index.js
中配置
import React from 'react'; import ReactDOM from 'react-dom'; import { registerMicroApps, start } from 'qiankun'; import './index.css'; import App from './App'; function render(){ ReactDOM.render(<App />, document.querySelector('#main-root')); } render({}); registerMicroApps([ { name: 'react', // app name registered entry: '//localhost:10100', container: "#subApp", activeRule: '/react' }, { name: 'vue', // app name registered entry: '//localhost:10200', container: "#subApp", activeRule: '/vue' }, { name: 'static', // app name registered entry: '//localhost:10300', container: "#subApp", activeRule: '/static' } ], { beforeLoad: app => { console.log('before load app.name=====>>>>>', app.name) }, beforeMount: [ app => { console.log('[LifeCycle] before mount %c%s', 'color: green;', app.name) } ], afterMount: [ app => { console.log('[LifeCycle] after mount %c%s', 'color: green;', app.name) } ], afterUnmount: [ app => { console.log('[LifeCycle] after unmount %c%s', 'color: green;', app.name) } ] }) start() 復制代碼
引入react-router-dom
給微應用配置路由,展示不同的頁面,如下:
修改src/index.js
下啟動文件
function render(props) { const { container } = props; ReactDOM.render(<App />, container ? container.querySelector('#root') : document.querySelector('#root')); } if (!window.__POWERED_BY_QIANKUN__) { render({}); } export async function bootstrap() { console.log('[react16] react app bootstraped'); } export async function mount(props) { console.log('[react16] props from main framework', props); render(props); } export async function unmount(props) { const { container } = props; ReactDOM.unmountComponentAtNode(container ? container.querySelector('#root') : document.querySelector('#root')); } 復制代碼
給微應用添加導出聲明周期函數,微應用掛載成功時,渲染到當前應用的root節點。
當前cra并沒有釋放webpack配置,所以要通過插件覆蓋配置:
yarn add react-app-rewired -D 復制代碼
"scripts": { "start": "PORT=10100 react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test", "eject": "react-app-rewired eject" } 復制代碼
在當前微應用根目錄下touch config-overrides.js
const { name } = require('./package'); module.exports = { webpack: (config, env) => { config.output.library = `${name}-[name]`; config.output.libraryTarget = 'umd'; config.output.globalObject = 'window'; config.output.chunkLoadingGlobal = `webpackJsonp_${name}`; return config; }, devServer: (_) => { const config = _; config.headers = { 'Access-Control-Allow-Origin': '*', }; config.historyApiFallback = true; config.hot = false; config.watchContentBase = false; config.liveReload = false; config.injectClient = false return config; } } 復制代碼
啟動微應用yarn start
,正常運行
新增 public-path.js
文件,用于修改運行時的 publicPath
src/public-path.js
if (window.__POWERED_BY_QIANKUN__) { __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__; } 復制代碼
引入vue路由,設置成history模式,baseRouter設置成vue,導出聲明周期函數
import { createApp } from 'vue' import App from './App.vue' import router from './router' import './public-path' const app = createApp(App); function render(props) { const { container } = props; app.use(router) .mount(container ? container.querySelector('#app') : '#app') } export async function bootstrap() { console.log('bootstrap'); } export async function mount(props) { console.log('mount', props); render(props); } export async function unmount() { console.log('unmount'); app.unmount(); } 復制代碼
修改webpack配置vue.config.js
module.exports = defineConfig({ configureWebpack: { output: { // 微應用的包名,這里與主應用中注冊的微應用名稱一致 library: name, // 將你的 library 暴露為所有的模塊定義下都可運行的方式 libraryTarget: "umd", // 按需加載相關,設置為 webpackJsonp_微應用名稱 即可 chunkLoadingGlobal: `webpackJsonp_${name}`, } } }) 復制代碼
啟動應用yarn serve
這是一個express服務啟動的靜態服務
文件入口導出聲明周期entry.js
const render = ($) => { $('#app').html('Hello, render html, 一個通過http服務部署的靜態網站'); return Promise.resolve(); }; ((global) => { global['static'] = { bootstrap: () => { console.log('purehtml bootstrap'); return Promise.resolve(); }, mount: () => { console.log('purehtml mount'); return render($); }, unmount: () => { console.log('purehtml unmount'); return Promise.resolve(); }, }; })(window); 復制代碼
然后在模版文件導入
其實也是掛載在了app節點。
啟動當前微服務node index.js
cd micro-front-demo yarn start 復制代碼
'__webpack_public_path__' is not defined
Uncaught Error: single-spa minified message #20
覆蓋CRA的Webpack配置
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; }, }; 復制代碼
這里報錯,是因為是webpack5.x不兼容config.output.jsonpFunction
的寫法,需要替換成config.output.chunkLoadingGlobal
construct.js:17 Uncaught Error: application 'react' died in status LOADING_SOURCE_CODE: [qiankun]: You need to export lifecycle functions in react entry
沒有將生命周期暴露出來,需要挨個檢查下面的配置
Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema. - configuration.output has an unknown property 'jsonpFunction'. These properties are valid: object { assetModuleFilename?, asyncChunks?, auxiliaryComment?, charset?, chunkFilename?, chunkFormat?, chunkLoadTimeout?, chunkLoading?, chunkLoadingGlobal?, clean?, compareBeforeEmit?, crossOriginLoading?, cssChunkFilename?, cssFilename?, devtoolFallbackModuleFilenameTemplate?, devtoolModuleFilenameTemplate?, devtoolNamespace?, enabledChunkLoadingTypes?, enabledLibraryTypes?, enabledWasmLoadingTypes?, environment?, filename?, globalObject?, hashDigest?, hashDigestLength?, hashFunction?, hashSalt?, hotUpdateChunkFilename?, hotUpdateGlobal?, hotUpdateMainFilename?, iife?, importFunctionName?, importMetaName?, library?, libraryExport?, libraryTarget?, module?, path?, pathinfo?, publicPath?, scriptType?, sourceMapFilename?, sourcePrefix?, strictModuleErrorHandling?, strictModuleExceptionHandling?, trustedTypes?, umdNamedDefine?, uniqueName?, wasmLoading?, webassemblyModuleFilename?, workerChunkLoading?, workerWasmLoading? } -> Options affecting the output of the compilation. `output` options tell webpack how to write the compiled files to disk. Did you mean output.chunkLoadingGlobal (BREAKING CHANGE since webpack 5)?
作者:前端中后臺
鏈接:https://juejin.cn/post/7075607657205710855
來源:稀土掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/127964.html
摘要:而從技術實現角度,微前端架構解決方案大概分為兩類場景單實例即同一時刻,只有一個子應用被展示,子應用具備一個完整的應用生命周期。為了解決產品研發之間各種耦合的問題,大部分企業也都會有自己的解決方案。 原文鏈接:https://zhuanlan.zhihu.com/p/... Techniques, strategies and recipes for building a modern ...
摘要:可視化鋼琴使用鋼琴音色播放文件,并且將按鍵可視化到鋼琴鍵盤上。如圖主界面鏈接在線 可視化鋼琴 使用鋼琴音色播放Midi文件,并且將按鍵可視化到鋼琴鍵盤上。如圖: 主界面: showImg(https://segmentfault.com/img/bVbmEzC?w=1920&h=943); github鏈接 https://github.com/qk44077907...在線demo ...
摘要:近期公司需要針對分享流程進行優化,其中一點就是前端檢測是否安裝應用,來進行不同的判斷下載或直接跳轉到中。為回調函數,根據返回來判斷是否安裝。 近期公司需要針對分享流程進行優化,其中一點就是前端H5檢測是否安裝應用,來進行不同的判斷(下載或直接跳轉到app中)。原理很簡單:創建一個iframe去打開uri。如果打開app成功網頁進入后臺,再切換回來時間會超過2.5s。利用時間去檢測。下面...
閱讀 289·2024-11-07 18:25
閱讀 130366·2024-02-01 10:43
閱讀 868·2024-01-31 14:58
閱讀 828·2024-01-31 14:54
閱讀 82766·2024-01-29 17:11
閱讀 3048·2024-01-25 14:55
閱讀 1985·2023-06-02 13:36
閱讀 3033·2023-05-23 10:26