前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用Single-spa集成Vue2、Vue3、React

使用Single-spa集成Vue2、Vue3、React

作者头像
前端小书童
发布2023-09-02 10:13:08
3280
发布2023-09-02 10:13:08
举报
文章被收录于专栏:前端小书童前端小书童

导言

引用Single-spa文档的描述:

Single-spa 是一个将多个单页面应用聚合为一个整体应用的 JavaScript 微前端框架。使用 single-spa 进行前端架构设计可以带来很多好处,例如:

在同一页面上使用多个前端框架 而不用刷新页面 (React, AngularJS, Angular, Ember, 你正在使用的框架) 独立部署每一个单页面应用 新功能使用新框架,旧的单页应用不用重写可以共存 改善初始加载时间,延迟加载代码

开始使用Single-spa搭建项目

  1. 基座应用(Vue)
  2. 子应用react-app(react17)
  3. 子应用vue2-app(vue2)
  4. 子应用vue3-app(vue3)

以上应该局可以通过cli工具搭建(vue-cli、create-react-app)

基座应用

1. 添加依赖
代码语言:javascript
复制
npm i single-spa

引入systemjs(用于加载依赖及子应用js)

代码语言:javascript
复制
<!-- index.html -->
      <script src="https://cdn.jsdelivr.net/npm/systemjs@6.8.3/dist/system.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/systemjs@6.8.3/dist/extras/amd.js"></script>
      <script type="systemjs-importmap">
          {
            "imports": {
                 "@single-spa/react-app": "http://localhost:8080/react-app-react-app.js",
                  "@single-spa/vue3-app": "http://localhost:8001/js/app.js",
                  "@single-spa/vue2-app": "http://localhost:8002/js/app.js",
                  "react": "https://cdn.jsdelivr.net/npm/react@17.0.2/umd/react.production.min.js",
                  "react-dom": "https://cdn.jsdelivr.net/npm/react-dom@17.0.2/umd/react-dom.production.min.js"
            }
          }
       </script>
2. 注册子应用(react)
  • 主应用配置

采用全局注册,路由匹配形式

代码语言:javascript
复制
// main.js
import {
 registerApplication,
 start
} from 'single-spa'

registerApplication(
 'react-app',
 // eslint-disable-next-line no-undef
 () => System.import("@single-spa/react-app"),
 location => location.hash.startsWith('#/react-app'),
 {
  domElementGetter: function () {
   // 此处用于异步返回挂在街节点,如果不返回默认在body下新增节点挂载
   return document.getElementById('react-app')
  }
 }
)
start({ urlRerouteOnly: true, })
代码语言:javascript
复制
<template>
<!-- 在组件内指定挂载节点 -->
	<div id="react-app"></div>
</template>
  • 子应用(microapps/react-app)配置

修改打包配置指定输出文件名

代码语言:javascript
复制
// webpack.config.js
const { merge } = require("webpack-merge");
const singleSpaDefaults = require("webpack-config-single-spa-react");

module.exports = (webpackConfigEnv, argv) => {
  const defaultConfig = singleSpaDefaults({
    orgName: "react-app",
    projectName: "react-app",
    webpackConfigEnv,
    argv,
  });

  return merge(defaultConfig, {
    // modify the webpack config however you'd like to by adding to this object
  });
};

初始化子应用

代码语言:javascript
复制
import React from "react";
import ReactDOM from "react-dom";
import singleSpaReact from "single-spa-react";
import Root from "./root.component";

const lifecycles = singleSpaReact({
  React,
  ReactDOM,
  rootComponent: Root,
  errorBoundary(err, info, props) {
    // Customize the root error boundary for your microfrontend here.
    return null;
  },
});

export const { bootstrap, mount, unmount } = lifecycles;

3. 注册子应用(vue2)

采用parcel形式接入

  • 主应用
代码语言:javascript
复制
<template>
	<Parcel @parcelMounted="parcelMounted"
		@parcelUpdated="parcelUpdated"
		@parcelUnmount="parcelUnMounted"
		:config="parcelConfig"
		:mountParcel="mountRootParcel"
		wrapWith="div"
		wrapClass="vue-child-app-load"
		:parcelProps="getParcelProps()" />
</template>

<script setup>
	import Parcel from 'single-spa-vue/parcel'
	import { mountRootParcel } from 'single-spa'
	import { computed } from 'vue'
	// eslint-disable-next-line no-undef
	const parcelConfig = computed(() => System.import("@single-spa/vue2-app"))
	const getParcelProps = () => {
		// props some context to child app
		return {
			foo: { token: 'some thing' }
		}
	}
	const parcelMounted = () => {
		console.log("parcel mounted");
	}
	const parcelUpdated = () => {
		console.log("parcel updated");
	};
	const parcelUnMounted = () => {
		console.log("parcel parcelUnMounted");
	};
</script>

因为在主应用中引入了systemjs,且使用importmap映射了依赖名称,则可以使用window下的System直接通过map名称加载文件。这也是single-spa实现依赖共享的主要形式。

  • 子应用(microapps/vue2-app),修改打包配置指定输出文件名
代码语言:javascript
复制
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  configureWebpack: {
    output: {
      libraryTarget: "system",
      filename: "js/app.js",
    },
  },
  devServer: {
    port: 8002
  }
})

初始化生命周期

代码语言:javascript
复制
const vueLifecycles = singleSpaVue({
  Vue,
  appOptions: {
    render(h) {
      return h(App, {
        props: {
          // single-spa props are available on the "this" object. Forward them to your component as needed.
          // https://single-spa.js.org/docs/building-applications#lifecycle-props
          // if you uncomment these, remember to add matching prop definitions for them in your App.vue file.
          /*
          name: this.name,
          mountParcel: this.mountParcel,
          singleSpa: this.singleSpa,
          */
        },
      });
    },
  },
});

export const bootstrap = vueLifecycles.bootstrap;
export const mount = vueLifecycles.mount;
export const unmount = vueLifecycles.unmount;


4. 注册子应用(vue3)

(microapps/vue3-app)

因为该子应用和主应用使用相同技术栈,除了上面vue2-app的引入形式,其实可以采用通过alias、或者link(npm、yarn)的形式在编译阶段就接入

代码语言:javascript
复制
// vue.config.js
module.exports = defineConfig({
configureWebpack: {
    resolve: {
      alias: {
        "@": path.resolve(__dirname, "src"),
        "microapps": path.resolve(__dirname, "microapps"),
      }
    }
  }
})

挂载时机既可以使用single-spa-vue/parcel形式挂载

代码语言:javascript
复制
<template>
	<Parcel @parcelMounted="parcelMounted"
		@parcelUpdated="parcelUpdated"
		@parcelUnmount="parcelUnMounted"
		:config="parcelConfig"
		:mountParcel="mountRootParcel"
		wrapWith="div"
		wrapClass="vue-child-app-load"
		:parcelProps="getParcelProps()" />
</template>

<script setup>
	import Parcel from 'single-spa-vue/parcel'
	import { mountRootParcel } from 'single-spa'
	import { computed } from 'vue'
	const parcelConfig = computed(() => import('microapps/vue3-app/src/singleSpaApp'))
	const getParcelProps = () => {
		// props some context to child app
		return {
			foo: { token: 'some thing' }
		}
	}
	const parcelMounted = () => {
		console.log("parcel mounted");
	}
	const parcelUpdated = () => {
		console.log("parcel updated");
	};
	const parcelUnMounted = () => {
		console.log("parcel parcelUnMounted");
	};
</script>

也可以使用import直接引入使用:

代码语言:javascript
复制
<template>
	<App />
</template>

<script setup>
	import App from "microapps/vue3-app/src/App"
</script>

详细代码见 https://github.com/wenjuGao/microapp-examples

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-02-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端小书童 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导言
  • 开始使用Single-spa搭建项目
    • 基座应用
      • 1. 添加依赖
      • 2. 注册子应用(react)
      • 3. 注册子应用(vue2)
      • 4. 注册子应用(vue3)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档