微前端的基础知识介绍及使用Next.js的实现教程

1,809 阅读8分钟

在一个大型项目上工作并管理其代码库对团队来说是一个很大的挑战。尽管微前端已经出现了一段时间,但由于其独特的功能和可用性,它们正变得越来越流行。

微前端特别有帮助,因为多个团队可以在同一个项目的个别模块上工作,而不必担心其他模块。有了微前端,在当前的系统中加入多少个模块并不重要。

在这篇文章中,我们将介绍什么是微前端的基本知识,以及如何使用Next.js实现它。我们还将讨论在你的应用程序中使用微前端的优势。

微型前端的介绍

对于初学者来说,微型前端不遵循任何特定的结构,没有固定的边界。

那么,一个微型前端有多小呢?这个问题还没有答案。底线是,你应该把你的项目分割开来,这样用户体验就不会受到干扰了。这个过程可能是痛苦的,因为它很可能包括多次白板的修改。

你的项目很可能会随着时间的推移而发展,你可能需要边走边修改你的微型前端。

Micro Frontend Structure

图片来源:https://microfrontends.com/。

React是一个流行的前端技术栈,以其实用性和功能而闻名。使用React的微观前端是最重要的。而这正是Next.js的优势所在。

Next.js有大量的好处,包括:

  • 内建的路由器支持。不需要额外的软件包
  • 内置的CSS和TypeScript支持
  • 自动设置,基于页面的路由
  • 易于为生产构建
  • 图像优化和国际化的SDK
  • 内置的无服务器功能(API路由)。

那么现在让我们看看如何用Next.js创建一个微前端吧

用Next.js实现一个微前台

我们将使用模块联盟,这在技术上是webpack v5的一个功能。它允许一个应用程序的多个构建,并作为一个单体运行。

有些人可能认为模块联合是一个新的JavaScript功能,但它实际上只是一个架构原则,可以动态地从其他构建器加载代码。如果你想在现有的系统中增加一个新的微观前端,这是非常好的;你可以在不影响当前的情况下快速完成。

前提条件

假设你的机器上已经安装了Node,我们将构建三个Next.js微前端。我们将在第一个微前端中公开一个组件,在第二个微前端中公开一个通用函数。然后我们将在第三个微前端中使用这些暴露的项目,基本上使其成为每个导出模块的消费者。

你的Next.js应用程序应该是10.2或更高版本,以便支持webpack 5。否则,你需要使用一个外部包,以支持模块联合。在本教程中,我使用Next.js v12.2.0。

设置微型前端

首先,通过运行给定的命令在一个目录中创建三个前端。

> mkdir next_microfrontend
> npx create-next-app fe1
> npx create-next-app fe2
> npx create-next-app fe3

在第一个前端,即fe1 ,我们将创建一个Header ,该组件将被暴露。我们将在文件src/component/Header.jsx 中这样做。

import * as React from 'react'

const Header = () => {
  return (
    <div
      style={{
        background: 'black',
        width: '100%',
        height: '100px',
        color: 'white',
        textAlign: 'center',
        display: 'flex',
        justifyContent: 'left',
        alignItems: 'center',
        fontSize: '24px',
        paddingLeft: '15px'
      }}>
      Name
    </div>
  );
};

export default Header;

现在,为了使其工作,我们需要将其添加到index.js 页面中。

import styles from '../styles/Home.module.css'
import Header from '../src/component/Header'

export default function Home() {
  return (
    <div className={styles.container}>
      <main className={styles.main}>
        <Header />
      </main>
    </div>
  )
}

如果你想看到输出,请运行npm run dev ,并访问 [http://localhost:3000/](http://localhost:3000/).它应该看起来像这样:

Micro Frontend Setup Output

现在,我们必须暴露我们的组件,使其对另一个微观前台全球可用。要做到这一点,我们需要对next.config.js 作如下修改:

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  webpack5: true, // Need to make it true for some versions of Next JS
  distDir: 'build', // Defined build directory
  webpack: (config, options) => { // webpack configurations
    config.plugins.push(
      new options.webpack.container.ModuleFederationPlugin({
        name:"fe1",
        filename: "remoteEntry.js", // remote file name which will used later
        remoteType: "var",
        exposes: { // expose all component here.
          "./header": "./src/component/Header"
        },
        shared: [
          {
            react: {
              eager: true,
              singleton: true,
              requiredVersion: false,
            }
          },
          {
            "react-dom": {
              eager: true,
              singleton: true,
              requiredVersion: false,
            }
          },
        ]
      })
    )
    return config
  }
}

module.exports = nextConfig

当我们构建fe1 ,你可以在以下位置找到另一个微前端中使用的JavaScript文件 [http://localhost:%5BPORT%5D/build/remoteEntry.js](http://localhost:%5BPORT%5D/build/remoteEntry.js).

很好,我们已经在fe1fe2 中创建了组件 !我们现在要创建一个共同的函数来公开。

让我们在fe2 中创建一个函数。

// utils/getSquareRoot.js
const squareRoot = (number) => {
  return Math.sqrt(number)
}

export default squareRoot;

现在让我们对next.config.js 进行同样的配置。

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  distDir: 'build',
  webpack: (config, options) => {
    config.plugins.push(
      new options.webpack.container.ModuleFederationPlugin({
        name:"fe2",
        filename: "remoteEntry_2.js",
        remoteType: "var",
        exposes: {
          "./squareRoot": "./utils/getSquareRoot"
        },
        shared: [
          {
            react: {
              eager: true,
              singleton: true,
              requiredVersion: false,
            }
          },
          {
            "react-dom": {
              eager: true,
              singleton: true,
              requiredVersion: false,
            }
          },
        ]
      })
    )
    return config
  }
}

module.exports = nextConfig

一旦我们构建了它。 [http://localhost:%5BPORT%5D/build/remoteEntry_2.js](http://localhost:%5BPORT%5D/build/remoteEntry_2.js)就可以开始使用了。

让我们把fe3 作为一个消费者。我们将使用fe1 的导出组件和fe2 的函数。

首先,让我们配置一下next.config.js

/** @type {import('next').NextConfig} */
const path = require('path');
const nextConfig = {
  reactStrictMode: true,
  distDir: 'build',
  webpack: (config, options) => {
    config.plugins.push(
      new options.webpack.container.ModuleFederationPlugin({
        name:"fe3",
        filename: 'static/consumerFile.js'
        remoteType: "var",
        remotes: {
            fe1: options.isServer ? path.resolve(../fe1/build/remoteEntry.js) : 'fe1',
            fe2: options.isServer ? path.resolve(../fe1/build/remoteEntry_2.js) : 'fe2',
        },
        shared: [
          {
            react: {
              eager: true,
              singleton: true,
              requiredVersion: false,
            }
          },
          {
            "react-dom": {
              eager: true,
              singleton: true,
              requiredVersion: false,
            }
          },
        ]
      })
    )
    return config
  }
}

module.exports = nextConfig

在这里,你可以看到,我们在webpack配置中定义了remoteremote 的工作是从给定的URL中消费,并使内容对该应用可用。它将根据我们指定的条件接受远程或本地依赖。

为了使用该文件,我们需要更新pages 下的_document.js 文件。

import { Html, Head, Main, NextScript } from 'next/document'

export default function Document() {
  return (
    <Html>
      <script src="http://localhost:3000/build/remoteEntry.js" />
      <script src="http://localhost:3001/build/remoteEntry_2.js" />
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}

让我们把该模块导入到index.js 文件中并使用它。

import Head from 'next/head'
import Image from 'next/image'
import styles from '../styles/Home.module.css'

// Importing modules
const Header = (await import('fe1/header')).default;
const squareRoot = (await import('app1/getSquareRoot')).default;

export default function Home() {
  return (
    <div className={styles.container}>
      <Head>
        <Header />
      </Head>
      <main className={styles.main}>
        <h1 className={styles.title}>
           Square root of 4: {squareRoot(4)}
        </h1>
      </main>
    </div>
  )
}

执行和结果

现在是时候检查它是否工作了。首先,构建并启动fe1fe2 。通过运行npm start dev ,启动fe3 ,并进入其各自的URL,检查输出:

Execution Results

Woah!我们刚刚把两个前台代码的内容消耗到我们的主前台中!

🚀 让我们施展一些魔法。

转到fe1 → src → component ,把数值从name 改为name updated 。然后,重新运行f2

你可以看到在fe1 中更新的新代码,而不用做任何事情。很神奇,对吗?

微型前台的优势

简单地说,微前端使Web应用程序更容易维护。如果你曾经是一个大型应用程序的一部分,你知道管理所有的东西是非常乏味的。

微前端的工作原理类似于分而治之的规则。现在,让我们了解一下使用微前端工作的最重要和最有价值的方面。

部署和安全

微前端架构的一个重要优势是,你可以将一个主体分离成可以独立部署的各个部分。在单独部署时,你可以在不处理其他片段的情况下进行维护和构建。

Varcel支持不同前端的单独 repo,不考虑语言和框架,将它们部署在一起。除此以外,你可以使用Netlify等部署服务。一旦部署完毕,你就可以把它作为一个单独的前端来使用。

当前端被大量受众使用时,它需要安全和稳健。为了使其安全,你可以使用通配符或单域、多域或SAN SSL证书等SSL证书。一个SAN或多域SSL证书可以确保多个网站和子域的安全。

可扩展性

有多个用JavaScript构建的框架,但如果你想在同一个项目上让不同背景的开发人员保持一致,这是否可能呢?答案是肯定的,因为有了微前端!

通过利用微前端架构的优势,你可以在一个项目中结合React、Vue和Angular。在我看来,它最终会产生最好的结果。

更快的开发速度

现在你知道,你的团队可以独立工作。很好,不再有不必要的混乱了!

你的团队可以随时开发和部署他们的前端。发布可以很快完成,因为与单个模块相关的依赖性为零。

定义微型前端的主要目标是更快的迭代。

易于测试

在跳入集成测试之前,最好先测试一个应用程序的各个部分。这一点可以在这里实现!

团队将在测试应用程序之前测试微前端,从而减少错误进入真实系统的机会。

除此以外,其他的优点是代码基数小,容易维护,并且能够快速添加或删除系统中的任何模块。

总结

在这篇文章中,我们讨论了微前端的概念,并给出了例子。希望你现在知道,它很容易被采用,而且有一些很好的功能

Next.js是相当干净的,并且遵循简单的微前端架构。我很期待看到Next在未来带来的关于微架构和服务器端渲染与微前端的发展。

就我个人而言,我喜欢微前端的编码风格,因为它很容易在团队之间维护。除此之外,前端的构建和安全也被管理得相当优雅。对于一个团队来说,这是一个非常激动人心的机会,因为在未来,这个概念很可能会发展到超越限制的程度!

后来,你不会发现微前端和单一骨架系统之间有什么不同。