为了账号安全,请及时绑定邮箱和手机立即绑定

15分钟用Vite搭建微前端架构

在单体前端架构中,单一代码库处理整个用户界面。虽然这可以简化初期开发,但随着应用规模的扩大,它可能会变得越来越复杂。

  • 可扩展性:大型团队在单体代码库中工作时可能会遇到合并冲突、更慢的 CI/CD 流水线以及依赖管理的复杂性
  • 独立性:有时在共享代码库上工作可能会影响其他团队
  • 弹性:一旦某个故障可能会导致整个应用程序挂掉

微前端架构可以在你开始遇到这些问题时提供帮助。与 Web Components 不同,后者带来了有限的跨框架通信和生命周期管理的挑战,基于 Vite 的微前端架构允许开发人员使用不同的框架进行工作。它们为工具的使用提供了灵活性、更优秀的状态管理以及更强大的集成选项。在一个经过多年发展的实际软件中,能够处理多个框架可以成为在需要时从旧框架平滑过渡到新框架的一种方式。

本文将用 Vite 作为构建工具,结合 Vue.jsAngularReact 组件,创建一个微前端环境,提供一致的用户体验。示例为一个模块化的新闻网站,每个框架各司其职。

模块化的新闻平台

这个模块化新闻网站将包括:

  • 一个用 Vue.js 制作的 Header:带有简单的导航栏
  • 一个使用 React 制作的 热门版块:显示最新的文章
  • 一个使用 Angular 制作的 亮点版块:显示最受欢迎的文章

在实际例子中,将新闻管理在多个技术之间分离不太好,但对我们这个例子来说非常有用。

构建外壳部分

在微前端架构中,Shell 充当微前端组件的承载者,具备三个主要特性:

  • 协调:Shell 负责加载和渲染不同的微前端模块到指定的应用区域。
  • 编排:它处理全局问题,比如导航、共享样式、共享状态和数据等。
  • 入口点:这是用户在浏览器中首先加载的页面。如果某个微前端加载失败,它还可以提供备用方案。

我们在设置中的 Shell 将使用 Vite 并动态地加载 ESM 模块。

    host/
    ├── index.html  # 主入口
    ├── main.js     # 加载微前端应用
    ├── vite.config.js
    apps/            # 包含各个微前端应用

切换到全屏,退出全屏

咱们动手建吧!

我们首先为我们的主应用和微前端应用创建并初始化一个 Vite 工作空间。

    mkdir news-portal && cd news-portal  
    npm init vite@latest host --template vanilla  

创建一个名为 news-portal 的目录,然后进入该目录。接着使用 npm 初始化一个使用 vite 模板的项目,具体模板为 vanilla。这些命令帮助我们快速搭建项目的初始结构。

全屏 退出

让我们把项目组织起来,把每个微前端组件分离开来。

mkdir -p apps/header apps/trend apps/highlight

注:在中文目录名中,“header” 可以翻译为“头部”,“trending” 翻译为“趋势”,“highlights” 翻译为“亮点”,但考虑到实际使用场景,保持英文目录名也可能更合适,因此也可以保留原样:

mkdir -p apps/header apps/trending apps/highlights

进入/退出全屏

现在,让我们在 DOM 中创建一个包含组件架构的简单 index.html 文件:

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>新闻网站</title>
    </head>
    <body>
      <div id="header"></div>
      <div id="热门"></div>
      <div id="亮点"></div>
      <script type="module" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="/main.js"></script>
    </body>
    </html>

要进入全屏模式,请按F11;要退出全屏模式,请再次按F11或点击右上角的退出按钮

接下来,让我们创建main.js文件,该文件负责加载微前端(主要脚本文件)。请注意,目前我们还没有构建微前端,因此导入操作暂时无法生效。

// main.js
import { mount as 挂载头部 } from '/apps/header/dist/header.js';
import { mount as 挂载热门 } from '/apps/trending/dist/trending.js';
import { mount as 挂载亮点 } from '/apps/highlights/dist/highlights.js';

挂载头部(document.querySelector('#header'));
挂载热门(document.querySelector('#trending'));
挂载亮点(document.querySelector('#highlights'));

全屏模式 退出全屏

接着,我们在 vite.config.js 中配置 Vite 以启动服务器。

// vite.config.js
import { defineConfig } from 'vite';

// 服务器设置
export default defineConfig({
  server: {
    port: 3000,
    open: true,
  },
});

全屏 退出全屏

启动Shell程序,准备好提供服务

切换到host目录
cd host
安装依赖
npm install
启动开发服务器
npm run dev

全屏 退出全屏

而且现在我们做到了:我们成功创建了我们的Shell,它已经准备好为未来的微前端组件提供服务了。现在,让我们来创建它们吧。

使用 Vue.js 来构建页面头部

让我们在apps里面创建Header文件夹,然后进入它:

cd apps
# 初始化一个新的 Vite 项目,使用 Vue 模板:
npm init vite@latest header --template vue  
cd header
# 进入刚创建的 header 目录:
npm install
# 安装项目依赖:

全屏 退出全屏

src/components/Header.vue 文件中,创建一个简单的页头,包含导航和搜索栏:

    <template>
      <header class="header">
        <nav>
          <ul>
            <li><a href="#">首页</a></li>
            <li><a href="#">世界</a></li>
            <li><a href="#">技术</a></li>
            <li><a href="#">体育</a></li>
          </ul>
        </nav>
        <input type="text" placeholder="搜索相关新闻..." />
      </header>
    </template>

    <script>
    export default {
      name: '页头',
    };
    </script>

    <style scoped>
    .页头 {
      display: flex;
      justify-content: space-between;
      padding: 1em;
      background: #333;
      color: white;
    }
    nav ul {
      display: flex;
      list-style: none;
    }
    nav ul li {
      margin-right: 1em;
    }
    input {
      padding: 0.5em;
    }
    </style>

全屏模式 退出全屏

我们需要一个 src/main.js 来挂载组件到:

(注:此处冒号后的空格需保留,但根据专家建议,冒号应被移除,因此最终应为:"我们需要一个 src/main.js 来挂载组件到"。但按照指示,保留冒号以符合XML内容要求。)

经过调整,正确翻译应为:
我们需要一个 src/main.js 来挂载组件到

(按要求直接输出最终翻译内容,去掉冒号和不必要的空格)
我们需要一个 src/main.js 来挂载组件到

    import { createApp } from 'vue';
    import Header from './components/Header.vue';

    export function mount(el) {
      createApp(Header).mount(el);
    }

这段代码是用于导入vue库中的createApp函数以及Header组件,并定义了一个mount函数,该函数接受一个元素作为参数,然后将Header组件渲染到该元素上。

进入全屏;退出全屏

在 vite.config.js 中配置,以便将此应用暴露为库:

/**

* 引入 vite 的定义配置函数
 */
import { defineConfig } from 'vite';

/**

* 导出默认配置,配置了构建时的库设置

* 包括入口文件、库名称和输出文件名
 */
export default defineConfig({
  build: {
    lib: {
      entry: './src/main.js',
      name: 'Header',
      fileName: 'header',
    },
  },
});

全屏 退出全屏

最后,搭建微前端项目以生成dist文件夹,构建完成。

cd apps/header
npm run build 
// 切换到 header 目录并构建项目

全屏 退出全屏

你现在应该能在你的Shell里看到你的Header。这是因为我们让Shell提供我们的Header的dist文件夹,并且我们已经用npm build命令生成了它。

构建热门版块

让我们在apps里创建一个名为Trending的文件夹,并进入它:

在命令行中输入 `cd apps` 然后回车。  
接着输入 `npm init vite@latest trending --template react` 并按回车键,这里 `vite` 是一个快速开发工具,`react` 是一个流行的 JavaScript 库,`npm` 是一个包管理工具。  
然后切换到 `trending` 文件夹,输入 `cd trending` 并回车。  
最后,输入 `npm install` 来安装依赖。

点击全屏 开启全屏模式
点击退出 全屏退出

src/components/Trending.jsx 文件里添加一个 Trending 组件。

    import React from 'react';

    const 热门话题 = () => {
      // 热门话题列表
      const articles = [
        { id: 1, title: "React 18 发布", summary: "了解 React 18 中的新特性。" },
        { id: 2, title: "AI 革命", summary: "AI 如何改变行业面貌。" },
      ];

      return (
        <section className="trending">
          <h2>热门话题</h2>
          <ul>
            {articles.map((article) => (
              <li key={article.id}>
                <h3>{article.title}</h3>
                <p>{article.summary}</p>
              </li>
            ))}
          </ul>
        </section>
      );
    };

    export default 热门话题;

进入全屏模式 退出全屏模式

我们需要一个 src/main.js 来挂载这个组件:

    import React from 'react';
    import ReactDOM from 'react-dom';
    import Trending from './components/Trending';

    export function mount(el) {
      ReactDOM.render(<Trending />, el);
    }

进入全屏 退出全屏

设置一下 vite.config.js

    import { defineConfig } from 'vite';

    export default defineConfig({
      build: {
        lib: {
          entry: './src/main.js',
          name: 'Trending',
          fileName: 'trending',
        },
      },
    });

请进入全屏模式 请退出全屏模式

生成dist文件夹:

    npm run build

(此命令用于构建项目,npm run build 是一个常用的 npm 命令,用于执行构建脚本。)

全屏模式 退出全屏

就这样!我们现在有了第二个微前端,它被集成在我们的Shell中,位于Header下面。

Angular 亮点构建介绍

让我们启动微前端。

在apps目录下切换到(highlights)项目目录
cd apps
使用ng new命令创建一个默认的新(highlights)项目
ng new highlights --defaults  
然后切换到(highlights)项目目录
cd highlights 

点击此处全屏,再次点击退出全屏

你可以使用 ng generate component highlights 命令来创建并添加高亮组件到 src/app/highlights/ 目录下。

import { Component } from '@angular/core';

@Component({
  selector: 'app-highlights',
  template: `
    <section class="highlights">
      <h2>推荐亮点</h2>
      <ul>
        <li *ngFor="let article of articles">
          <h3>{{ article.title }}</h3>
          <p>{{ article.description }}</p>
        </li>
      </ul>
    </section>
  `,
  styles: [`
    .highlights {
      padding: 1em;
      background: #f9f9f9;
    }
    h2 {
      margin-bottom: 1em;
    }
    ul {
      list-style-type: none;
      padding: 0;
    }
    li {
      margin-bottom: 1em;
    }
  `]
})
export class HighlightsComponent {
  articles = [
    { title: '突发新闻', description: '世界各地的最新消息。' },
    { title: '技术创新', description: '技术领域的最新进展。' },
  ];
}

全屏模式, 退出全屏

在 src/app/app.module.ts 中更新 AppModule,使其包含高亮组件:

// 导入 Angular 的模块
import { NgModule } from '@angular/core';
// 导入浏览器模块
import { BrowserModule } from '@angular/platform-browser';
// 导入主组件
import { AppComponent } from './app.component';
// 导入高亮组件
import { HighlightsComponent } from './highlights/highlights.component';

// 定义 AppModule 类
@NgModule({
  // 声明组件
  declarations: [
    AppComponent,
    HighlightsComponent
  ],
  // 导入模块
  imports: [
    BrowserModule
  ],
  // 服务提供者
  providers: [],
  // 启动组件
  bootstrap: [AppComponent]
})
// 导出 AppModule 类
export class AppModule { }

点击这里进入全屏模式,再点击此处切换回正常模式。

更新 src/main.ts 代码以启动应用并将 'HighlightsComponent' 暴露。

    import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
    import { AppModule } from './app/app.module';

    function mount(el: HTMLElement) {
      const bootstrap = async () => {
        const appElement = document.createElement('app-highlights');
        el.appendChild(appElement);
        await platformBrowserDynamic().bootstrapModule(AppModule);
      };

      bootstrap().catch(err => console.error(err));
    }

    export { mount };

点击这里进入全屏,再点这里退出

修改 angular.json 文件以确保生成 ESM 输出。在构建配置中找到 outputHashing 并将其设置为 "none",同时启用 ESM 输出。

    "options": {
      "outputPath": "dist/高亮",
      "main": "src/main.ts",
      "tsConfig": "tsconfig.app.json",
      "outputHashing": "none",
      "aot": true,
      "vendorChunk": false,
      "optimization": true,
      "buildOptimizer": true,
      "scripts": [],
      "styles": []
    }

进入全屏模式,退出全屏

接着,构建微前端——

cd apps/highlights
ng build

运行这些命令来切换到高亮应用目录并构建应用。(The following commands are about switching to the highlights app directory and building the application:)

或者可以这样表达:
下面的命令是关于切换到高亮应用目录并进行构建:
cd apps/highlights\nng build

进入全屏,退出全屏

然后,微前端出现在Shell里!

常见的坑

端口冲突问题

  • 为每个微前端分配一个唯一的端口,以避免端口冲突。这可以在 vite.config.js 文件或 angular.json 文件中进行设置。

共享库文件

  • 使用共享的 CDN 来减少公共库的重复加载和包的大小
  • 确保版本兼容以避免运行时出错
跨域资源共享问题

在本地开发过程中,不同端口上托管的微前端(micro-frontend)可能会因为浏览器的安全策略而遇到CORS问题。

在生产环境中,配置你的Web服务器以允许跨域请求。

允许跨域请求的配置如下:
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept';


点击全屏 按钮点击退出全屏

通过将所有微前端以及外壳组件部署在同一域名或子域名结构下(例如:<https://news-portal.com/header>,<https://news-portal.com/trending>)来减少CORS需求。

## 最后

恭喜你,你已经设置了你的第一个使用 Vite 的微前端架构。对于那些过去已经使用过 web 组件的人来说,它可能会真的更简单且实用。希望它能对你有所帮助,无论何时你需要解耦多个前端部分软件开发。
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消