2023年6月21日发(作者:)

EMP微前端-Vue和React项⽬互相调⽤React和 Vue 相互远程调⽤ Demo什么是微前端什么是 EMP 是⼀套基于 Webpack5 和 Module Federation 的全新微前端框架(区别与以往以 dom 隔离和 iframe 为技术栈的微前端),同时更是⼀种全新的开发⽅式。 是⼀种可以跨项⽬跨框架互相调⽤项⽬⾥的任何资源(包括但不限于 第三⽅依赖、组件、Function、图⽚资源等等)的微前端框架。 是 YY(欢聚时代) 业务中台 Web 技术组最新开源的前端框架。在开源 EMP 之前,YY 业务中台 Web 技术组曾开源 等爆星项⽬。 已经在 YY 内部⼴泛使⽤,应⽤于众多中台项⽬以及 To C 、 To B 项⽬。 框架的核⼼是 ,了解更多具体实现可以看 源码。EMP 的微前端服务发现EMP 的微前端服务发现,可以让本地项⽬调⽤远端项⽬的时候知道远端项⽬含有的功能、组件、具体的函数传参、组件传参等等。类似于后端微服务的服务发现。⼤体架构如下:

了解更多具体实现可以看 Webpack Plugin 。EMP 的微前端服务发现,同时解决了 Module Federation 在 Typescript 情况下类型⽆法与远端项⽬共享的问题( ),可以说是针对该问题的业界先进解决⽅案。怎么快速上⼿ EMP 项⽬使⽤ emp-cli 的 init 命令: npx @efox/emp-cli init

启动 cli 的 init 命令,选择你所需技术栈的 emp 模板,⽬前 emp-cli ⽀持的模板有:reactvue2vue3react-basereact-projectvue3-basevue3-project(陆续会⽀持到所有主流技术栈)React 和 Vue 的远程组件互相调⽤实践实践分别新建 emp 的 React 和 Vue 项⽬React使⽤ emp-cli , npx @efox/emp-cli init,选择 React 模板写⼀个简单 React 组件 新建 /src/components/ort React from 'react'import './'import './'import './'const Hello = ({title}: {title: string}) => ( <>

{title}

)export default Hello修改项⽬⾥的 ( 是 EMP 项⽬的配置⽂件) :暴露这个 React 组件,以供远程调⽤引⼊远程的 Vue 组件(下⾯会写 Vue )const path = require('path')const packagePath = (e('./'), '')const {dependencies} = require(packagePath)(packagePath)s = ({config, env}) => { const port = 8001 const projectName = 'ReactComponents' const publicPath = `localhost:${port}/` ('mf').tap(args => { args[0] = { ...args[0], ...{ // 项⽬名称 name: projectName, // 暴露项⽬的全局变量名 library: {type: 'var', name: projectName}, // 被远程引⼊的⽂件名 filename: '', // 远程项⽬别名:远程引⼊的项⽬名 remotes: { '@emp/vueComponents': 'vueComponents', }, // 需要暴露的东西 exposes: { // 别名:组件的路径 './configs/index': 'src/configs/index', './components/Hello': 'src/components/Hello', }, // shared: ['react', 'react-dom'], shared: {...dependencies}, }, } return args }) Path(publicPath) (port) ('html').tap(args => { args[0] = { ...args[0], ...{ files: { js: ['localhost:8006/'], }, }, } return args })}在 /src/ 引⼊远程 Vue 组件,引⼊ vuera ,使⽤ VueInReact 包裹远程 Vue 组件进⾏使⽤import * as React from 'react'import * as ReactDOM from 'react-dom'import Hello from 'src/components/Hello'import Content from '@emp/vueComponents/'import {VueInReact} from 'vuera'const VueComponent = VueInReact(Content)( <>
, mentById('emp-root'),)启动项⽬ yarn dev,可以看到本项⽬的组件和远程引⽤的 Vue 组件

Vue(暂时不⽀持 Vue3)使⽤ emp-cli , npx @efox/emp-cli init,选择 Vue2 模板写⼀个简单的 Vue 组件 /src/components/修改项⽬⾥的 ( 是 EMP 项⽬的配置⽂件) :暴露这个 Vue 组件,以供远程调⽤引⼊远程的 React 组件const path = require('path')const {VueLoaderPlugin} = require('vue-loader')//const ProjectRootPath = e('./')// const packagePath = (ProjectRootPath, '')// const {dependencies} = require(packagePath)//const {getConfig} = require((ProjectRootPath, './src/config'))//s = ({config, env, empEnv}) => { const confEnv = env === 'production' ? 'prod' : 'dev' const conf = getConfig(empEnv || confEnv) ('config', conf) // const srcPath = e('./src') ('index').clear().add((srcPath, '')) // ('vue', '@vue/runtime-dom') ('vue').use(VueLoaderPlugin, []) .rule('vue') .test(/.vue$/) .use('vue-loader') .loader('vue-loader') // const host = const port = const projectName = 'vueComponents' const publicPath = Path Path(publicPath) (port) // ('mf').tap(args => { args[0] = { ...args[0], ...{ name: projectName, library: {type: 'var', name: projectName}, filename: '', remotes: { ReactComponents: 'ReactComponents', }, exposes: { './': './src/components/Content', }, /* shared: { ...dependencies, }, */ }, } return args }) .set('vue$', 'vue/dist/') .clear() // ('html').tap(args => { args[0] = { ...args[0], ...{ title: 'EMP Vue Components', files: { js: ['localhost:8001/'], }, }, } return args })}在 /src/ 引⼊远程 React 组件,引⼊ vuera ,使⽤ ReactInVue 包裹远程 React 组件进⾏使⽤启动项⽬ yarn dev,可以看到本项⽬的组件和远程引⽤的 React 组件 原理解析远程组件的编译与分发 根据 的 exposes 字段配置将组件编译成⼀个单独的闭包,然后将组件单独打包成⼀个js,最后以 的形式作为引⽤索引,按需加载。上⼀节 React 的 Hello 组件编译后的代码如下:(self["webpackChunk_empreactvue_react"] = self["webpackChunk_empreactvue_react"] || []).push([["src_components_Hello_tsx"],{/***/ "./src/components/":/*!**********************************!* !*** ./src/components/ ***! **********************************//*! namespace exports *//*! export default [provided] [maybe used in ReactComponents (runtime-defined); used in index] [usage prevents renaming] *//*! other exports [not provided] [maybe used in ReactComponents (runtime-defined)] *//*! runtime requirements: __webpack_require__, __webpack_require__.n, __webpack_exports__, __webpack_require__.r, __webpack_require__.* *//***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {"use strict";__webpack_require__.r(__webpack_exports__);/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "webpack/sharing/consume/default/react/react");/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODU/* harmony import */ var _common_scss__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ */ "./src/components/"/* harmony import */ var _common_scss__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_common_scss__WEBPACK/* harmony import */ var _common_less__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./ */ "./src/components/");/* harmony import */ var _common_css__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./ */ "./src/components/");var Hello = function Hello(_ref) { var title = _;};/* harmony default export */ __webpack_exports__["default"] = (Hello);/***/ })}]);/* harmony import */ var _common_less__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_common_less__WEBPACK/* harmony import */ var _common_css__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_common_css__WEBPACK_ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragme//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9AZW1wcmVhY3R2dWUvcmVhY3QvL远程调⽤时将其他框架的组件编译成当前框架在调⽤时编译其他框架的组件需要⽤到 vuera 这个库,帮助我们把其他框架的组件编译成当前所⽤的框架。与其他微前端技术⽐较与基于 dom 隔离的微前端框架所⽐较,以 qiankun 为例状态⽅⾯。qiankun 所做的微前端不能把基站项⽬和⼦项⽬过度隔离导致上下⽂不⼀致,共享状态等等需要通过总线⽅式传递,⼗分⿇烦。⽽ EMP 通过把调⽤远程的状态管理使得状态共享⼗分⽅便。跨框架调⽤实现。qiankun 通过 dom 隔离的⽅式,使得跨框架实现⼗分容易,但是不能互相调⽤,粒度只能渲染在规定的 dom 区域。EMP 实现的跨框架调⽤粒度到了 function ,⽽且使⽤⼗分⽅便。体积⽅⾯。qiankun 因为是通过 dom 隔离⽅式实现,所以依赖共享并不完善,需要依赖于 systemjs,⽽且共享不⽅便,导致依赖可能会出现重复,使得出现体积变⼤。EMP 通过 module federation 实现依赖共享,使得依赖不会重新重复(依赖变成全局变量,相同依赖只会留下⼀个),所以体积会相对 qiankun 更⼩。与基于 iframe 的微前端所⽐较状态⽅⾯。iframe 的微前端,⽆真正意义上的状态管理,通过 postMessage 进⾏通信。跨框架调⽤⽅⾯。iframe 的微前端不能跨框架调⽤。体积⽅⾯。 iframe 的微前端并不能共享依赖。总结 是 YY 业务中台 Web 技术组最新开源的微前端框架。⽬前已在公司内⼴泛使⽤,对多项⽬的状态管理、互相调⽤、体积优化都有很⼤的提升。跨框架远程调⽤⽅便。跨框架互相调⽤如此⽅便,同技术栈互相调⽤更是不在话下。致⼒于提⾼多项⽬协作,是⼀种全新的开发⽅式。----------------------------------------------------------------------具体的教程⽬录如下:基础知识解析快速⼊门进阶教程

2023年6月21日发(作者:)

EMP微前端-Vue和React项⽬互相调⽤React和 Vue 相互远程调⽤ Demo什么是微前端什么是 EMP 是⼀套基于 Webpack5 和 Module Federation 的全新微前端框架(区别与以往以 dom 隔离和 iframe 为技术栈的微前端),同时更是⼀种全新的开发⽅式。 是⼀种可以跨项⽬跨框架互相调⽤项⽬⾥的任何资源(包括但不限于 第三⽅依赖、组件、Function、图⽚资源等等)的微前端框架。 是 YY(欢聚时代) 业务中台 Web 技术组最新开源的前端框架。在开源 EMP 之前,YY 业务中台 Web 技术组曾开源 等爆星项⽬。 已经在 YY 内部⼴泛使⽤,应⽤于众多中台项⽬以及 To C 、 To B 项⽬。 框架的核⼼是 ,了解更多具体实现可以看 源码。EMP 的微前端服务发现EMP 的微前端服务发现,可以让本地项⽬调⽤远端项⽬的时候知道远端项⽬含有的功能、组件、具体的函数传参、组件传参等等。类似于后端微服务的服务发现。⼤体架构如下:

了解更多具体实现可以看 Webpack Plugin 。EMP 的微前端服务发现,同时解决了 Module Federation 在 Typescript 情况下类型⽆法与远端项⽬共享的问题( ),可以说是针对该问题的业界先进解决⽅案。怎么快速上⼿ EMP 项⽬使⽤ emp-cli 的 init 命令: npx @efox/emp-cli init

启动 cli 的 init 命令,选择你所需技术栈的 emp 模板,⽬前 emp-cli ⽀持的模板有:reactvue2vue3react-basereact-projectvue3-basevue3-project(陆续会⽀持到所有主流技术栈)React 和 Vue 的远程组件互相调⽤实践实践分别新建 emp 的 React 和 Vue 项⽬React使⽤ emp-cli , npx @efox/emp-cli init,选择 React 模板写⼀个简单 React 组件 新建 /src/components/ort React from 'react'import './'import './'import './'const Hello = ({title}: {title: string}) => ( <>

{title}

)export default Hello修改项⽬⾥的 ( 是 EMP 项⽬的配置⽂件) :暴露这个 React 组件,以供远程调⽤引⼊远程的 Vue 组件(下⾯会写 Vue )const path = require('path')const packagePath = (e('./'), '')const {dependencies} = require(packagePath)(packagePath)s = ({config, env}) => { const port = 8001 const projectName = 'ReactComponents' const publicPath = `localhost:${port}/` ('mf').tap(args => { args[0] = { ...args[0], ...{ // 项⽬名称 name: projectName, // 暴露项⽬的全局变量名 library: {type: 'var', name: projectName}, // 被远程引⼊的⽂件名 filename: '', // 远程项⽬别名:远程引⼊的项⽬名 remotes: { '@emp/vueComponents': 'vueComponents', }, // 需要暴露的东西 exposes: { // 别名:组件的路径 './configs/index': 'src/configs/index', './components/Hello': 'src/components/Hello', }, // shared: ['react', 'react-dom'], shared: {...dependencies}, }, } return args }) Path(publicPath) (port) ('html').tap(args => { args[0] = { ...args[0], ...{ files: { js: ['localhost:8006/'], }, }, } return args })}在 /src/ 引⼊远程 Vue 组件,引⼊ vuera ,使⽤ VueInReact 包裹远程 Vue 组件进⾏使⽤import * as React from 'react'import * as ReactDOM from 'react-dom'import Hello from 'src/components/Hello'import Content from '@emp/vueComponents/'import {VueInReact} from 'vuera'const VueComponent = VueInReact(Content)( <>
, mentById('emp-root'),)启动项⽬ yarn dev,可以看到本项⽬的组件和远程引⽤的 Vue 组件

Vue(暂时不⽀持 Vue3)使⽤ emp-cli , npx @efox/emp-cli init,选择 Vue2 模板写⼀个简单的 Vue 组件 /src/components/修改项⽬⾥的 ( 是 EMP 项⽬的配置⽂件) :暴露这个 Vue 组件,以供远程调⽤引⼊远程的 React 组件const path = require('path')const {VueLoaderPlugin} = require('vue-loader')//const ProjectRootPath = e('./')// const packagePath = (ProjectRootPath, '')// const {dependencies} = require(packagePath)//const {getConfig} = require((ProjectRootPath, './src/config'))//s = ({config, env, empEnv}) => { const confEnv = env === 'production' ? 'prod' : 'dev' const conf = getConfig(empEnv || confEnv) ('config', conf) // const srcPath = e('./src') ('index').clear().add((srcPath, '')) // ('vue', '@vue/runtime-dom') ('vue').use(VueLoaderPlugin, []) .rule('vue') .test(/.vue$/) .use('vue-loader') .loader('vue-loader') // const host = const port = const projectName = 'vueComponents' const publicPath = Path Path(publicPath) (port) // ('mf').tap(args => { args[0] = { ...args[0], ...{ name: projectName, library: {type: 'var', name: projectName}, filename: '', remotes: { ReactComponents: 'ReactComponents', }, exposes: { './': './src/components/Content', }, /* shared: { ...dependencies, }, */ }, } return args }) .set('vue$', 'vue/dist/') .clear() // ('html').tap(args => { args[0] = { ...args[0], ...{ title: 'EMP Vue Components', files: { js: ['localhost:8001/'], }, }, } return args })}在 /src/ 引⼊远程 React 组件,引⼊ vuera ,使⽤ ReactInVue 包裹远程 React 组件进⾏使⽤启动项⽬ yarn dev,可以看到本项⽬的组件和远程引⽤的 React 组件 原理解析远程组件的编译与分发 根据 的 exposes 字段配置将组件编译成⼀个单独的闭包,然后将组件单独打包成⼀个js,最后以 的形式作为引⽤索引,按需加载。上⼀节 React 的 Hello 组件编译后的代码如下:(self["webpackChunk_empreactvue_react"] = self["webpackChunk_empreactvue_react"] || []).push([["src_components_Hello_tsx"],{/***/ "./src/components/":/*!**********************************!* !*** ./src/components/ ***! **********************************//*! namespace exports *//*! export default [provided] [maybe used in ReactComponents (runtime-defined); used in index] [usage prevents renaming] *//*! other exports [not provided] [maybe used in ReactComponents (runtime-defined)] *//*! runtime requirements: __webpack_require__, __webpack_require__.n, __webpack_exports__, __webpack_require__.r, __webpack_require__.* *//***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {"use strict";__webpack_require__.r(__webpack_exports__);/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "webpack/sharing/consume/default/react/react");/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODU/* harmony import */ var _common_scss__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ */ "./src/components/"/* harmony import */ var _common_scss__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_common_scss__WEBPACK/* harmony import */ var _common_less__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./ */ "./src/components/");/* harmony import */ var _common_css__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./ */ "./src/components/");var Hello = function Hello(_ref) { var title = _;};/* harmony default export */ __webpack_exports__["default"] = (Hello);/***/ })}]);/* harmony import */ var _common_less__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_common_less__WEBPACK/* harmony import */ var _common_css__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_common_css__WEBPACK_ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragme//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9AZW1wcmVhY3R2dWUvcmVhY3QvL远程调⽤时将其他框架的组件编译成当前框架在调⽤时编译其他框架的组件需要⽤到 vuera 这个库,帮助我们把其他框架的组件编译成当前所⽤的框架。与其他微前端技术⽐较与基于 dom 隔离的微前端框架所⽐较,以 qiankun 为例状态⽅⾯。qiankun 所做的微前端不能把基站项⽬和⼦项⽬过度隔离导致上下⽂不⼀致,共享状态等等需要通过总线⽅式传递,⼗分⿇烦。⽽ EMP 通过把调⽤远程的状态管理使得状态共享⼗分⽅便。跨框架调⽤实现。qiankun 通过 dom 隔离的⽅式,使得跨框架实现⼗分容易,但是不能互相调⽤,粒度只能渲染在规定的 dom 区域。EMP 实现的跨框架调⽤粒度到了 function ,⽽且使⽤⼗分⽅便。体积⽅⾯。qiankun 因为是通过 dom 隔离⽅式实现,所以依赖共享并不完善,需要依赖于 systemjs,⽽且共享不⽅便,导致依赖可能会出现重复,使得出现体积变⼤。EMP 通过 module federation 实现依赖共享,使得依赖不会重新重复(依赖变成全局变量,相同依赖只会留下⼀个),所以体积会相对 qiankun 更⼩。与基于 iframe 的微前端所⽐较状态⽅⾯。iframe 的微前端,⽆真正意义上的状态管理,通过 postMessage 进⾏通信。跨框架调⽤⽅⾯。iframe 的微前端不能跨框架调⽤。体积⽅⾯。 iframe 的微前端并不能共享依赖。总结 是 YY 业务中台 Web 技术组最新开源的微前端框架。⽬前已在公司内⼴泛使⽤,对多项⽬的状态管理、互相调⽤、体积优化都有很⼤的提升。跨框架远程调⽤⽅便。跨框架互相调⽤如此⽅便,同技术栈互相调⽤更是不在话下。致⼒于提⾼多项⽬协作,是⼀种全新的开发⽅式。----------------------------------------------------------------------具体的教程⽬录如下:基础知识解析快速⼊门进阶教程