当前位置: 首页 > news >正文

泗水县城乡建设局网站做网站公司在丹麦

泗水县城乡建设局网站,做网站公司在丹麦,产品网络营销,公司建站前言 说起微前端框架#xff0c;很多人第一反应就是 single-spa。但是再问深入一点#xff1a;它是干嘛的#xff0c;它有什么用#xff0c;可能就回答不出来了。 一方面没多少人研究和使用微前端。可能还没来得及用微前端扩展项目#xff0c;公司就已经倒闭了。 另一方…前言 说起微前端框架很多人第一反应就是 single-spa。但是再问深入一点它是干嘛的它有什么用可能就回答不出来了。 一方面没多少人研究和使用微前端。可能还没来得及用微前端扩展项目公司就已经倒闭了。 另一方面是中文博客对微前端的研究少之又少很多文章只是简单翻译一下官方文档读几个API放个官方的 Demo 就完事了。很少有深入研究到底 single-spa 是怎么一回事的。 还有一方面是 single-spa 的文档非常难看懂和 Redux 文档一样喜欢造概念。讲一个东西的时候总是把别的库拉进来一起讲把一个简单的东西变得非常复杂。最令人吐槽的一点就是官方的 sample code 都是只言片语完全拼凑不出来一个 Demo而 Github 的 Demo 还贼复杂没解释光看完都要 clone 好几个 repo。 最后求人不如求己刚完源码再刚一下文档。 这篇文章将不会会聊怎么搭建一个 Demo而是会从 “Why” 和 “How” 的角度来聊一下官方文档的都讲了哪些内容相信看完这篇文章就能看懂 官方的 Demo 了。 一个需求 让我们从一个最小的需求开始说起。有一天产品经理突然说我们要做一个 A 页面我看到隔壁组已经做过这个 A 页面了你把它放到我们项目里吧应该不是很难吧明天上线吧。 此时产品经理想的是应该就填一个 URL 就好吧再不行复制粘贴也很快吧。而程序员想的却是又要看屎山了。又要重构了。又要联调了。测试数据有没有啊等一下联调的后端是谁啊 估计这是做大项目时经常遇到的需求了搬运一个现有的页面。我想大多数人都会选择在自己项目里复制粘贴别人的代码然后稍微重构一下再测试环境联调最后上线。 但是这样就又多了一份代码了如果别人的页面改了那么自己项目又要跟着同步修改再联调再上线非常麻烦。 所以程序员就想能不能我填一个 url然后这个页面就到项目里来了呢所以iframe/ 就出场了。 iframe 的弊端 iframe 就相当于页面里再开个窗口加载别的页面但是它有很多弊端 每次进来都要加载状态不能保留DOM 结构不共享。比如子应用里有一个 Modal显示的时候只能在那一小块地方展示不能全屏展示无法跟随浏览器前进后退天生的硬隔离无法与主应用进行资源共享交流也很困难 而 SPA 正好可以解决上面的问题 切换路由就是切换页面组件组件的挂载和卸载非常快单页应用肯定共享 DOM前端控制路由想前就前想后就后React 通信有 ReduxVue 通信有 Vuex可与 App 组件进行资源共享交流很爽 这就给我们一个启发能不能有这么一个巨型 SPA 框架把现有的 SPA 当成 Page Component 来组装成一个新的 SPA 呢这就是微前端的由来。 微前端是什么 微前端应该有如下特点 技术栈无关主框架不限制接入应用的技术栈微应用具备完全自主权独立开发、独立部署微应用仓库独立前后端可独立开发部署完成后主框架自动完成同步更新增量升级在面对各种复杂场景时我们通常很难对一个已经存在的系统做全量的技术栈升级或重构而微前端是一种非常好的实施渐进式重构的手段和策略独立运行时每个微应用之间状态隔离运行时状态不共享 等一下等一下说了一堆到底啥是 single-spa 啊。 嘿嘿single-spa 框架并没有实现上面任何特点对的一个都没有Just Zero。 single-spa 到底是干嘛的 single-spa 仅仅是一个子应用生命周期的调度者。single-spa 为应用定义了 boostrap, load, mount, unmount 四个生命周期回调 只要写过 SPA 的人都能理解无非就是生、老、病、死。不过有几个点需要注意一下 Register 不是生命周期指的是调用 registerApplication 函数这一步Load 是开始加载子应用怎么加载由开发者自己实现等会会说到Unload 钩子只能通过调用 unloadApplication 函数才会被调用 OK上面 4 个生命周期的回调顺序是 single-spa 可以控制的我能理解那什么时候应该开始这一套生命周期呢应该是有一个契机来开始整套流程的或者某几个流程的。 契机就是当 window.location.href 匹配到 url 时开始走对应子 App 的这一套生命周期嘛。所以single-spa 还要监听 url 的变化然后执行子 app 的生命周期流程。 到此我们就有了 single-spa 的大致框架了无非就两件事 实现一套生命周期在 load 时加载子 app由开发者自己玩别的生命周期里要干嘛的还是由开发者造的子应用自己玩监听 url 的变化url 变化时会使得某个子 app 变成 active 状态然后走整套生命周期 画个草图如下 是不是感觉 single-spa 很鸡贼虽然 single-spa 说自己是微前端框架但是一个微前端的特性都没有实现都是需要开发者在加载自己子 App 的时候实现的要不就是通过一些第三方工具实现。 注册子应用 有了上面的了解之后我们再来看 single-spa 里最重要的 APIregisterApplication表示注册一个子应用。使用如下 singleSpa.registerApplication({name: taobao, // 子应用名app: () System.import(taobao), // 如何加载你的子应用activeWhen: /appName, // url 匹配规则表示啥时候开始走这个子应用的生命周期customProps: { // 自定义 props从子应用的 bootstrap, mount, unmount 回调可以拿到authToken: xc67f6as87f7s9d} })singleSpa.start() // 启动主应用上面注册了一个子应用 taobao。我们自己实现了加载子应用的方法通过 activeWhen 告诉 single-spa 什么时候要挂载子应用好像就可以上手开撸代码喽。 可以个鬼请告诉我 System.import 是个什么鬼。哦是 SystemJS诶SystemJS 听说过它是个啥为啥要用 SystemJS凭啥要用 SystemJS SystemJS 相信很多人看过一些微前端的博客它们都会说 single-spa 是基于 SystemJS 的。错single-spa 和 SystemJS 一点关系都没有这里先放个主应用和子应用的关系图 single-spa 的理念是希望主应用可以做到非常非常简单的和轻量简单到只要一个 index.html 一个 main.js 就可以完成微前端工程连 Webpack 都不需要直接在浏览器里执行 singleSpa.registerApplication 就收工了这种执行方式也就是 in-browser 执行。 但是浏览器里执行 JS别说实现 import xxx from https://taobao.com 了我要是在浏览器里实现 ES6 的 import/export 都不行啊 import axios from axios。 其实也不是不行只需要在 script 标签加上 typemodule也是可以实现的例如 script typemodule srcmodule.js/script script typemodule// or an inline scriptimport {helperMethod} from ./providesHelperMethod.js;helperMethod(); /script // providesHelperMethod.js export function helperMethod() {console.info(Im helping!); }但是遇到导入模块依赖的像 import axios from axios 这样的就需要 importmap 了 script typeimportmap{imports: {vue: https://cdn.jsdelivr.net/npm/vue2.6.12/dist/vue.esm.browser.js}} /scriptdiv idcontainer我是{{name}}/divscript typemoduleimport Vue from vuenew Vue({el: #container,data: {name: Jack}}) /script importmap 的功能就是告诉 vue 这个玩意要从 https://cdn.jsdelivr.net/npm/vue2.6.12/dist/vue.esm.browser.js 这里来的。不过importmap 现在只有 Chrome 是支持的。 所以SystemJS 就将这一块补齐了。当然除了 importmap它还有很多的功能比如获取当前加载的所有模块、当前模块的 URL、可以 import html, import cssimport wasm。 等等这在 Webpack 不也可以做到么Webpack 还能 import less, import scss 呢这不比 SystemJS 牛逼对的如果不是因为要在浏览器使用 import/export没人会用 SystemJS。SystemJS 的好处和优势有且仅有一点那就是在浏览器里使用 ES6 的 import/export。 而正因为 SystemJS 可以在浏览器里可以使用 ES6 的 import/export 并支持动态引入正好符合 single-spa 所提倡的 in-browser 执行思路所以 single-spa 文档里才反复出现 SystemJS 的身影而且 Github Demo 里依然是使用 SystemJS 的 importmap 机制来引入不同模块 script typesystemjs-importmap{imports: {react-mf/root-config: //localhost:9000/react-mf-root-config.js}} /scriptscriptsingleSpa.registerApplication({name: taobao, // 子应用名app: () System.import(react-mf/root-config), // 如何加载你的子应用activeWhen: /appName, // url 匹配规则表示啥时候开始走这个子应用的生命周期customProps: { // 自定义 props从子应用的 bootstrap, mount, unmount 回调可以拿到authToken: xc67f6as87f7s9d}}) /script 公共依赖 SystemJS 另一个好处就是可以通过 importmap 引入公共依赖。 假如我们有三个子应用它们都有公共依赖项 antd那每个子应用打包出来都会有一份 antd 的代码就显示很冗余。 一个解决方法就是在主应用里通过 importmap 直接把 antd 代码引入进来子应用在 Webpack 设置 external 把 antd 打包时排除掉。子应用打包就不会把 antd 打包进去了体积也变小了。 有人会说了我用 CDN 引入不行嘛不行啊因为子应用的代码都是 import {Button} from antd 的浏览器要怎么直接识别 ES6 的 import/export 呢那还不得 SystemJS 嘛。 难道 Webpack 就没有办法可以实现 importmap 的效果了么Webpack 5 提出的 Module Federation 模块联邦就可以很好地做的 importmap 的效果。这是 Webpack 5 的新特性使用的效果和 importmap 差不多。关于模块联邦是个啥可以参考 这篇文章。 至于用 importmap 还是 Webpack 的 Module Federationsingles-spa 是推荐使用 importmap 的但是文档也没有反对使用 Webpack 的 Module Federation 的理由。能用就OK。 SystemJS vs Webpack ES 有人可能会想都 1202 年了怎么还要在浏览器环境写 JS 呢不上个 Webpack 都不好意思说自己是前端开发了。 没错Webpack 是非常强大的而且可以利用 Webpack 很多能力让主应用变得更加灵活。比如写 lessscssWebpack 的 prefetch 等等等等。然后在注册子应用时完全可以利用 Webpack 的动态引入 singleSpa.registerApplication({name: taobao, // 子应用名app: () import(taobao), // 如何加载你的子应用activeWhen: /appName, // url 匹配规则表示啥时候开始走这个子应用的生命周期customProps: { // 自定义 props从子应用的 bootstrap, mount, unmount 回调可以拿到authToken: xc67f6as87f7s9d} })那为什么 single-spa 还要推荐 SystemJS 呢个人猜测是因为 single-spa 希望主应用应该就一个空壳子只需要管内容要放在哪个地方所有的功能、交互都应该交由 index.html 来统一管理。 当然这仅仅是一种理念可以完全不遵循它。像我个人还是喜欢用 Webpack 多一点SystemJS 还是有点多余而且觉得有点奥特曼了。不过为了跟着文档的节奏来这里假设就用 SystemJS 来实现主应用。 Root Config 由于 single-spa 非常强调 in-browser 的方式来实现主应用所以 index.html 就充当了静态资源、子应用的路径声明的角色。 !DOCTYPE html html langen headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0meta http-equivX-UA-Compatible contentieedgetitlePolyglot Microfrontends/titlemeta nameimportmap-type contentsystemjs-importmap /script typesystemjs-importmap srchttps://storage.googleapis.com/polyglot.microfrontends.app/importmap.json/script% if (isLocal) { %script typesystemjs-importmap{imports: {polyglot-mf/root-config: //localhost:9000/polyglot-mf-root-config.js}}/script% } %script srchttps://cdn.jsdelivr.net/npm/import-map-overrides2.2.0/dist/import-map-overrides.js/scriptscript srchttps://cdn.jsdelivr.net/npm/systemjs6.8.3/dist/system.min.js/scriptscript srchttps://cdn.jsdelivr.net/npm/systemjs6.8.3/dist/extras/amd.min.js/script /head bodyscriptSystem.import(polyglot-mf/root-config);System.import(polyglot-mf/styleguide);/scriptimport-map-overrides-full show-when-local-storagedevtools dev-libs/import-map-overrides-full /body /html 而 main.js 则实现子应用注册、主应用启动。 import { registerApplication, start } from single-spa;registerApplication({name: polyglot-mf/navbar,app: () System.import(polyglot-mf/navbar),activeWhen: /, });registerApplication({name: polyglot-mf/clients,app: () System.import(polyglot-mf/clients),activeWhen: /clients, });registerApplication({name: polyglot-mf/account-settings,app: () loadWithoutAmd(polyglot-mf/account-settings),activeWhen: /settings, });start();// A lot of angularjs libs are compiled to UMD, and if you dont process them with webpack // the UMD calls to window.define() can be problematic. function loadWithoutAmd(name) {return Promise.resolve().then(() {let globalDefine window.define;delete window.define;return System.import(name).then((module) {window.define globalDefine;return module;});}); }像这样的资源声明 主子应用加载的组件single-spa 称之为 Root Config。 它不是什么新概念就只有两个东西 一个主应用的 index.html 一个执行 registerApplication 函数的 JS 文件 single-spa-layout 虽然一个 index.html 是完美的轻量微前端主应用但是就算再压缩主应用的交互那总得告诉子应用放置的位置吧那不还得 DOM API 一把梭一样麻烦 为了解决这个问题single-spa 说没事我帮你搞然后造了 single-spa-layout。具体使用请看代码 htmlheadtemplate idsingle-spa-layoutsingle-spa-routernav classtopnavapplication nameorganization/nav/application/navdiv classmain-contentroute pathsettingsapplication nameorganization/settings/application/routeroute pathclientsapplication nameorganization/clients/application/route/divfooterapplication nameorganization/footer/application/footer/single-spa-router/template/head /html 不能说和 Vue Router 很像只能说一模一样吧。当然上面这么写很直观但是浏览器并不认识这些元素所以 single-spa-layout 把识别这些元素的逻辑都封装成了函数并暴露给开发者开发者只要调用一下就能识别出 appName 等信息了 import { registerApplication, start } from single-spa; import {constructApplications,constructRoutes,constructLayoutEngine, } from single-spa-layout;// 获取 routes const routes constructRoutes(document.querySelector(#single-spa-layout));// 获取所有的子应用 const applications constructApplications({routes,loadApp({ name }) {return System.import(name); // SystemJS 引入入口 JS}, });// 生成 layoutEngine const layoutEngine constructLayoutEngine({ routes, applications });// 批量注册子应用 applications.forEach(registerApplication);// 启动主应用 start();没什么好说的constrcutRoutes, constructApplication 和 constructLayoutEngine 本质上就是识别 single-spa-layout 定义的元素标签然后获取里面的属性再通过 registerApplication 函数一个个注册就完事了。 改造子应用 上面说的都是主应用的事情现在我们来关心一下子应用。 子应用最关键的一步就是导出 bootstrap, mount, unmount 三个生命周期钩子。 import SubApp from ./index.tsxexport const bootstrap () {} export const mount () {// 使用 React 来渲染子应用的根组件ReactDOM.render(SubApp/, document.getElementById(root)); } export const unmount () {}single-spa-react, single-spa-vue, single-spa-angular, single-spa-xxx, ... emmmm怎么说的呢上面三个 export 不太好看能不能有一种更直接的方法就实现 3 个生命周期的导出呢 single-spa 说可以啊搞所以有了 single-spa-react import React from react; import ReactDOM from react-dom; import SubApp from ./index.tsx; import singleSpaReact, {SingleSpaContext} from single-spa-react;const reactLifecycles singleSpaReact({React,ReactDOM,rootComponent: SubApp,errorBoundary(err, info, props) {return (div出错啦/div);}, });export const bootstrap reactLifecycles.bootstrap; export const mount reactLifecycles.mount; export const unmount reactLifecycles.unmount;single-spa 说我不能单给 react 搞啊别的框架也要给它们整上一个一碗水端平所以有这了这些牛鬼蛇神 不禁感慨这些小轮子是真能造啊。 导入子应用的 CSS 不知道你有没有注意到在刚刚的子应用注册里我们仅仅用 System.import 导入了一个 JS 文件那 CSS 样式文件怎么搞呢可能可以 System.import(xxx.css) 来导入。 但是这又有问题了在切换了应用时unmount 的时候要怎么把已有的 CSS 给删掉呢官方说可以这样 const style document.createElement(style); style.textContent .settings {color: blue;};export const mount [async () {document.head.appendChild(styleElement);},reactLifecycles.mount, ]export const unmount [reactLifecycles.unmount,async () {styleElement.remove();} ]我single-spa求求你做个人吧搭个 Demo还要我来处理 CSSsingle-spa 说好等我再去造一个轮子。于是就有了 single-spa-css。用法如下 import singleSpaCss from single-spa-css;const cssLifecycles singleSpaCss({// 这里放你导出的 CSS如果 webpackExtractedCss 为 true可以不指定cssUrls: [https://example.com/main.css],// 是否要使用从 Webpack 导出的 CSS默认为 falsewebpackExtractedCss: false,// 是否 unmount 后被移除默认为 trueshouldUnmount: true,// 超时不废话了都懂的timeout: 5000 })const reactLifecycles singleSpaReact({...})// 加入到子应用的 bootstrap 里 export const bootstrap [cssLifecycles.bootstrap,reactLifecycles.bootstrap ]export const mount [// 加入到子应用的 mount 里一定要在前面不然 mount 后会有样式闪一下的问题cssLifecycles.mount,reactLifecycles.mount ]export const unmount [// 和 mount 同理reactLifecycles.unmount,cssLifecycles.unmount ]这里要注意一下上面的 https://example.com/main.css 并没有看起来那么简单易用。 假如你用了 Webpack 来打包很有可能会用分包或者 content hash 来给 CSS 文件命名比如 filename: [name].[contenthash].css。那请问 cssUrls 要怎么写呀每次都要改 cssUrls 参数么太麻烦了吧。 single-spa-css 说我可以通过 Webpack 导出的 __webpack_require__.cssAssetFileName 获取导出之后的真实 CSS 文件名。ExposeRuntimeCssAssetsPlugin 这个插件正好可以解决这个问题。这么一来 cssUrls 就可以不用指定了直接把 Webpack 导出的真实 CSS 名放到 cssUrls 里了。 const MiniCssExtractPlugin require(mini-css-extract-plugin); const ExposeRuntimeCssAssetsPlugin require(single-spa-css/ExposeRuntimeCssAssetsPlugin.cjs);module.exports {plugins: [new MiniCssExtractPlugin({filename: [name].css,}),new ExposeRuntimeCssAssetsPlugin({// The filename here must match the filename for the MiniCssExtractPluginfilename: [name].css,}),], };子应用 CSS 样式隔离 虽然 single-spa-css 解决了子应用的 CSS 引入和移除问题但是又带来了另一个问题怎么保证各个子应用的样式不互相干扰呢官方给出的建议是 第一种方法使用 Scoped CSS也即在子应用的 CSS 选择器上加前缀就好了嘛像这样 .app1__settings-67f89dd87sf89ds {color: blue; } 要是嫌麻烦可以在 Webpack 使用 PostCSS Prefix Selector 给样式自动加前缀 const prefixer require(postcss-prefix-selector);module.exports {plugins: [prefixer({prefix: #single-spa-application\\:\\org-name\\/project-name})] }另一种方法是在加载子应用的函数里将子应用挂载到 Shadow DOM 上可以实现完美的样式隔离。Shadow DOM 是什么怎么玩可见 MDN这里。 公共 CSS 样式怎么处理 上面说的都是子应用自己的 CSS 样式那如果子应用之间要共享 CSS 怎么办呢比如有两个子应用都用了 antd那都要 import 两次 antd.min.css 了。 这个问题和上面提到的处理“公共依赖”的问题是差不多的。官方给出两个建议 将公共的 CSS 放到 importmap 里也可以理解为在 index.html 里直接加个 link 获取 antd 的 CSS 完事将所有的公共的 UI 库都 import 到 utility 里将 antd 所有内容都 export再把 utility 包放到 importmap 里然后 import { Button } from your-org-name/utility; 去引入里面的组件 其实上面两个方法都大同小异思路都是在主应用一波引入只是一个统一引入CSS另一个统一引入 UI 库。 子应用的 JS 隔离 我们来想想应用的 JS 隔离本质是什么本质其实就是在 B 子应用里使用 window 全局对象里的变量时不要被 A 子应用给污染了。 一个简单的解决思路就是在 mount A 子应用时正常添加全局变量比如 jQuery 的 $, lodash 的 _。在 unmount A 子应用时用一个对象记录之前给 window 添加的全局变量并把 A 应用里添加 window 的变量都删掉。下一次再 mount A 应用时把记录的全局变量重新加回来就好了。 single-spa 再次站出来这个不用你自己手动记录 window 的变更了。single-spa-leaked-globals 已经实现好了直接用就好了 import singleSpaLeakedGlobals from single-spa-leaked-globals;// 其它 single-spa-xxx 提供的生命周期函数 const frameworkLifecycles ...const leakedGlobalsLifecycles singleSpaLeakedGlobals({globalVariableNames: [$, jQuery, _], // 新添加的全局变量 })export const bootstrap [leakedGlobalsLifecycles.bootstrap, // 放在第一位frameworkLifecycles.bootstrap, ]export const mount [leakedGlobalsLifecycles.mount, // mount 时添加全局变量如果之前有记录在案的直接恢复frameworkLifecycles.mount, ]export const unmount [leakedGlobalsLifecycles.unmount, // 删掉新添加的全局变量frameworkLifecycles.unmount, ]但是这个库的局限性在于每个 url 只能加一个子 app如果多个子 app 之间还是会访问同一个 window 对象也因此会互相干扰并不能做到完美的 JS 沙箱。 比如一个页面里导航栏用 3.0 的 jQuery而页面主体用 5.0 的 jQuery那就会有冲突了。 所以这个库的场景也仅限于首页用 3.0 的 jQuery订单详情页使用 5.0 的 jQuery 这样的场景。 子应用的分类 上面我们说到了当 url 匹配 activeWhen 参数时就会执行对应子应用的生命周期。那这样就相当于子应用和 url 绑定在了一起了。 我们再来看 single-spa-leaked-globalssingle-spa-css 这些库虽然它们也导出了生命周期但这些生命周期与页面渲染、url 变化没有多大关系。 它们与普通的 application 唯一不同的地方就是普通 application 的生命周期是通过 single-spa 来自动调度的而这些库是要通过手动调度的。只不过我们一般选择在子应用里的生命周期里手动调用它们而已。 这种与 url 无关的 “app” 在微前端也有着非常重要的作用一般是在子应用的生命周期里提供一些功能像 single-spa-css 就是在 mount 时添加 link/ 标签。single-spa 将这样的 “类子 app” 称为 Parcel。 同时single-spa 还分出另一个类Utility Modules。很多子应用都用 antd, dayjs, axios 的那么就可以搞一个 utility 集合这些公共库然后统一做 export然后在 importmap 里统一导入。子应用就可以不需要在自己的 package.json 里添加 antd, dayjs, axios 的依赖了。 总结一下single-spa 将微前端分为三大类 分类功能导出是否与 url 有关Application子应用bootstrap, mount, unmount是Parcel功能组件比如给子应用的生命周期打一些补丁bootstrap, mount, unmount, update否Utility Module公共资源所有公共资源否 create-single-spa 上面介绍了一堆的与子应用相关的库如果自己要从 0 开始慢慢地配置子应用就比较麻烦。所以single-spa 说不麻烦有脚手架工具一行命令生成子应用都给您配好了。 npm install --global create-single-spa# 或者 yarn global add create-single-spa 然后 create-single-spa 注意这里的 create-single-spa 指的是创建子应用 总结 以上就是 singles-spa 文档里的所有内容了除了 SSR 和 Dev Tools前者用的不多后者自己看一下就会了不多废话。由于本文是通过发现问题到解决问题来讲述文档内容的所以从头看到尾还是有点乱这里就做一下总结 微前端概念 特点 技术栈无关 独立开发、独立部署 增量升级 独立运行时 single-spa 只做两件事 提供生命周期概念并负责调度子应用的生命周期 挟持 url 变化事件和函数url 变化时匹配对应子应用并执行生命周期流程 三大分类 Application子应用和 url 强相关交由 single-spa 调用生命周期 Parcel组件和 url 无关手动调用生命周期 * Utility Module统一将公共资源导出的模块 “重要”概念 Root Config指主应用的 index.html main.js。HTML 负责声明资源路径JS 负责注册子应用和启动主应用 Application要暴露 bootstrap, mount, umount 三个生命周期一般在 mount 开始渲染子 SPA 应用 * Parcel也要暴露 bootstrap, mount, unmount 三个生命周期可以再暴露 update 生命周期。Parcel 可大到一个 Application也可以小到一个功能组件。与 Application 不同的是 Parcel 需要开发都手动调用生命周期 SystemJS 可以在浏览器使用 ES6 的 import/export 语法通过 importmap 指定依赖库的地址。 和 single-spa 没有关系只是 in-browser import/export 和 single-spa 倡导的 in-browser run time 相符合所以 single-spa 将其作为主要的导入导出工具。 用 Webpack 动态引入可不可以可以甚至可能比 SystemJS 好用并无好坏之分。 single-spa-layout 和 Vue Router 差不多主要功能是可以在 index.html 指定在哪里渲染哪个子应用。 single-spa-react, single-spa-xxx.... 给子应用快速生成 bootstrap, mount, unmount 的生命周期函数的工具库。 single-spa-css 隔离前后两个子应用的 CSS 样式。 在子应用 mount 时添加子应用的 CSS在 unmount 时删除子应用的 CSS。子应用使用 Webpack 导出 CSS 文件时要配合 ExposeRuntimeCssAssetsPlugin 插件来获取最终导出的 CSS 文件名。 算实现了一半的 CSS 沙箱。 如果要在多个子应用进行样式隔离可以有两种方法 Shadow DOM样式隔离比较好的方法但是穿透比较麻烦Scoped CSS在子应用的 CSS 选择器上添加前缀做区分可以使用 postcss-prefix-selector 这个包来快速添加前缀 single-spa-leaked-globals 在子应用 mount 时给 window 对象恢复/添加一些全局变量如 jQuery 的 $ 或者 lodash 的 _在 unmount 时把 window 对象的变量删掉。 实现了“如果主应用一个url只有一个页面”情况下的 JS 沙箱。 公共依赖 有两种方法处理 造一个 Utility Module 包在这个包导出所有公共资源内容并用 SystemJS 的 importmap 在主应用的 index.html 里声明使用 Webpack 5 Module Federation 特性实现公共依赖的导入 哪个更推荐都可以。 最后 single-spa 文档就这些了嘛没错就这些了。文档好像给了很多“最佳实践”但真正将所有“最佳实践”结合起来并落地的又没多少。 比如文档说用 Shadow CSS 来做子应用之间的样式隔离但是 single-spa-leaked-globals 又不让别人在一个 url 上挂载多个子应用。感觉很不靠谱这里行了那里又不行了。 再说回 Shadow CSS 来做样式隔离但是也没有详细说明要具体要怎么做。像这样的例子还有很多文档往往只告诉了一条路怎么走还要看开发者自己。这就你给人一种 “把问题只解决一半” 的感觉。 如果真的想用 single-spa 来玩小 Demo 的用上面提到的小库来搭建微前端是可以的但是要用到生产环境真的没那么容易。 所以为了填平 single-spa 遗留下来的坑阿里基于 single-spa 造出了 qiankun 微前端框架真正实现了微前端的所有特性不过这又是另外一个故事了。
http://www.dnsts.com.cn/news/106247.html

相关文章:

  • 网站做等保是什么意思装修公司取名高端大气
  • 建网站一定要备案吗wordpress模版丢失
  • 网站开发使用的软件外贸自主建站平台
  • 网站充值页面模板小程序代理合同
  • 在济南什么人想做网站中国十大门户网站
  • 汕头seo管理做seo要明白网站内容
  • 网站模版图片网页设计网站视频
  • 中国亚马逊网站建设茶叶网站设计
  • 网站建设维护费用游戏开发用什么语言
  • 网站没有后台登陆文件夹vue 做门户网站
  • 大寺网站建设公司网站建设论文摘要
  • 网站建设人员岗位设置个人网站用什么域名
  • j2ee 建设简单网站高端大气的网站制作
  • 网站没备案可以使用了吗成年人正能量入口
  • 山西省网站建设哪家好开发公司对物业公司的补贴怎么开票
  • 百通互联网站建设在床上做很黄很暴力网站
  • 单位网站建设费用支出账务处理绍兴百度seo排名
  • 谷建网站建设模板进口跨境电商平台排名
  • 国外做外贸的小网站制作网页编码
  • 免费在线观看电视剧的网站付费论坛源码
  • 做网站团队的人员安排郑州市哪里有网站建设
  • 网站建设栏目设计互联网推广和传统营销有哪些相同点
  • 专业商城网站建设网站建设框架都有哪些内容
  • 建设银行的官方网站积分商场更新wordpress咋办
  • 深圳有哪些做网站的公司好那个网站做图片
  • 网站建设与网页制作盒子模型网站内页降权 关键词排名下降
  • 佛山网站设计平台公众平台是什么
  • 网站建设在线建站开发游戏怎么赚钱
  • 教育局网站建设管理工作意见怎么注册网站域名备案
  • 佛山网站优化公司排名简历做的很棒的网站