如何用React做微观前台

99 阅读6分钟

微前端是微服务的对应物。微服务是一种将单体后端应用分割成更小的服务的架构,而微前端可以用来在前端实现同样的目的。但它们还没有像微服务那样流行。

对于我的最后一个客户,我为微前端React与Webpack的方案做了一个实验性的秒杀。这里我想分享一下我的成果。完成的实验性微前端应用可以在这里找到。

React前台

我们将从这个带有Webpack的高级React设置开始。你还需要安装React Router。让我们一步一步地浏览React组件。这是我们的src/index.js根入口点:

import React from 'react';import ReactDOM from 'react-dom';
import App from './App';
const title = 'My React Micro Frontend';
ReactDOM.render(  <App title={title} />,  document.getElementById('app'));

在这里,我们在src/App/index.js 中有一个 App 组件:

import React from 'react';import {  BrowserRouter as Router,  Routes,  Route,  Link,} from 'react-router-dom';
import * as routes from '../constants/routes';import Programming from '../Programming';import Installation from '../Installation';
const App = ({ title }) => (  <Router>    <h1>{title}</h1>
    <ul>      <li>        <Link to={routes.PROGRAMMING}>Programming</Link>      </li>      <li>        <Link to={routes.INSTALLATION}>Installation</Link>      </li>    </ul>
    <Routes>      <Route path={routes.PROGRAMMING} element={<Programming />} />      <Route path={routes.INSTALLATION} element={<Installation />} />    </Routes>  </Router>);
export default App;

App组件负责使用React路由器进行路由,因此显示带有链接的导航,并根据路由渲染一个编程或安装组件。这两个组件将是我们的微型前端。但以后会有更多关于这方面的内容。

为了完整起见,这是src/constants/routes.js文件:

export const PROGRAMMING = '/';export const INSTALLATION = '/installation';

每个微型前端组件,这里是安装和编程,都存在于它们自己的文件夹中。一个在src/Installation/index.js,一个在src/Programming/index.js

// src/Installation/index.js
import React from 'react';
const Installation = () => (  <div style={{ backgroundColor: 'yellow', padding: '20px' }}>    <h1>Installation</h1>  </div>);
export default Installation;
// src/Programming/index.js
import React from 'react';
const Programming = () => (  <div style={{ backgroundColor: 'green', padding: '20px' }}>    <h1>Programming</h1>  </div>);
export default Programming;

文件夹结构应该与此相似。

- src/-- App--- index.js-- constants--- routes.js-- Installation--- index.js-- Programming--- index.js

到目前为止,所有的组件几乎都是相互耦合的。App组件渲染了安装和编程组件。让我们转移到我们的Webpack设置,用这些React组件启用微前端架构。

Webpack微前端

我们将从package.json文件开始,并将所有的层级下移到我们的Webpack配置文件中。之前我们只有一个脚本来启动这个React应用程序。现在我们用另外两个命令来扩展它,以启动我们的一个微前端。

package.json

{  ...  "scripts": {    "start": "webpack serve --config build-utils/webpack.config.js --env env=dev",    "start:programming": "webpack serve --config build-utils/webpack.config.js --env env=dev --env micro=Programming",    "start:installation": "webpack serve --config build-utils/webpack.config.js --env env=dev --env micro=Installation",    ...  },  ...}

与之前的启动脚本相比,唯一改变的是这些新的--env micro 标志。这就是我们如何在Webpack中区分哪个应用程序应该作为微型前端启动。我们的build-utils/webpack.config.js文件看起来像这样。

const webpackMerge = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
const getAddons = addonsArgs => { ... };
module.exports = ({ env, addon }) => {  const envConfig = require(`./webpack.${env}.js`);
  return webpackMerge(commonConfig, envConfig, ...getAddons(addon));};

注意:环境配置取决于另一个env 标志,它被传入以评估开发或生产构建之间。getAddons 功能是可选的,如果你有Webpack附加组件。再看看如何用Webpack设置构建过程和附加组件

现在我们把这个实现改为如下。

...
module.exports = ({ env, micro, addon }) => {  const envConfig = require(`./webpack.${env}.js`);  const commonConfig = require('./webpack.common.js')(micro);
  return webpackMerge(commonConfig, envConfig, ...getAddons(addon));};

这个变化假定我们的build-utils/webpack.common.js文件不再输出一个配置对象,而是一个返回配置对象的函数。基本上取决于micro 标志,这个函数返回一个合适的配置。我们在这里做的是普通Webpack配置,但如果在开发或生产Webpack配置文件中需要这个标志的话,它也可以同样工作。

现在在build-utils/webpack.common.js文件中,我们只需要调整两件事。我们将以下对象进行了转换。

module.exports = {  entry: './src/index.js',  ...};

到一个函数,它返回一个对象,有micro 标志作为参数,并根据我们是否要返回一个微型前端,返回适当的入口点文件。如果没有micro 标志,我们返回渲染App组件的标准src/index.js 文件,如果有micro 标志,我们返回我们源文件夹中的一个动态文件。

module.exports = micro => ({  entry: micro ? `./src/${micro}/standalone.js` : './src/index.js',  ...});

我们还没有这个standalone.js文件。我们需要在源文件夹中为我们的微型前端提供这些新的入口文件。这发生在接下来。

React微前端

让我们来看看第一个微型前端的standalone.js文件,它是src/Installation/standalone.js

import React from 'react';import ReactDOM from 'react-dom';
import Installation from '.';
const InstallationStandalone = () => {  const props = {};
  return <Installation isStandalone {...props} />;};
ReactDOM.render(  <InstallationStandalone />,  document.getElementById('app'));

这个文件将之前在App组件中使用的常规安装组件,包装成另一个React组件(这里是InstallationStandalone)。然后这个新的包装组件被用来用React DOM渲染一切。

这个新的包装组件(InstallationStandalone)的重要之处在于,你可以向安装组件提供任何不再来自App组件的信息。以前,App组件可能会向安装组件提供数据。现在这些数据不再可用了,因为安装组件必须自己渲染。这就是InstallationStandalone组件发挥作用的地方,它以道具的形式提供这些数据。

我们可以对第二个微型前端standalone.js文件采用同样的方法,即src/Programming/standalone.js。注意isStandalone 标志,这有助于我们以后在微型前端组件(这里是Programming)中识别它是作为微型前端独立呈现还是作为更大的单体的一部分。

import React from 'react';import ReactDOM from 'react-dom';
import Programming from '.';
const ProgrammingStandalone = () => {  const props = {};
  return <Programming isStandalone {...props} />;};
ReactDOM.render(  <ProgrammingStandalone />,  document.getElementById('app'));

isStandalone 标志可以在每个组件中使用。我们将使用它来渲染一个指向其他微前端组件的链接,但只有在该组件本身不是微前端的情况下。在src/Installation/index.js中,我们会这样做。

import React from 'react';import { Link } from 'react-router-dom';
import * as routes from '../constants/routes';
const Installation = ({ isStandalone }) => (  <div style={{ backgroundColor: 'yellow', padding: '20px' }}>    <h1>Installation</h1>
    {!isStandalone && (      <ul>        <li>          <Link to={routes.PROGRAMMING}>Back to Programming</Link>        </li>      </ul>    )}  </div>);
export default Installation;

而在src/Programming/index.js中,我们这样做了。

import React from 'react';import { Link } from 'react-router-dom';
import * as routes from '../constants/routes';
const Programming = ({ isStandalone }) => (  <div style={{ backgroundColor: 'green', padding: '20px' }}>    <h1>Programming</h1>
    {!isStandalone && (      <ul>        <li>          <Link to={routes.INSTALLATION}>Back to Installation</Link>        </li>      </ul>    )}  </div>);
export default Programming;

现在你可以尝试运行你新的微前端npm脚本了。npm start ,用App组件创建整个单片机应用程序,而其他新的npm脚本只创建微前端。

npm run start:programmingnpm run start:installation

你可以单独运行这两个微前端。如果它们被单独运行,它们的独立包装组件被用来在HTML中渲染,并提供通常来自App组件的额外道具。


你所看到的只是关于如何用Webpack和React创建一个微型前端架构的第一波高潮。还有很多事情需要考虑:

  • 也应该有用于测试和构建的微型前端脚本。
  • 每个微型前端文件夹都应该有自己的package.json文件,以便在没有monolith的情况下执行其脚本?
    • 如果有的话,它是否应该从单体中列出所有的依赖关系,或者只是复制过来?
    • 所有的测试都应该从单片机上执行,还是转移到微型前端的package.json文件中?
  • 如何将微前端和单片机分离到它们自己的版本控制系统中?

无论如何,如果你正在寻找如何用React创建一个微型前端,我希望这个攻略能帮助你了解如何实现它。