2022 你还不会微前端吗 (上) — 从巨石应用到微应用(二)

简介: 2022 你还不会微前端吗 (上) — 从巨石应用到微应用

路由配置

路由模式为 hash 模式,自定义路由配置:

<Router>
    <Switch>
      <Route path="/" exact>
        <Home />
      </Route>
      <Route path="/about" exact>
        <About />
      </Route>
    </Switch>
</Router>
复制代码

打包配置

对于 React 应用来讲,要么是一开始就是自定义 webpack 相关配置,要么是基于 crate-react-app 内置的 webpack 配置进行修改,由于上面是通过 crate-react-app 的方式创建的项目,因此可以基于其内置的配置文件进行修改:

不想通过 eject 的方式去修改配置文件,可通过 react-app-rewired 进行重写

  • 执行 npm run eject 将内置的 webpack 配置像暴露出来,会生成一个 scripts 目录 和 config 目录

image.png

  • 这里只需要关注 config 目录即可,因为 webpack.config.js 在该目录下
  • image.png
  • 为其中的 output 配置添加上如下两行配置项即可(需重新启动)
output: {
    library: 'singleReact',
    libraryTarget: 'umd',
    globalObject: 'window',
    ....
 }
复制代码

创建基座应用

基座应用的技术栈这里选择 Vue2,同样可以通过 vue create vue2-main-app 的方式创建对应的基座应用:

image.png

路由配置

为了让 基座应用 的路由看起来更美观,这里选择 history 模式(也可选 hash 模式),接着配置具体路由:

  • 基座应用的路由
  • 配置对应的路由路径
  • 指定对应组件作为路由渲染视图,如 HomeView 组件
  • 微应用的路由
  • 只需要设定对应的路由路径,不需要指定对应的具体组件
import Vue from 'vue'
import VueRouter, { RouteConfig } from 'vue-router'
import HomeView from '../views/HomeView.vue'
Vue.use(VueRouter)
const routes: Array<RouteConfig> = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/vue3-micro-app',
    name: 'about',
  },
  {
    path: '/react-micro-app',
    name: 'about',
  }
]
const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})
export default router
复制代码

子应用挂载容器

基座应用中的 <router-view /> 是为了渲染基座应用自身的路由视图,而子应用是不能通过 <router-view /> 来渲染,因此,我们需要在基座应用中设定一个 Dom 节点专门用于渲染子应用的视图,这里就将子应用的内容挂载在 <div id="micro-content"></div> 的节点中:

<!-- 主内容 -->
<main class="content">
  <!-- 基座应用路由视图渲染 -->
  <router-view />
  <!-- 子应用挂载容器 -->
  <div id="micro-content"></div>
</main>
复制代码

菜单配置

菜单配置实际就是指定路由的跳转,具体包含内容如下:

  • Home 菜单渲染的视图内容是 基座应用 中对应的 HomeView 组件
  • Vue3-micro-app 菜单渲染视图是名为 vue3-micro-app子应用
  • Home 菜单渲染视图是基名为 react-micro-app子应用

基座应用注册子应用

基座应用 中尚未注册 子应用 时的页面效果如下:

image.png

为了切换菜单路由时,对应的子应用能够被正确的渲染在基座应用中,需要我们在基座应用中注册子应用:

  • 通过 pnpm install single-spa -S 安装 single-spa
  • 通过 single-spa 中提供的 registerApplication()start() 函数完成注册和启动,该逻辑可抽离到 registerApplication.ts
// registerApplication.ts
import { registerApplication, start } from 'single-spa';
// 子应用
export const applications = [{
    name: 'singleVue3',
    async activeWhen() {
        await loadScript('http://localhost:5000/js/chunk-vendors.js');
        await loadScript('http://localhost:5000/js/app.js');
        return window.singleVue3
    },
    app(location: Location) {
        return location.pathname.startsWith('/vue3-micro-app')
    },
    customProps: {
        container: '#micro-content'
    }
},
{
    name: 'singleReact',
    async activeWhen() {
        await loadScript('http://localhost:3000/static/js/main.js');
        return window.singleReact
    },
    app(location: Location) {
        return location.pathname.startsWith('/react-micro-app')
    },
    customProps: {
        container: '#micro-content'
    }
}]
// 加载子应用 script
export const loadScript = async (url: string) => {
    await new Promise((resolve, reject) => {
        const script = document.createElement('script');
        script.src = url;
        script.onload = resolve;
        script.onerror = reject;
        document.head.appendChild(script)
    });
}
// 注册子应用
export const registerApps = (apps: any[] = applications) => {
    apps.forEach(({
        name,
        activeWhen,
        app,
        customProps = {}
    }) => registerApplication(name, activeWhen, app, customProps)
    );
    start();
}
复制代码
  • main.ts 中导入并执行 registerApplication() 即可

效果预览

源码地址

其中包含了 子应用 在基座应用中 特定位置的渲染,以及 子应用 自身路由的切换时的效果,可以看出子应用路由和主应用路由互不影响。

qiankun 实践

有了前面 single-spa 的基础,通过 qiankun 来实现微前端更加简单了,因为 qiankun 本身就是基于 single-spa 实现的微前端架构系统,目的是提供更简单、简洁的方式接入。

下面我们还是使用上述的三个项目来通过 qiankun 的形式来实现微前端。

配置基座应用

vue2-main-app 的入口文件 registerApplication.ts 中使用 qiankun 进行简单配置即可,相比于上面 single-spa 的方式来说更简单:

// registerApplication.ts
import { registerMicroApps, start } from 'qiankun';
// 默认子应用
export const applications = [
    {
        name: 'singleVue3', // app name registered
        entry: 'http://localhost:5000',
        container: '#micro-content',
        activeRule: '/vue3-micro-app',
      },
      {
        name: 'singleReact', // app name registered
        entry: 'http://localhost:3000',
        container: '#micro-content',
        activeRule: '/react-micro-app',
      },
]
// 注册子应用
export const registerApps = (apps: any[] = applications) => {
    registerMicroApps(applications);
    start();
}
复制代码

配置子应用

子应用 部分该导出的生命周期还是要导出,值得注意的是生命周期中的 container 已经是对应基座应用中的 真实 DOM 节点,而不是 CSS 选择器,因此只需要进行简单的修改即可,具体如下所示:

vue3-micro-app 子应用

// src/main.ts
import { createApp } from 'vue'
import type { App as AppType } from 'vue'
import App from './App.vue'
import router from './router'
let instance: AppType
function render(container?: string) {
    instance = createApp(App)
    // 这里的 container 已经是对应基座应用中的真实 DOM 节点,而不是 CSS 选择器
    instance.use(router).mount(container || '#micro-vue-app')
}
// 当 window.singleVue3 不存在时,意味着是子应用单独运行
if (!window.singleVue3) {
    render();
}
// 子应用必须导出 以下生命周期 bootstrap、mount、unmount
export const bootstrap = () => {
    return Promise.resolve()
};
export const mount = (props: any) => {
    render(props.container);
    return Promise.resolve()
};
export const unmount = () => {
    instance.unmount();
    return Promise.resolve()
};
复制代码

react-micro-app 子应用

// src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
import './index.css'
import App from './App'
let root = null
function render(props = {}) {
  // 这里的 container 已经是对应基座应用中的真实 DOM 节点,而不是 CSS 选择器
  const container = props.container || document.getElementById('root')
  if(!container) return
  root = ReactDOM.createRoot(container)
  root.render(
    <React.StrictMode>
      <App {...props} />
    </React.StrictMode>,
  )
}
// 当 window.singleReact 不存在时,意味着是子应用单独运行
if (!window.singleReact) {
  render()
}
// 子应用必须导出 以下生命周期 bootstrap、mount、unmount
export const bootstrap = () => {
  return Promise.resolve()
}
export const mount = (props) => {
  render(props)
  return Promise.resolve()
}
export const unmount = () => {
  root.unmount()
  return Promise.resolve()
}
复制代码

子应用配置 CORS

前面说过基座应用是需要将子应用的入口文件加载到当前应用下来执行的,这个过程第一步就是请求对应的入口文件,由于浏览器 同源策略 的限制,我们必须要在子应用中配置当前子应用的资源是允许被跨域请求的。

子应用没有配置 CORS 发生跨域

image.png

vue3-micro-app 配置 CORS

vue.config.js 中配置 devServer 既可,其中的 devServer 可以配置所有符合 webpack-dev-server 的选项:

module.exports = {
  publicPath: '//localhost:5000',
  configureWebpack: {
    output: {
      library: 'singleVue3',
      libraryTarget: 'umd',
      globalObject: 'window',
    },
    devServer: {
      port: 5000,
      headers: {
        'Access-Control-Allow-Origin': '*',
      },
    },
  },
}
复制代码

react-micro-app 配置 CORS

因为之前是通过 npm run eject 的方式暴露出来和 webpack 相关的配置,在查看对应的 config\webpackDevServer.config.js 配置发现其内部已经默认做了 CORS 配置

image.png

最后

经过以上的实践,下面简单地对微前端框架核心内容进行自己的理解:

  • 技术栈无关
  • 任何一个子应用不论使用什么技术栈,最终都会被编译为 JavaScript 代码,因此真正在执行时无论基座应用还是子应用都已经是同一种语言形式
  • 独立开发、独立部署
  • 子应用本质上就是普遍使用的 spa 单页面应用,因此当然可以拥有独立代码仓库进行关联,可独立发布运行,也可作为子应用运行,只需要做好不同环境的兼容即可
  • 增量升级
  • 子应用能够独立开发部署,自然支持自身应用的功能的独立扩展,又或者是接入新的子应用
  • 独立运行时
  • 保证多个子应用在基座应用中运行时,自身的状态不受其他子应用的影响

本篇文章就这里就结束了,下一篇文章再去聊聊微前端的实现原理,以及通过自己实现一个微前端的方式加深理解。

希望本篇文章能对你有所帮助!!!


目录
相关文章
|
3天前
|
前端开发 JavaScript Java
Java语言在Web前端开发中的技术应用
Java语言在Web前端开发中的技术应用
|
10天前
|
JavaScript 前端开发 NoSQL
构建基于Node.js的全栈应用:从前端到后端的完整指南
【5月更文挑战第24天】本文是关于使用Node.js构建全栈应用的指南,涵盖前端(React或Vue)、后端(Node.js + Express)和数据库(MongoDB)的选型与实现。文章介绍了项目结构、前端组件化开发、后端API接口编写、前后端联调及部署上线的注意事项,帮助读者掌握全栈开发流程。
|
11天前
|
JavaScript 前端开发
TypeScript 学习笔记(六):TypeScript 与前端框架的结合应用
笔记,进一步提升 TypeScript 编程技能。
16 1
|
14天前
|
前端开发 Java Go
从前端到后端:构建现代化Web应用的技术演进
本文探讨了从前端到后端的技术演进,介绍了前端、后端以及多种编程语言,如Java、Python、C、PHP和Go,以及数据库在构建现代化Web应用中的应用。通过深入剖析各个技术领域的发展和应用,读者将对构建高效、可扩展、安全的Web应用有更深入的理解。
|
17天前
|
前端开发 Java Go
从前端到后端:构建现代化Web应用的技术实践
本文将介绍如何通过前端和后端技术相结合,构建现代化Web应用的技术实践。我们将探讨前端开发、后端架构以及多种编程语言(如Java、Python、C、PHP、Go)在构建高效、可扩展的Web应用中的应用。
|
18天前
|
前端开发 JavaScript 测试技术
第八章(应用场景篇) 中大型项目的解构:从单体应用到微前端
第八章(应用场景篇) 中大型项目的解构:从单体应用到微前端
|
18天前
|
Web App开发 前端开发 JavaScript
构建跨浏览器兼容的前端应用:技术实践与挑战
【5月更文挑战第16天】构建跨浏览器兼容的前端应用是应对浏览器差异和多样性的挑战。使用现代框架(如React、Vue)能自动转换代码,编写可移植的Web标准代码,结合浏览器兼容性测试工具和Polyfill解决旧浏览器支持问题。关注浏览器更新,应对性能、API差异和样式问题,采用渐进增强、条件判断和CSS Reset策略确保应用在各种浏览器上运行良好。
|
19天前
|
前端开发 JavaScript Java
浅谈企业级前端应用中的组件概念和具体的应用
浅谈企业级前端应用中的组件概念和具体的应用
20 1
|
19天前
|
JSON 前端开发 JavaScript
快照测试在前端自动化测试中的应用
在前端自动化测试中,快照测试常用于检验组件渲染与布局。
|
19天前
|
缓存 移动开发 前端开发
【专栏:HTML与CSS前端技术趋势篇】HTML与CSS在PWA(Progressive Web Apps)中的应用
【4月更文挑战第30天】PWA(Progressive Web Apps)结合现代Web技术,提供接近原生应用的体验。HTML在PWA中构建页面结构和内容,响应式设计、语义化标签、Manifest文件和离线页面的创建都离不开HTML。CSS则用于定制主题样式、实现动画效果、响应式布局和管理字体图标。两者协同工作,保证PWA在不同设备和网络环境下的快速、可靠和一致性体验。随着前端技术进步,HTML与CSS在PWA中的应用将更广泛。