微型前端,Web组件和共享库

时间:2019-06-12 12:03:39

标签: reactjs web-component micro-frontend

所以我正在努力将公司的应用程序迁移到微前端方法。我们遵循https://micro-frontends.org/中描述的标准。虽然目前所有东西都在使用React,但我们仍在使用Web Components进行包装,以便将来拥有与框架无关的自由和灵活性。我们已经建立并运行了一个可运行的架构,到目前为止,它运行得很漂亮。我们甚至在Web组件规范的基础上创建了一个精美的兼容性层,该层允许我们将类似React的props传递给Web组件,包括对象,数组,甚至函数。这样可以使它们之间的交互更好。

我们现在主要关心的是库的重复。我们是一个React商店,因此,即使我们有这种与框架无关的方法,所有内容都在使用React。尽管这种新方法使我们能够将应用程序的各个部分最终升级到较新的React版本,但我们仍然不喜欢React库如此重复的想法。

从角度看,甚至Gzip,React / ReactDOM也超过40kb。单独来看,这是非常微小的,但是按比例放大,则开始占用越来越多的带宽。 RAM方面的问题不大,这些库大约130kb,考虑到大多数设备的RAM容量,现在已经不算什么了。

但是,当然,我们希望事情尽可能优化和简化。因此,我希望有人可以为微前端应用程序(包装在Web组件中的微前端应用程序)提供一种方法,使其可以从父应用程序中获取React和其他库。

您应该知道,父应用程序JavaScript是在微前端之前加载的。每个微前端都通过<script>标签加载。最后,我们目前暂不使用Shadow DOM,这是我们为了将现有代码迁移到新的微前端架构中而受益的权衡。

2 个答案:

答案 0 :(得分:1)

可能的解决方案是使用“导入地图”准备库,但由于它不支持IE11 +,因此我建议您使用SystemJS?

https://github.com/systemjs/systemjs

尤其是这似乎与您的情况很接近:

https://github.com/systemjs/systemjs-examples/tree/master/loading-code/react-hello-world

在html上,您可以这样做:

func addWishComplete(wishName: String, selectedWishlistIDX: Int, wishImage: UIImage?, wishLink: String?, wishPrice: String?, wishNote: String?, wishCounter: Int?) {
    
    let wishToAdd = Wish(name: wishName, link: wishLink!, price: wishPrice!, note: wishNote!, image: wishImage!, checkedStatus: false, wishCounter: wishCounter!)
    
    self.dataSourceArray[selectedWishlistIDX].wishes.append(wishToAdd)
    DataHandler.saveWish(dataSourceArray: self.dataSourceArray, selectedWishlistIdx: selectedWishlistIDX, wish: wishToAdd)
    // save dataSourceArray with new wish in UserDefaults
    if let defaults = UserDefaults(suiteName: UserDefaults.Keys.groupKey) {
        defaults.setDataSourceArray(data: self.dataSourceArray)
        defaults.synchronize()
    } else {
        print("error wish to datasource")
    }

    // only update current list if selectedWishlist is currentWishlist
    if selectedWishlistIDX == currentWishListIDX {
        wishList.wishes.append(Wish(name: wishName, link: wishLink!, price: wishPrice!, note: wishNote!, image: wishImage!, checkedStatus: false, wishCounter: wishCounter!))
        
        theTableView.wishData = wishList.wishes
        theTableView.tableView.beginUpdates()
        theTableView.tableView.insertRows(at: [
            (NSIndexPath(row: theTableView.wishData.count-1, section: 0) as IndexPath)], with: .left)
        theTableView.tableView.endUpdates()
    }
    dismissWishView()
}

然后,您可以导入ReactJS,因为浏览器知道从何处获取它。

可能可以构建某种类型的库,以查看您的微型前端(MFE)' path to public folder; should be similar to ' "Public Folders\All Public Folders\Company\Sales" strFolder = "\\Public Folders - gabriel.buehler@wingd.com\All Public Folders\Local Winterthur Holidays" Call AddFolderToFavorites(strFolder, True) Sub AddFolderToFavorites(strPath, AddToAddressBook) Const olContactItem = 2 Set myFolder = GetFolder(strPath) If Not myFolder Is Nothing Then myFolder.AddToPFFavorites ' if contacts folder, ' optionally add new Favorite to OAB If myFolder.DefaultItemType = olContactItem Then If AddToAddressBook = True Then strFavFolder = _ "Public Folders\Favorites\" & _ myFolder.Name Set myFavFolder = GetFolder(strFavFolder) If Not myFavFolder Is Nothing Then myFavFolder.ShowAsOutlookAB = True End If End If End If End If Set myFolder = Nothing End Sub Public Function GetFolder(strFolderPath) On Error Resume Next strFolderPath = Replace(strFolderPath, "/", "\") arrFolders = Split(strFolderPath, "\") Set objApp = CreateObject("Outlook.Application") Set objNS = objApp.GetNamespace("MAPI") Set objFolder = objNS.Folders.Item(arrFolders(0)) If Not objFolder Is Nothing Then For I = 1 To UBound(arrFolders) Set colFolders = objFolder.Folders Set objFolder = Nothing Set objFolder = colFolders.Item(arrFolders(I)) If objFolder Is Nothing Then Exit For End If Next End If Set GetFolder = objFolder Set colFolders = Nothing Set objNS = Nothing Set objApp = Nothing End Function ,以了解需要使用哪个库并动态创建与上面的示例类似的导入对象。

我们要记住,有必要涵盖版本检查。提及的库可能会存储某种地图,该地图将依赖项与版本以及可访问的位置联系起来。想象一下,万一提到我们需要在每个MFE上处理不同的反应版本:)。

然后,在加载另一个MFE库时,可以检查是否已经包含所需的依赖项,如果缺少,请下载它,否则使用已经获取的内容。

另一件事是将Webpack 5与模块联合一起使用,我不建议这样做,因为它对于生产来说不够稳定,但是有可能开始使用它。困难的部分将涉及版本检查,因此很可能需要另一个抽象层来处理它。

https://indepth.dev/webpack-5-module-federation-a-game-changer-in-javascript-architecture/

答案 1 :(得分:0)

  

核心思想是告诉模块捆绑器如何打包您的微前端。

假设您正在使用Webpack捆绑应用程序,这是您需要做的两件事。

步骤1:

将React声明为外部依赖项,例如在您的Webpack config中:

externals: {
  'react': 'React',
  'react-dom': 'ReactDOM'
},

步骤2:

在加载父应用程序的JS之前,请确保从CDN或其他等效位置加载ReactReactDOM

<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

将这些脚本放入主index.html中,该脚本负责引导整个SPA。

说明

当您将某些软件包/库声明为外部软件包时,Webpack不会将其包含在捆绑软件中。它假定外部环境将使该特定版本作为全局变量可用。对于React,它使用ReactReactDOM作为全局变量。

这样做并通过CDN包括在内,您将只剩下一份 React ReactDOM 。用户首次访问该应用程序时,速度会变慢,但是一旦被缓存,就没有问题了

此外,您可以扩展这个想法,也可以将它们声明为父应用父外壳容器外部