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:
- Library: Basically define app1 and mount app1 as a global variable
- Name: The name of the shared library
- Remotes: Remote subproject
- 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:
- Consider a sandbox environment
- Child applications are nested
- Parent and child application communication problem
- 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!!