The introduction

Hello ~

Over the weekend, explore the new ability Federation provided by Webpackage 5. This article mainly uses this function to build the micro-front-end environment from 0-1. At the end of the paper, the micro front end will be analyzed.

There is a lot of talk in the community about the microfront end, the sandbox environment, the value of the microfront end, the downsides, and so on. Several links will be listed at the end of the article, so if you are interested, you will not have to go over them here.

Webpack Federation

Federation is a new capability provided by webpack5. According to the website, “multiple independent builds can form an application. These independent builds should not be dependent on each other, so they can be developed and deployed separately.”

The main API

const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      shared: {},  // The dependent library to share
      library: {}, // The definition of the current module to exportRemotes: {},// Other child definitions
      filename: ' '.// The name of the file to export
      exposes: {} // The exported module})]};Copy the code

start

In a project, there are many sub-modules and a common base. In order to put all the projects in one file conveniently, this paper naturally chooses lerna, a popular package management tool

Project initialization

mkdir federation-demo
cd federation-demo & yarn init
yarn add lerna
lerna init
Copy the code

Once the project is initialized, it’s time to write the correct run commands

  "scripts": {
    "init": "lerna init"."build": "lerna run --parallel build"."serve": "lerna run --parallel serve"
  }
Copy the code

The directory structure of the project

Federation-demo/Packages/APP1 app2 Package. json Lerna. jsonCopy the code

Build a base (APP1)

React is mainly used to build simple applications.

App1 directory structure

app1/
  public
    index.html
  src
    app.js
    index.js
  webpack.config.js
  package.json
Copy the code

To facilitate debugging, use serve to start a static server. Package. json commands are as follows:

  "scripts": {
    "start": "webpack serve",
    "build": "webpack --mode development",
    "serve": "serve dist -p 8888"
  }
Copy the code

public/index.html

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Project a</title>
    <script src="xxxxx"></script><! -- Remote exposed address, path of child application -->
</head>
<body>
    <h1>Project a</h1>

    <div id="app"></div>
</body>
</html>
Copy the code

scr/app.js

import React from 'react'
const { lazy, Suspense} = React

const App2 = lazy(() = > import('app2/App2')) / / application

const App = () = > (
    <div>
        <h1>The container application</h1>

        <Suspense fallback="loading">
            <App2 />
        </Suspense>
    </div>
)

export default App
Copy the code

src/index.js

import React from 'react'
import ReactDOM from 'react-dom'
import App from './app'

ReactDOM.render(<App />.document.getElementById('app'))
Copy the code

The react page is a simple application. The next step is to configure webpack.config.js, which is developed using Federation’s capabilities.

React builds with Babel and other necessary libraries, such as Webpack

yarn add babel-loader @babel/core @babel/preset-env @babel/preset-react webpack webpack-cli -D
Copy the code

Some necessary tools and libraries are installed on it, but for convenience, a library needs to be installed so that the service can be started and tested

yarn add serve
Copy the code

Webapck.config. js configuration (some configuration will be ignored here, such as the react configuration, I believe you are familiar with it). Here are the main configurations:

module.exports = {
    plugins: [
        new ModuleFederationPlugin({
            name: 'app1',
            library: { type: 'var', name: 'app1' },
            remotes: { app2: 'app2' },
            shared: {
                react: {
                    singleton: true,
                    eager: true,
                },
                'react-dom': {
                    singleton: true,
                    eager: true,
                }
            },
        }),
    ]
}
Copy the code

Resolution:

  1. Library: Basically define app1 and mount app1 as a global variable
  2. Name: The name of the shared library
  3. Remotes: Remote subproject
  4. Shared: A dependency that needs to be shared.

Now that the basic base environment has been written, let’s build the child application.

The child applications (app2)

In fact, the subapp is similar to the base, so we just copy it and modify it a little bit.

public/index.html

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>The second project</title>
</head>
<body>
    <h1>The second project</h1><div id="app"></div>
</body>
</html>
Copy the code

src/app.js

import React from 'react'
import Button from './button'const App = () = > (
    <div>
        <h2>The child application</h2><Button />
    </div>    
)
​
export default App
Copy the code

src/index.js

import React from 'react'
import ReactDOM from 'react-dom'
import App from './app'
​
ReactDOM.render(<App />.document.getElementById('app'))
Copy the code

To demonstrate the flexibility of the component, we will also remove a button component SRC /button.js for App2

import React from 'react'const Button = () = > <button>I'm the button for the child app</button>export default Button
Copy the code

The configuration of webpack.config.js is a little different from that of app1, as follows:

module.exports = {
    plugins: [
        new ModuleFederationPlugin({
            name: 'app2'.library: {
                type: 'var'.name: 'app2'
            },
            exposes: {
                './App2': './src/app'.// The component to expose
                './Button': './src/button'
            },
            filename: 'remote.js'.// The exposed file name})],}Copy the code

The main task of sub-application is to expose the corresponding JS, so that the main application to be used is loaded into the corresponding JS file (equivalent to the entry file).

The principle is actually very simple, app2 is exposed separately: the entire application and a button component, when you need to use this content, load the JS file, and then use the corresponding exposed component.

Project running

With the capabilities provided by Lerna, commands related to packaging and starting servers can be run directly from the root directory

yarn build
Copy the code

At the same time, start the packaging of sub-projects to avoid the packaging of one project by one project, too tedious.

Once the package is complete, you can start the static server. Test items: APP1. Start on port 8888, app2 on port 8889.

Path to open app1:

You can see that the project is running properly and the Federation loads the contents of other projects, including the components of other projects (provided, of course, that other projects are exposed).

Open the console at this time, you can see the package produced by Webpack intuitively, the most important files are: remote. Js, src_app_js.js, src_button_js.js

The most important package is remote.js. After loading this package, the application will load corresponding components such as APP, Button, etc.

In the remote. Js code, you can see that App2 is globally mounted as var

Main.js, using the custom module mechanism unique to WebPack, mounts App2 into the module so that when the main application visits, it can access something from the child application.

conclusion

At present, there are many micro front-end implementation schemes, such as IFrame, Qiankun, Web Component and so on. But the common problems to be solved are likely to be the following:

  1. Consider a sandbox environment
  2. Child applications are nested
  3. Parent and child application communication problem
  4. The public relies on

Webpack provides the ability to federation, and it may be that tools evolve with The Times, but webPack configuration can be a bit challenging for beginners.

Personally, the concept of a micro front end complicates the application, essentially integrating different technologies. However, on second thought, popular frameworks such as Vue and React have the same concept: components, compilation and responsiveness, but the corresponding processing may be different.

Will Vue and React slowly fade out like Jq when the native Web components of browsers are well supported?

END

These are some practices and ideas for Webpack’s new features over the weekend

I’m Gavin, let’s go!!