preface

Hello, I’m Xiao Ling. With the increase of iterations and requirements, a project often forms a large project system in the later stage. This often leads to a number of problems, such as the need to update the entire application in each iteration, making the update iteration slow. The coupling degree between different modules is high, which can not be pluggable increment and maintenance.

With the rise of microservices, the back end has a good solution in this area. Front-end is currently popular to use Qiankun to build a micro front-end architecture.

What is qiankun

Qiankun: An open source micro-front-end framework based on Single-SPA. It has the following characteristics:

Simple – any JS framework can be used. Microapplication access is as simple as accessing an IFrame system, but it is not an IFrame.

Complete – contains almost all the basic capabilities needed to build a microfront-end system, such as style isolation, JS sandbox, preloading, etc.

Production availability – it has been tested and polished by a sufficient number of on-line systems both inside and outside the ant and is reliable in its robustness.

Building the base application

Today we will use the Vue project as a base to combine Vue and React sub-applications to build a micro front-end architecture. For your convenience, I have arranged the architecture diagram below:

The three applications to be built are the main Vue application (QK-Base), Vue sub-application (QK-VUE), and React sub-application (QK-React).

// Vue main application (base)
vue create qk-base
// Vue subapplication
vue create qk-vue
// react child application
npx create react-app qk-react
Copy the code

Once created, the folder will have the following three projects:

Main application (dock) configuration

Menu and style configuration

In order to facilitate the switching of display applications, we configured the home page of the main application, using the menu of Element-UI to optimize its display. It can be switched to display different application information.

Install elementUi

npm i element-ui -S

// main.js
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
Copy the code

App.vue

<el-menu :router="true" class="el-menu-demo" mode="horizontal" >
  <el-menu-item index="/">Main Application page</el-menu-item>
  <el-menu-item index="/vue">Vue applications</el-menu-item>
  <el-menu-item index="/react">The react application</el-menu-item>
</el-menu>
    <router-view></router-view>
    <! -- Load VUE child application -->
    <div id="vue"></div>
    <! React app -->
    <div id="react"></div>
Copy the code

Here, we set the path of the Vue child reference to start with ‘/ Vue ‘and the React child application to start with ‘/ React’. And receive them with two divs id=”vue” and id=”react”.

It is worth mentioning that the route of the main application can also be switched through router-view.

Main application Qiankun configuration

Install qiankun

Yarn Add Qiankun # or NPM I Qiankun-sCopy the code

The introduction of qiankun

main.js

import { registerMicroApps, start } from 'qiankun';
// ...
let apps = [
  {
    name: 'vue faxian'.// Name of the child application
    entry: '//localhost:10000'.// The default is to load the HTML parser inside the JS execution dynamically, because the requested resource subapplication needs to support cross-domain
    container: '#vue'.// Hang to that node
    activeRule: '/vue'.// Attach the port number to the URL when accessing it
  },
  {
    name: 'react exam'.entry: '//localhost:20000'.container: '#react'.activeRule: '/react',},]; registerMicroApps(apps);// Register the application
start({
  prefetch: false // Cancel preloading
}); / / open
Copy the code

We use ports 10000 and 20000 to listen on Vue and React respectively.

Sub-application Vue configuration

Three functions (which must be promise) are required in the child application: bootstrap(), mount(), and unmount(). We use async to export it here.

main.js

// Subcomponent protocol
/** ** startup ** /
export async function bootstrap(){}
/** * when created *@param {*} Data passed by the props parent application */
export async function mount(props){
  render(props)
}
/** ** when uninstalling */
export async function unmount(){
  instance.$destroy();
  instance.$el.innerHTML = "";
  instance = null;
}
Copy the code

We need to update some configuration of the subapplication route, including setting the root directory and setting it to history mode:

router/index.js

// your router config ...

const router = new VueRouter({
    mode: 'history'.// Set the routing mode to history
    base:'/vue'.// Set the root directory to /vue
    routes
})
export default router;

Copy the code

Set the render() method to create the vue instance, which is mounted to its OWN HTML, and the base will take the mounted HTML and insert it.

main.js

function render(){
  instance = new Vue({
    router,
    // store // Can also pass the vuex of the parent application
    render: h= > h(App),
  }).$mount('#app') // This is mounted to its OWN HTML. The base will take the mounted HTML and insert it
}
Copy the code

The parameter __POWERED_BY_QIANKUN__ was provided to determine whether it was running independently.

main.js

// Use the WebPack runtime publicPath configuration
if(window.__POWERED_BY_QIANKUN__){ // Add public_path dynamically
  // eslint-disable-next-line no-undef
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
// Run the microapplication independently
if (!window.__POWERED_BY_QIANKUN__) { // Run independently by default
  render();
}
Copy the code

Finally, we can configure the package.

vue.config.js

module.exports = {
    devServer: {port:10000.// Enable port 10000 to listen
        headers: {'Access-Control-Allow-origin':The '*' // Configure the local runtime to allow cross-domains}},configureWebpack: {output: {library: 'vueApp'.libraryTarget: 'umd'}}}Copy the code

Results after running:

Configure the React sub-application

To configure the React project, we first need to rewrite the configuration file. Here we use the react-app-rewired function to wire our React configuration.

yarn add react-app-rewired
Copy the code

Change our startup to react-scripts and react-app-rewired:

package.json

"scripts": {
    "start": "react-app-rewired start"."build": "react-app-rewired build"."test": "react-app-rewired test"."eject": "react-app-rewired eject"
  }
Copy the code

Create the config file config-overrides. Js in the root directory

config-overrides.js

module.exports = {
    webpack:(config) = > {
        config.output.library = 'reactApp'; // Package class library, project name
        config.output.libraryTarget = 'umd'; 
        config.output.publicPath = 'http://localhost:20000/'; / / port
        return config;
    },
    devServer:(configFunction) = >{
        return function(proxy,allowedHost){
            const config = configFunction(proxy,allowedHost);
            config.headers = {
                'Access-Control-Allow-origin':The '*' // All configurations are allowed across domains
            }
            returnconfig; }}}Copy the code

Env Configure the port number

.env

PORT = 20000
WDS_SOCKET_PORT= 20000
Copy the code

As in the previous project, we need to export three methods with fixed names: bootstrap(), mount(), and unmount().

src/index.js

// Subcomponent protocol
/** ** startup ** /
 export async function bootstrap(){}
 /** * when created *@param {*} props 
  */
 export async function mount(props){
   render(props)
 }
 /** ** when uninstalling *@param {*} props 
  */
 export async function unmount(){
  ReactDOM.unmountComponentAtNode(document.getElementById('root'));
 }
Copy the code

Encapsulate a render() to render the local runtime so that it can run independently.

src/index.js

function render(){
  ReactDOM.render(
    <React.StrictMode>
      <App />
    </React.StrictMode>.document.getElementById('root')); }// Run the microapplication independently
if (!window.__POWERED_BY_QIANKUN__) { // Run independently by default
  render();
}
Copy the code

Then we configure ReactRouter

Install the router

yarn add react-router-dom
Copy the code

The router and page are simply configured here

function App() {
  return (
    <BrowserRouter basename='/react'>
      <Link to='/'>Home page</Link>
      <Link to='/about'>On the page</Link>

      <Route path='/' exact render={()= > <div className="App">Home page</div>} ></Route>
      <Route path='/about' exact render={()= > <div className="App">On the page</div>} ></Route>
    </BrowserRouter>
  );
}

export default App;
Copy the code

Yarn start starts to read our own configuration file

End result:

Data communication

For example, we now need to synchronize user information from the main application to the child application.

We can pass parameters by configuring the main application’s main.js, which can be vuex or redux

Receive this parameter in the mount method of the child application

qk-vue main.js

export async function mount(props){
  if(props? .userInfo){console.log(props.userInfo)
    // Set the parameters from the main application
    window.sessionStorage.setItem('userInfo',props.userInfo);
  }
  render(props)
}
Copy the code

The problem

Faqs and Solutions: Problems and solutions

Project address and official website

Website address of Qiankun

Above code project address: project address

If you have any questions, please comment. If you think xiao Ling’s writing is good, please give xiao Ling a thumbs up. Your support is my motivation to move forward 🙂