本文使用react项目作为主应用。一个vue项目、一个react项目作为微应用。
1.创建主应用react项目:micro-app-base,输入cmd命令
create-react-app micro-app-base
2.创建微应用1 vue项目:micro-app-vue,输入cmd命令
vue create micro-app-vue
如图所示选择手动配置
接下来的很多选择如图
3.创建微应用2 react项目:micro-app-react,输入cmd命令
create-react-app micro-app-react
1.先安装好react-router-dom和micro-app
输入cmd命令
$ yarn add react-router-dom 或 npm i react-router-dom
npm i @micro-zoe/micro-app --save
2.修改index.js文件
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import microApp from '@micro-zoe/micro-app'
import { BrowserRouter,Link} from 'react-router-dom'
microApp.start()
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<Link to="/app1">react应用</Link>
<Link to="/app2">vue应用</Link>
<App />
</BrowserRouter>
{/**切换导航,将微应用渲染到container容器中 */}
<div id="container"></div>
</React.StrictMode>
);
// 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();
3.修改App.js文件
import { Route, Routes } from 'react-router-dom';
import './App.css';
import React from 'react';
import AppOne from './AppOne';
import AppTwo from './AppTwo';
function App() {
return (
<div className="App">
<Routes>
<Route path = "/app1" element={<AppOne />}/>
<Route path = "/app2" element={<AppTwo />}/>
</Routes>
</div>
);
}
export default App;
4.在scr文件夹下创建AppOne.js和AppTwo.js文件
AppOne.js:
import React from "react";
function AppOne() {
return <div>
<h1>AppOne</h1>
<micro-app name='app1' url='http://localhost:3001/' baseroute='/app1'></micro-app>
</div>
}
export default AppOne;
AppTwo.js
import React from "react";
function AppTwo() {
return <div>
<h1>AppTwo</h1>
<micro-app name='app2' url='http://localhost:3002/' baseroute='/app2'></micro-app>
</div>
}
export default AppTwo;
1.在 src 目录新增 public-path.js:
// __MICRO_APP_ENVIRONMENT__和__MICRO_APP_PUBLIC_PATH__是由micro-app注入的全局变量
if (window.__MICRO_APP_ENVIRONMENT__) {
// eslint-disable-next-line
__webpack_public_path__ = window.__MICRO_APP_PUBLIC_PATH__
}
2.在src文件夹下的router文件夹下的index.js文件中的顶部引入public-path.js:
// entry
import '../public-path'
import { createRouter, createWebHashHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
}
]
export default routes
在顶部引入
3.入口文件 main.js 修改,为了避免根 id #app 与其他的 DOM 冲突,需要限制查找范围。
import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router';
import App from './App.vue'
import routes from './router'
let history;
let router;
let app;
function render(props = {}) {
history = createWebHistory('/app2');
router = createRouter({
history,
routes
});
app = createApp(App);
let { container } = props;
app.use(router).mount(container ? container.querySelector('#app') : "#app")
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
export async function bootstrap() {
console.log('[vue] vue app bootstraped');
}
export async function mount(props) {
console.log('[vue] props from main framework', props);
render(props);
}
export async function unmount() {
console.log('[vue] vue app unmount');
history = null;
app = null;
router = null;
}
4.打包配置修改(vue.config.js):
const { name } = require('./package');
module.exports = {
lintOnSave: false,
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
},
},
configureWebpack: {
output: {
library: `${name}-[name]`,
libraryTarget: 'umd', // 把微应用打包成 umd 库格式
},
},
};
以 create-react-app 生成的 react 项目为例,搭配 react-router-dom 6.x。
1.在 src 目录新增 public-path.js:
// __MICRO_APP_ENVIRONMENT__和__MICRO_APP_PUBLIC_PATH__是由micro-app注入的全局变量
if (window.__MICRO_APP_ENVIRONMENT__) {
// eslint-disable-next-line
__webpack_public_path__ = window.__MICRO_APP_PUBLIC_PATH__
}
2.入口文件 index.js 修改,并在顶部引入public-path.js。为了避免根 id #root 与其他的 DOM 冲突,需要限制查找范围。
// entry
import './public-path';
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
// 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();
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'));
}
4.修改 webpack 配置
安装插件 @rescripts/cli
npm i -D @rescripts/cli
根目录新增 .rescriptsrc.js:
const { name } = require('./package');
module.exports = {
webpack: (config) => {
config.output.library = `${name}-[name]`;
config.output.libraryTarget = 'umd';
return config;
},
devServer: (_) => {
const config = _;
config.headers = {
'Access-Control-Allow-Origin': '*',
};
return config;
},
};
修改 package.json:
- "start": "react-scripts start",
+ "start": "rescripts start",
- "build": "react-scripts build",
+ "build": "rescripts build",
- "test": "react-scripts test",
+ "test": "rescripts test",
- "eject": "react-scripts eject"
根目录新增 .env:
PORT = 3001