本文记录我对微前端原理的探索与思考,以及微前端框架qiankun项目实践。

当下前端所存在的一些问题

  1. 在技术浪潮的推动下,由vue、rea陈涉世家翻译及原文ct所主导的单页面应用已成为主流,但在开发中,随着业务的深入和项目的复杂,带来了逻辑定位问题、打包速度问题部署上线等等问题,往往我们可能只是更改了一行JS代码,到最后发布的时候,整个项目却要整个重新打包编译发布。

  2. 公司可能存在旧系统框架开发维护的项目,我们需要对以前的项目进行迭代或前端框架维护的时候,就不得不适应之前项目的开发环境,如果想要陈思思使用新技术,将会遇到阻碍。

  3. 单页面应用在应对大型项目的场景下,不可避免的会造成用户在首次进入的时候加载时间较长,因为几乎所有JS都在打包在一起,即使采用路由懒加载的技术进行优化,也依然无法避免这其中前端框架reactwebpack最多支持几个入口生的DNS解析、三次握手、网络传输、代码解析等耗费的时间代价。

我们所希望的

  1. 陈思思够使各个子模块或者子系统进行隔离。我们在开发或更新一个子模块的时候,只需要对这个子模块单独进行打包,发布上线,而不会影响到其他模块。各个子长沙市天气系统由于相互隔离,不会受限于技术栈的影响,更加轻量化,打包速度,前端性能等也会上去。
  2. 能够使各个子系统之间进行数据共享,例如用户信息,状态。
  3. 能够对JS,CSS等进行相互隔离,防止出现方法或eslint怎么配置样式污染问题。

微前端

微前端(Micro-Frontwebpack是什么ends)是一种类似于微服务的架构,它将微服务的理念应用于前NPM端,即 Web 应用由单女配没有求生欲txt一的单页面应长生十万年用转变为多个小型前端应用聚合为一的应用。然后各个前端应用还可以独立运行、独立开发、独立部署。

实现微前端的方案

1. 路由转发

我们知道单页面应用的路由控制都长沙师范学院是在前端进行,当我们存在多个项目的时候,就算技术栈一样,A项目也指挥不了B里面的路由跳转。但是如果我们将路由跳转交给服务端,当我们访问一个路由的时候,后端进行重定向等操作,这样就会将我们的应用隔离开。 由于不存在跨域,可通过cookie、localstorage等技术进行信息共享。 因为每次路由匹配到的话,都会进行刷新,因此JS,CSS不会互相污染。

缺点:每次跳转都相当于重新刷新了一次页面,不是页面内跳转女配满眼都是钱,体验较差。 优点:配置简单,可快速部署。

2. 嵌长沙市天气常熟市疫情 iframe

通过创建一个父程序,在父程序中监听路由的变化,卸载或加载相应的子程序iframe。因每一个iframe就相当女配没有求生欲藤萝为枝于一个单独的页面女配美炸天,所以iframe具有天然的JS和cs长沙市天气s隔离。在信息共享方面,可以使用postMes女配美炸天sage或者contentWindow的方式进行。

缺点: iframe样式兼容问题。分别为功能性兼容性以及业务性兼容性的问题。并且可能会陈涉世家翻译及原文存在一些安全问题。

  • 主应用劫持快捷键操作
  • 事件无法冒泡到顶层,针对整个应用统一处理时效
  • iframe 内元素会被限制在文档树中,视窗宽高限制问题
  • 无法共享基础库进Webpack一步减少包体积
  • 事件通信繁琐且webpack打包流程限制多 事件整理参考

优点:实webpack面试题现简单,自带沙盒特ESLint

codesandbox

3. 纯 Web Components 开发

将每个子应用采用 Web Components 进行开发。纯 web-components 相当于自定义了一个html标签,我们就可以在任何的框前端框架是干啥的架中进行使用此标签。例如:

   <template id='userInfo'>
   	<div class='user-box'>
       <p class='user-name'>byeL</p>
       <p class='user-sex'></p>
    	</div>
   </template>
 class UserInfo extends HTMLElement {
     constructor() {
       super();
       var templateElem = document.getElementById('userInfo');
       var content = templateElem.content.cloneNode(true);
       this.appendChild(content);
     }
   } 
   window.customElements.define('user-info', UserCard);
// 直接使用
   <body>
     <link rel="import" href="./UserInfo.js">
   </body>
// 在vue中使用(需要在入口的main中引入userInfo
   <template>
     <user-info></user-info>
   </template>
// 在react中使用(需在入口引入userInfo
   class Hello extends React.Component {
     render() {
       return <div><user-info></user-info></div>;
     }
   }

缺点:之前男配每天都在体内成绩的子系统都要进行改造,工作量大,并且通信方面较为复杂。原生组件,普及度不高,未来充满不确定性,容易翻车。

优点:每个子应用拥有独立的script和css,也可单独部署。

4. 组合式应用路由

每个子应用单独打包,部署和运行。不过需要基于父应用进行路由管理。例如:有子应用A的路由是/testA,子女配美炸天应用B的路由是/testB,那webpack环境变量配置么父应用在监听到/testA的时候,如果此时处于/testB,那么首先会直接卸载子应用B,在去加载子应用A。

缺点:需要解决样式冲突,JS污染问题,需要有通信技术等。

优点:女配每天都在抱大腿我要成仙纯前端改造,相比于路由式,无刷新,体验更好。

5. 模块联邦

webpack是什么Webpack 5 的一种微前端方案,使用其 Module federation 插件。

它的主要功能是可以将项目中的部分组件或全部组件暴露给外部使用,我们也可以引用其他项目中暴露的组件,从而实现模块的复用。这和发布 npm 包然后在其他项目中引用听起来有些相似,本质区别在于,npm的webpack最多支持几个入口形式如果a包依赖b包,那webpack热更新原理么b更改发布后需要在a当中install新b包,重新发布a才能应用b的更改,而女配美炸天模块联邦只需要更新b即可。

缺点:依赖webpack,对老项目不友好,不支持js沙盒环境,需要自行实现,第一次需要将引用的依赖前置,可能会导致加载webpack原理时间变长。

优点:未来可期。

其他方案:EMP微前端方案

方案选择与实践

目前较多的微前端方案采用的技术方案是组合式应用路由分发,那么需要解决的问题是:JS的沙盒环境、css的样式重叠或冲突、以及通信技术问题。

css冲前端框架是干啥的突解决方案:

  1. 类似于vue的swebpack是什么coped。在打包的时候,对css选择器加上响应的属性,属性的key值是一些不重复的hash值,然后在选择的时候,使用属性选择器进行选择。
  2. 可以自定义前缀。在开发子模块之前,需要确定一个全局唯一的css前缀,然后在书写的过程中同一添加此前缀,或在根root上添加此前缀,使用less或sass作用域嵌套即可。例如:
<div class='rootA'>
	<span class='rootA-span'></span>  
</div>
<style>
.root{
  .rootA-span{
    // 子路由A的css
  }
}    
</style>

JS的沙盒环境:

首先我们需要明确的是,如果采用组合式应用路eslint是什么由开发,对于JS上下文有什么影响?我们做个例子:

假如我有个a子应用,会给window上挂在一个函webpack热更新原理数,函数名是hello,然后我父应用上也有一个函数名是hello,那么在子应用进行加载的时候,就会覆盖父类上的方法。

// 子应用A
window.hello = () => {
  alert('我是子应用A');
};
// 父应用
window.hello = () => {
  alert('我是父应用');
};

基于上面的例子,我们难破mg5大致就可以看出,沙盒环境最主要做的就是一个js作用域、属性等的隔离。那么在实际的应用中,基本采用以下原理进行隔离:

1. diff方法。

当我们的子页面加载到父CSS类的基座中的时候,我们可以生成一个map的散列表。在页面渲染之前,我们先把当前的window上的难破mg5日剧变量等都存储在这个map中。当页面卸载的时候,我们在遍历这个map,将其数据在替换回去。

class Sandbox {
  constructor() {
    this.cacheMy = {} // 存放修改的属性
    this.cacheBeforeWindow = {}
  }
  showPage() {
    this.cacheBeforeWindow = {}
    for (const item in window) {
      this.cacheBeforeWindow[item] = window[item]
    }
    Object.keys(this.cacheMy).forEach((p) => {
      window[p] = this.cacheMy[p]
    })
  }
  hidePage() {
    for (const item in window) {
      if (this.cacheBeforeWindow[item] !== window[item]) {
        // 记录变更
        this.cacheMy[item] = window[item]
        // 还原window
        window[item] = this.cacheBeforeWindow[item]
      }
    }
  }
}
const diffSandbox = new Sandbox()
// 模拟页面激活
diffSandbox.showPage() // 激活沙箱
window.info = '我是子应用'
console.log('页面激活,子应用对应的值', window.info)
// 模拟页面卸载
diffSandbox.hidePage()
// 模拟页面激活
console.log('页面卸载后,子应用的对应的值', window.info)
diffSandbox.showPage() // 重新激活
console.log('页面激活,子应用对应的值', window.info)

2. 使用代理女配每天都在抱大腿我要成仙

这里需要用到es6的新特性:proNPMxy,查看MDN Proxy介绍。女配没有求生欲txt原理是监听get和set方法,针对当前路由进女配每天都在抱大腿我要成仙行window的属性或方法的存取

const windowMap = new Map();
const resertWindow = {};
let routerUrl = '';
const handler = {
    get: function(obj, prop) {
        const tempWindow = windowMap.get(routerUrl);
        console.log(windowMap, routerUrl);
        return tempWindow[prop];
    },
    set: function(obj, prop, value) {
        if (!windowMap.has(routerUrl)) {
            windowMap.set(routerUrl, JSON.parse(JSON.stringify(resertWindow)));
        }
        const tempWindow =  windowMap.get(routerUrl);
        tempWindow[prop] = value;
        // console.log(obj, prop, value);
    },
};
let proxyWindow = new Proxy(resertWindow, handler);
// 首先是父类的a属性.
proxyWindow.a = '我是父类的a属性的值';
// 改变路由到子类
routerUrl = 'routeA';
proxyWindow.a = '我是routerA的a属性的值'
// 改变路由到父类
routerUrl = '';
console.log(proxyWindow.a);
// 改变路由到子类
routerUrl = 'routeA';
console.log(proxyWindow.a);

3. iframe自带css和js沙盒隔离。

single-spa 框架

通过上面的了解,webpack最多支持几个入口我们知道要实现组合式应用路由开发,首先需要设计一套前端基座,用于调控子项目,singlewebpack配置-spa就是其中最广为人知的框架,先以Vue为例看下如何使用它。

1. 在子项目eslint怎么配置中引入single-spa-webpack原理vue

npm install single-spa-vue --save

2. 在子类的m前端框架是干啥的ain.js中加入single-女配没有求生欲txtspa-vue相应的生命周期

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import singleSpaVue from 'single-spa-vue'
Vue.config.productionTip = false
const appOptions = {
  el: '#microApp',
  router,
  render: h => h(App)
}
// 支持应用独立运行、部署,不依赖于基座应用
if (!process.env.isMicro) {
  delete appOptions.el
  new Vue(appOptions).$mount('#app')
}
// 基于基座应用,导出生命周期函数
const vueLifecycle = singleSpaVue({
  Vue,
  appOptions
})
// 启动生命周期
export function bootstrap (props) {
  console.log('app2 bootstrap')
  return vueLifecycle.bootstrap(() => {})
}
// 挂载生命周期
export function mount (props) {
  console.log('app2 mount')
  return vueLifecycle.mount(() => {})
}
// 卸载生命周期
export function unmount (props) {
  console.log('app2 unmount')
  return vueLifecycle.unmount(() => {})
}

3. 新建vue.config.js文件,并设置导出格式为umd

const package = require('./package.json')
module.exports = {
  // 告诉子应用在这个地址加载静态资源,否则会去基座应用的域名下加载
  publicPath: '//localhost:8082',
  // 开发服务器
  devServer: {
    port: 8082,
  },
  configureWebpack: {
    // 导出 umd 格式的包,在全局对象上挂载属性 package.name,基座应用需要通过这个全局对象获取一些信息,比如子应用导出的生命周期函数
    output: {
      // library 的值在所有子应用中需要唯一
      library: package.name,
      libraryTarget: 'umd',
    },
  },
}

经过以上几步操作,一女配每天都在为国争光个微前端的子项目基本就创建完成了,我们webpack最多支持几个入口可以看出single-spa在这里只做了一件事,那就是提供生命周期的概念。

4. 创建父类基座。

4.1. 父类基座引入single-spa
npm install single-spa --save
4.2. 改造父类main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import { registerApplication, start } from 'single-spa'
Vue.config.productionTip = false
// 远程加载子应用
function createScript(url) {
  return new Promise((resolve, reject) => {
    const script = document.createElement('script')
    script.src = url
    script.onload = resolve
    script.onerror = reject
    const firstScript = document.getElementsByTagName('script')[0]
    firstScript.parentNode.insertBefore(script, firstScript)
  })
}
// 记载函数,返回一个 promise
function loadApp(url, globalVar) {
  // 支持远程加载子应用
  return async () => {
    //
    await createScript(url + '/js/chunk-vendors.js')
    await createScript(url + '/js/app.js')
    // 这里的return很重要,需要从这个全局对象中拿到子应用暴露出来的生命周期函数
    return window[globalVar]
  }
}
// 子应用列表
const apps = [
  {
    // 子应用名称
    name: 'app1',
    // 子应用加载函数,是一个promise
    app: loadApp('http://localhost:8083', 'app1'),
    // 当路由满足条件时(返回true),激活(挂载)子应用
    activeWhen: (location) => location.pathname.startsWith('/app1'),
    // 传递给子应用的对象
    customProps: {},
  },
  {
    name: 'app2',
    app: loadApp('http://localhost:8082', 'app2'),
    activeWhen: (location) => location.pathname.startsWith('/app2'),
    customProps: {},
  },
]
// 注册子应用
for (let i = apps.length - 1; i >= 0; i--) {
  registerApplication(apps[i])
}
new Vue({
  router,
  mounted() {
    // 启动
    start()
  },
  render: (h) => h(App),
}).$mount('#app')

经过上面改造完成之后,一个父类基座应用也就创建完毕了,看看它主要做了哪些事:

  1. loadA女配每天都在抱大腿我要成仙pp主女配没有求生欲txt要是根据资源地址去请求资源
  2. createScript主要是将请求回来的script添加到页面中。
  3. apps就是一些子类应用的描述。
  4. registerApplication就是将这些子应用注册到single-spa中。

现在一个由single-spa改造完成的微前端项目就完成了,我们再回头看看其原理流程图

微前端很好,为什么我却不使用?

从中我们可以看出浏览器首次打开父类应用的webpack性能优化时候,第一webpack配置步就是先调用reg长沙师范学院isterApplication注册app长生十万年,接下来判断当前的路由是属于哪一个子应用webpack打包流程的,他的判断依据就是appwebpack是什么s中的activeWhen,接下来就会将当前的子应用webpack环境变量配置划分状态,appToLoad,appToUnmoun难破mg5日剧tedESLint, appToMounted。接下来根据子应用的状态,先去执行需要卸载的子应用,卸载完成之后,就会去执行状态为appToLoad, appToMwebpack配置ounted的子应用,那么前端框架有哪些在最后在常熟市疫情执行相应的回调函eslint报错怎么解决数,也就是我们在子应用中注册的那些生命周期。

前面铺垫了这么陈思思多,我们发现single-spa就只做了两件事:提供生命周期概念与负责调度子应用的生命周期,对于组合式应用路由模式还有其它尚未解决的问题怎么办呢,这时候就要讲下一个框架:qiankun

qi女配美炸天ankun 框架难破mg5

qiankun 是一个基于 sinESLintgle-spa 的微前端实现库,样式隔离、JS沙盒环境、空闲预加载这些qiankun都帮我们做了,不需要自己去处webpack面试题理。在single-spa的开发过程中,我们需要自己手动的去写调用子应用JS的方法(如上面的 createScript方法),而qiankun不需要,乾坤只需要你传入响应的apps的配置即可,会帮助我们去加载难破mg5日剧

说到资源加载方案,可分为两种:

1. JS Entry难破mg5日剧

该方式通常是子应用将资源打成一份 script,这个方案的限制也颇多,如要求子应用的所有资源打包到一个 js bundle 里,包括 css、图片等资源。除了打出来的包可能体积庞大之外的问题之外,资源的前端框架react并行加载等特性也无法利用上。

2. HTML Entry (qiankun所采用的)

这种方式更加灵活,直接将子应用常熟市疫情打出来 HTML 作为入仓鼠寿命口,主框架可以通过 fetwebpack官网中文ch html 的方式获取子应用的静态资源,同时将 HTML document 作为子Webpack节点塞到主框架的容器中。这样不仅可以极大女配美炸天的减少主应用的接入成本,子应用的开发方式及打包方式基本上也webpack面试题不需要调整,而且可以天然的解决子应用仓鼠寿命之间样式隔离的问题(后面提到)。

qiankeslint怎么配置un微前端实践

项目架构简述:1. 基座采用:vue,2. 子项目:vue 2/3 、 react

说明:vue 通过 vue cli 进行创建, react 通过 create-react-前端框架vueapp 进行项目创建。

完整示例 Demo -> Micro-Frontends-Practice,以下篇幅为过程实现,代码片段经过反复修改女配满眼都是钱,有可能存在部分错误,具体实现参女配没有求生欲藤萝为枝考demo。

在创建完父类项目以及子类项目之后,安装好 qiankun 依赖库。

npm install qiankun --save

在安装完成之后,我们需要对其做相应的处理。分为三部分:

1. 在父类中创建微前端基座

首先在 src 下创建一个子应用的配置文件,我们叫做 micro_app.js

// src/micro_app.js
const microApps = [
  {
    name: 'micro_vue',
    entry: '//localhost:8081/',
    activeRule: '/micro_vue',
    container: '#subapp-viewport', // 子应用挂载的div
    props: {
      routerBase: '/micro_vue', // 下发路由给子应用,子应用根据该值去定义qiankun环境下的路由
    },
  },
  {
    name: 'micro_react',
    entry: '//localhost:10100/',
    activeRule: '/micro_react',
    container: '#subapp-viewport', // 子应用挂载的div
    props: {
      routerBase: '/micro_react',
    },
  },
]
export default microApps

在设置完子应用的配置文件之后,我们需要改写 App.vue

// 为了简单,只是改写了模板文件,
<template>
  <div id="layout-wrapper">
    <div class="layout-header">头部导航</div>
    <div id="subapp-viewport"></div>
  </div>
</template>   

长生十万年下来是更改 main.js。在 main.js 中最主要做的事情就是将之前配置的子应用进行注册并且启动 qia女配没有求生欲txtnkun 框架服务

import Vue from 'vue'
import App from './App.vue'
import store from './store'
import router from './router'
import { registerMicroApps, start } from 'qiankun'
import appConfig from './micro_app'
Vue.config.productionTip = false
new Vue({
  router,
  store,
  render: (h) => h(App),
}).$mount('#app')
// 注册子应用
registerMicroApps(appConfig, {
  beforeLoad: (app) => {
    console.log('before load app.name====>>>>>', app.name)
  },
  beforeMount: [
    (app) => {
      console.log('[LifeCycle] before mount %c%s', 'color: green;', app.name)
    },
  ],
  afterMount: [
    (app) => {
      console.log('[LifeCycle] after mount %c%s', 'color: green;', app.name)
    },
  ],
  afterUnmount: [
    (app) => {
      console.log('[LifeCycle] after unmount %c%s', 'color: green;', app.name)
    },
  ],
})
// 启动qiankun
start()   

父类的基座CSS创建完webpack原理成之后,接下来就女配没有求生欲txt宝书网是子应用的注册了。

2. vue 接入 qia陈思思nkun

首先需要在项目根目录下建立 vue.config.js 用来改写 webpack 的相应配置。在 src 下创建 public-path.js。public-path 用来改写 webpack 打包好之后,通过那个难破mg5日剧路径可以访问到打包后的文件。

// vue.config.js
const { name } = require('./package.json')
module.exports = {
  configureWebpack: {
    output: {
      library: `${name}-[name]`,
      libraryTarget: 'umd',
      jsonpFunction: `webpackJsonp_${name}`,
    },
  },
  devServer: {
    port: 8081, // 在.env中VUE_APP_PORT=7788,与父应用的配置一致
    headers: {
      'Access-Control-Allow-Origin': '*', // 主应用获取子应用时跨域响应头
    },
  },
}
// public-path.js
;(function () {
  // 用来判断是否运行在乾坤的框架下
  if (window.__POWERED_BY_QIANKUN__) {
    // eslint-disable-next-line no-undef
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
  }
})()

修改 router 下的 Index,我们只需要导eslint报错怎么解决出对应的路径定义即可,不需要导出对应的 vue-router 实例,如果直接导出 vue-router 实例的话,会与我们在父类 micro_app.js 中设置的 routerBase 匹配不上。导致渲染子应用失败。

import Home from '../views/Home.vue'
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home,
  },
  {
    path: '/about',
    name: 'About',
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'),
  },
]
export default routes

接下来就是需要改写 maeslint报错怎么解决in.js。同样是生命周期的引入。并且注册 vue-vouter 实例。

import './public-path' // 注意需要引入public-path
import Vue from 'vue'
import App from './App.vue'
import routes from './router'
import store from './store'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
Vue.config.productionTip = false
let instance = null
window.projectName = 'micro_vue'
function render(props = {}) {
  // 这个是我们在父类注册的时候定义的那些参数。
  const { container, routerBase } = props
  const router = new VueRouter({
    base: window.__POWERED_BY_QIANKUN__ ? routerBase : process.env.BASE_URL,
    mode: 'history',
    routes,
  })
  instance = new Vue({
    router,
    store,
    render: (h) => h(App),
  }).$mount(container ? container.querySelector('#app') : '#app')
}
if (!window.__POWERED_BY_QIANKUN__) {
  render()
}
export async function bootstrap() {
  console.log('[vue] vue app bootstraped')
}
export async function mount(props) {
  console.log('[vue] props from main framework', props)
  render(props)
}
export async function unmount() {
  instance.$destroy()
  instance.$el.innerHTML = ''
  instance = null
}

最后需要在根目录下创建.仓鼠饲养八大禁忌env 文件。

VUE_APP_PORT = 8081

以上步骤完成之后,我们只需要启动项目我们既可以通过对应的路由进行访问了http://localhost:xxxx/micro_vue

完整示例 Demo -> Micro-Frontends-Practice

3. react 项目的接入

在 src 下创建 public-path.js 文件

if (window.__POWERED_BY_QIANKUN__) {
  // eslint-disable-next-line no-undef
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}

接下来修改index.js

首先我们需要引入r难破mg5eact-router-dom

// npm install react-router-dom --save
import { BrowserRouter as Router } from 'react-router-dom'
// 接下来我们需要对render进行改写
function render(props) {
  const { container } = props
  ReactDOM.render(
    <Router basename={window.__POWERED_BY_QIANKUN__ ? '/micro_react' : '/'}>
      <App />
    </Router>,
    container ? container.querySelector('#root') : document.querySelector('#root'),
  )
}
// 然后加入生命周期即可
export async function bootstrap() {
  console.log('ReactMicroApp bootstraped')
}
/**
 * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
 */
export async function mount(props) {
  console.log('ReactMicroApp mount', props)
  render(props)
}
/**
 * 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
 */
export async function unmount() {
  console.log('ReactMicroApp unmount')
  ReactDOM.unmountComponentAtNode(document.getElementById('root'))
}
修改 webpack 配置
方式 1:

运行 npm run eject

修改config/webpackDevServer.config.js

module.exports = function (proxy, allowedHost) {
  return {
    headers: {
      'Access-Control-Allow-Origin': '*', // 表示允许跨域
    },
    ...
}

接下来修改config/webpack.c长沙师范学院onfig.js

return {
  ...
  output: {
    // The build folder.
    ...
    // 微应用配置
    library: `${appPackageJson.name}-[name]`,
    libraryTarget: 'umd'
  },
  ...
}
方式2:

安装插件 @rescripESLintts/cli,当然也可以选择其他的插件,例如 reaceslintrc.js配置t-app-rewired

npm i -D @rescripts/cli

根目录新增 .re辰时是几点scriptsrc.js

const { name } = require('./package')
module.exports = {
  webpack: (config) => {
    config.output.library = `${name}-[name]`
    config.output.libraryTarget = 'umd'
    config.output.jsonpFunction = `webpackJsonp_${name}`
    config.output.globalObject = 'window'
    return config
  },
  devServer: (_) => {
    const config = _
    config.headers = {
      'Access-Control-Allow-Origin': '*',
    }
    config.historyApiFallback = true
    config.hot = false
    config.watchContentBase = false
    config.liveReload = false
    return config
  },
}

修改 package.json

         -   "start": "react-scripts start",
         +   "start": "rescripts start",
         -   "build": "react-scripts build",
         +   "build": "rescripts build",
         -   "test": "react-scripts test",
         +   "test": "rescripts test",

最后,同理在根目录下创建一个.env 文件,

PORT = 10100
BROWSER = none

然后启动 react 项目,之后就可以webpack面试题通过http://localhost:xxx/micro_react进行常熟市疫情访问了

完整示例 Demo -> Micro-Frontends-Practice

数据交互

qiankun 内前端框架vue部使用 initGlobalState(state)定手机前端框架义全局状态,该方法执行后返回一个 MicroAppStateActions 实例,实例中包含三个方法,分别是 onGlobalSta手机前端框架teChange、setGlobalState、offGlobalState常熟市疫情Change。

默认会通过 props 将通信方法传递给子应用。

  • on女配满眼都是钱GlobalStateChange: 当 global 有数据发生更改的时候,就会触发回调函数,回调函数传入的是更改后的 globalState
  • setGlobalState: 更改 globalstate 的方法
  • offGlobalStateChange: 移除监听,微应用执行前端框架react umount 时会默认调用。

webpack面试题何使用:

首先我长沙师范学院们在父类基座的 src 下建一个文件为action.js文件。

import { initGlobalState } from 'qiankun'
import store from './store'
const initialState = {
  //这里写初始化数据
  userName: 'testInfo',
  userId: '1232',
}
// 初始化 state
const actions = initGlobalState(initialState)
actions.onGlobalStateChange((state, prev) => {
  //监听公共状态的变化
  console.log('主应用: 变更前')
  console.log(prev)
  console.log('主应用: 变更后')
  console.log(state)
})
export default actions

在父类如何获取初始的GlobalStatewebpack是什么:

// 当onGlobalStateChange的最后一个属性为true的时候,表示立即获取,不需要等待数据发生变更
action.onGlobalStateChange((state) => {
  console.log('全局状态发生改变')
  // this.mes = state
  this.userInfo.userName = state.userName
  console.log(state)
}, true)

在父类中更改GlobalState:

action.setGlobalState({
  userName: '更改之后的名称',
  userId: 'new Id',
})

如何在子类中进行使用:

首先在子类中 src 下创建一个 action.js

function emptyAction() {
  //设置一个actions实例
  // 提示当前使用的是空 Action
  console.warn('Current execute action is empty!')
}
class Actions {
  // 默认值为空 Action
  actions = {
    onGlobalStateChange: emptyAction,
    setGlobalState: emptyAction,
  }
  /**
   * 设置 actions
   */
  setActions(actions) {
    this.actions = actions
  }
  /**
   * 映射
   */
  onGlobalStateChange(...args) {
    return this.actions.onGlobalStateChange(...args)
  }
  /**
   * 映射
   */
  setGlobalState(...args) {
    return this.actions.setGlobalState(...args)
  }
}
const actions = new Actions()
export default actions

之后我们在女配没有求生欲藤萝为枝子类的 main.js 中接受 props 上传递过来的方法webpack官网中文

export async function mount(props) {
  console.log('[vue] props from main framework', props)
  actions.setActions(props)
  render(props)
}

之后的获取数据,以及更新与父类的相同。

结尾

总结我对微前端的思考,我认为它或许会成为主流,但未来不一定完全属于微前端。因为我们希望的一直都是——可以使用熟悉webpack打包流程的技术、或是新潮的技术去完成开webpack最多支持几个入口发工作,微前端既是在这种情况下诞生的。而解决大型系统各方各面的问题,可以是统一治理,也可以eslintrc.js配置是分而治之,微前端则是后者。 所以我们当下既要全面了解各种微前端的技术,也不用急于去追随潮流webpack官网中文,强行微前端化。如果争取在实践中获得更多经验与思考,不论什么女配美炸天技术ESLint都会有派上用场的时候。