微前端 ---- wujie-vue3 原理

2023-12-07 06:20

本文主要是介绍微前端 ---- wujie-vue3 原理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

 前言

设置子应用​

预加载​

启动子应用​

封装 

1.创建文件

2.安装依赖

3.编写组件

4.配置打包规则

5.执行打包命令 

 swc技术

SWC

Babel

 Babel VS SWC

更改使用 swc 解析 

 使用swc 完成 esm 模式  (export--import)

发布到npm

更改package.json

创建npm账户

登录npm

切换npm源

发布到npm


 前言

这个包其实是作者根据wujie 自行封装的我们也可以自己去封装一下

设置子应用​

非必须,由于preloadAppstartApp参数重复,为了避免重复输入,可以通过setupApp来设置默认参数。

  • name: "唯一id",
  • url: "子应用地址",
  •  el: "容器", 
setupApp({ name: "唯一id", url: "子应用地址", exec: true, el: "容器", sync: true })

预加载​

javascript

preloadApp({ name: "唯一id"});

启动子应用​

javascript

startApp({ name: "唯一id" });

 知道以上几个API的用法就可以简单封装一个无界的组件我们使用vue3 + webpack + swc 封装

封装 

1.创建文件

  • index.ts 入口文件
  • type.ts类型文件
  • index.d.ts 类型声明文件
pnpm init  生成package.json
tsc --init 生成tsconfig.json
创建webpack.config.js

2.安装依赖

pnpm i wujie   
pnpm i vue -D   
pnpm i webpack-cli -D
pnpm i typescript -D 
pnpm i ts-loader  -D 
pnpm i webpack -D

3.编写组件

声明文件

// import { bus, preloadApp, destroyApp, setupApp } from "wujie";
import type { App } from 'vue';declare const WujieVue: {// bus: typeof bus;// setupApp: typeof setupApp;// preloadApp: typeof preloadApp;// destroyApp: typeof destroyApp;install: (app: App) => void
};export default WujieVue;

 

类型文件

import type { plugin } from 'wujie'
type lifecycle = (appWindow: Window) => any;
interface Props {/** 唯一性用户必须保证 */name: string;/** 需要渲染的url */url: string;/** 需要渲染的html, 如果用户已有则无需从url请求 */html?: string;/** 渲染的容器 */loading?: HTMLElement;/** 路由同步开关, false刷新无效,但是前进后退依然有效 */sync?: boolean;/** 子应用短路径替换,路由同步时生效 */prefix?: { [key: string]: string };/** 子应用保活模式,state不会丢失 */alive?: boolean;/** 注入给子应用的数据 */props?: { [key: string]: any };/** js采用fiber模式执行 */fiber?: boolean;/** 子应用采用降级iframe方案 */degrade?: boolean;/** 自定义运行iframe的属性 */attrs?: { [key: string]: any };/** 自定义降级渲染iframe的属性 */degradeAttrs?: { [key: string]: any };/** 代码替换钩子 */replace?: (codeText: string) => string;/** 自定义fetch,资源和接口 */fetch?: (input: RequestInfo, init?: RequestInit) => Promise<Response>;/** 子应插件 */plugins: Array<plugin>;/** 子应用生命周期 */beforeLoad?: lifecycle;/** 没有做生命周期改造的子应用不会调用 */beforeMount?: lifecycle;afterMount?: lifecycle;beforeUnmount?: lifecycle;afterUnmount?: lifecycle;/** 非保活应用不会调用 */activated?: lifecycle;deactivated?: lifecycle;
};export { Props } 

组件封装

这段代码是一个Vue组件的封装,它使用了Vue 3的Composition API来定义组件。让我来解释一下它的功能和结构

首先,我们需要了解一下这个组件的功能。这个组件是一个封装了微前端框架wujie的Vue组件,它可以在Vue应用中加载其他独立的微前端应用。它接受一些props作为配置参数,包括组件的宽度、高度、名称、URL等。它还提供了一些生命周期钩子函数,用于在组件加载、卸载和切换时执行一些操作。

接下来,让我们来看一下这个组件的代码结构。

首先,我们引入了Vue的一些函数和类型,包括defineComponenthgetCurrentInstance等。这些函数和类型将在后面的代码中使用。

然后,我们定义了一个名为wujie的组件,使用defineComponent函数来创建组件。在props选项中,我们定义了组件的props,包括宽度、高度、名称、URL等。其中,一些props的类型是复杂的,我们使用PropType来进行强制类型转换,以确保传入的props符合预期的类型。

setup函数中,我们定义了组件的逻辑。首先,我们定义了一个init函数,用于初始化微前端应用。在这个函数中,我们使用startApp函数来启动微前端应用,传入一些配置参数,包括应用的名称、URL、加载元素等。

接下来,我们定义了一个handleEmit函数,用于处理事件的触发和参数的传递。在这个函数中,我们使用emit函数来触发事件,并将参数传递给事件的监听函数。

然后,我们使用onMounted钩子函数,在组件挂载后执行一些操作。在这个钩子函数中,我们使用bus.$onAll函数来监听所有事件的触发,并将事件和参数传递给handleEmit函数。然后,我们调用init函数来初始化微前端应用。

接下来,我们使用watch函数来监听props.nameprops.url的变化。当这两个props发生变化时,我们重新调用init函数来重新初始化微前端应用。

最后,我们使用onBeforeMount钩子函数,在组件卸载前执行一些操作。在这个钩子函数中,我们使用bus.$offAll函数来取消所有事件的监听。

最后,我们返回一个渲染函数,使用h函数来创建一个div元素,并将宽度和高度设置为props中的值。我们还将这个div元素的引用设置为wujie,以便以后可以访问它。

最后,我们通过wujie.install方法将这个组件注册为Vue插件,以便在Vue应用中使用。

import { defineComponent, h, getCurrentInstance, onMounted, watch, onBeforeMount } from 'vue'
//子组件的props类型是复杂的类型的时候,可以用propType进行强制类型转换(eg 复杂函数,对象数组,对象的类型检查)import type { PropType } from 'vue'
import { startApp, bus } from 'wujie'
import { Props } from './type'
// 声明组件
const wujie = defineComponent({props: {width: { type: String, default: "" },height: { type: String, default: "" },name: { type: String, default: "", required: true },loading: { type: HTMLElement, default: undefined },url: { type: String, default: "", required: true },sync: { type: Boolean, default: undefined },prefix: { type: Object, default: undefined },alive: { type: Boolean, default: undefined },props: { type: Object, default: undefined },attrs: { type: Object, default: undefined },replace: { type: Function as PropType<Props['replace']>, default: undefined },fetch: { type: Function as PropType<Props['fetch']>, default: undefined },fiber: { type: Boolean, default: undefined },degrade: { type: Boolean, default: undefined },plugins: { type: Array as PropType<Props['plugins']>, default: null },beforeLoad: { type: Function as PropType<Props['beforeLoad']>, default: null },beforeMount: { type: Function as PropType<Props['beforeMount']>, default: null },afterMount: { type: Function as PropType<Props['afterMount']>, default: null },beforeUnmount: { type: Function as PropType<Props['beforeUnmount']>, default: null },afterUnmount: { type: Function as PropType<Props['afterUnmount']>, default: null },activated: { type: Function as PropType<Props['activated']>, default: null },deactivated: { type: Function as PropType<Props['deactivated']>, default: null },},setup(props, { emit }) {const init = () => {// 获取当前组件实例const instance = getCurrentInstance()// 微前端初始化方法startApp({name: props.name,url: props.url,el: instance?.refs.wujie as HTMLElement,loading: props.loading,alive: props.alive,fetch: props.fetch,props: props.props,attrs: props.attrs,replace: props.replace,sync: props.sync,prefix: props.prefix,fiber: props.fiber,degrade: props.degrade,plugins: props.plugins,beforeLoad: props.beforeLoad,beforeMount: props.beforeMount,afterMount: props.afterMount,beforeUnmount: props.beforeUnmount,afterUnmount: props.afterUnmount,activated: props.activated,deactivated: props.deactivated,})}// 监听事件触发传递参数const handleEmit = (event: string, ...args: any) => {emit(event, ...args)}// 要获取el 所以采用onMountedonMounted(() => {// 任何$emit都会导致监听函数触发,第一个参数为事件名,后续的参数为$emit的参数bus.$onAll(handleEmit)init()})// name 跟url可能是动态变化的,所以要watch后重新初始化watch([props.name, props.url], () => {init()})// 销毁时要取消监听onBeforeMount(() => {bus.$offAll(handleEmit)})// 返回渲染函数return () => h('div', {style: {width: props.width,height: props.height,},// 当作el传递给startAppref: 'wujie', //方便以后读取})}})
// 提供app.use使用的方法 会自动调用install
wujie.install = function (app: any) {app.component('WujieVue', wujie)
}
export default wujie

4.配置打包规则

  1. 引入所需的模块:

    • Configuration:Webpack 的配置类型。
    • path:Node.js 的内置模块,用于处理文件路径。
  2. 创建一个配置对象 config,用于配置 Webpack。

  3. 设置入口文件:

    • entry 属性指定了入口文件的路径,这里是 ./src/index.ts
  4. 设置出口文件:

    • output 属性指定了打包后的文件的输出配置。
    • filename 属性指定了输出文件的名称,这里是 wujie.js
    • path 属性指定了输出文件目的录,这里使用了 path.resolve 方法来获取绝对路径,__dirname 表示当前文件所在的目录,./lib 表示输出到当前目录下的 lib 文件夹。
  5. 配置打包忽略的文件:

    • externals 属性指定了需要忽略打包的模块。
    • 这里忽略了 vue 和 wujie 模块,意味着在打包时不会将这两个模块打包进最终的输出文件中,而是通过外部引入的方式使用它们。
  6. 设置打包模式:

    • mode 属性指定了打包的模式,这里是 "none",表示不使用任何内置优化。
  7. 配置模块规则:

    • module 属性用于配置模块的加载规则。
    • rules 属性是一个数组,包含了各种规则对象。
    • 这里只有一个规则对象,用于解析 TypeScript 文件。
    • test 属性指定了需要匹配的文件类型,这里是以 .ts 结尾的文件。
    • loader 属性指定了用于处理匹配到的文件的加载器,这里是 ts-loader,用于将 TypeScript 转换为 JavaScript。
  8. 导出配置对象 config,使其可以被 Webpack 使用。

const { Configuration } = require("webpack");
const path = require("path");
/*** @type {Configuration} //配置智能提示*/
const config = {entry: "./src/index.ts", //入口文件//出口output: {//   文件名filename: "wujie.js",//   出口文件目录path: path.resolve(__dirname, "./lib"),},//配置打包忽略的文件externals: {vue: "vue",wujie: "wujie",},// 模式源码的方式mode: "none",module: {// 打包规则rules: [{test: /\.ts$/, //解析tsloader: "ts-loader",},],},
};module.exports = config;

5.执行打包命令 

pnpm run lib 

  "scripts": {"test": "echo \"Error: no test specified\" && exit 1","lib": "webpack",},

 swc技术

SWC

SWC(Super-fast WebAssembly Compiler)是一个基于Rust语言开发的高性能JavaScript和TypeScript编译器。它旨在提供快速且可靠的代码转换和优化,以改善JavaScript和TypeScript应用程序的性能。

SWC的主要特点和优势包括:

  1. 高性能:SWC通过使用Rust语言和优化的算法,实现了比传统的JavaScript编译器更快的编译速度。它能够处理大型代码库,并在短时间内生成高效的输出代码。

  2. 完整的语法支持:SWC支持最新的JavaScript和TypeScript语法,包括ES2015+、JSX、Decorators等。它可以将这些新语法转换为向后兼容的代码,以便在不同的JavaScript环境中运行。

  3. 模块化支持:SWC支持处理模块化的代码,包括CommonJS、ES modules和AMD等。它可以处理模块之间的依赖关系,并生成适合目标环境的模块化代码。

  4. 优化和压缩:SWC可以进行代码优化和压缩,以减小输出文件的大小并提高运行时性能。它可以消除未使用的代码、进行常量折叠和内联等优化操作。

  5. 插件系统:SWC提供了灵活的插件系统,允许开发人员根据自己的需求扩展和定制编译过程。开发人员可以编写自定义的插件来处理特定的转换或优化操作。

总的来说,SWC是一个强大且高性能的JavaScript和TypeScript编译器,适用于需要快速编译和优化代码的项目。它可以帮助开发人员提高应用程序的性能,并提供丰富的语法支持和灵活的插件系统。


Babel

Babel是一个广泛使用的JavaScript编译器工具,用于将新版本的JavaScript代码转换为向后兼容的旧版本,以便在不支持新语法和特性的环境中运行。

JavaScript是一门不断发展的语言,每年都会推出新的语法和特性,但是不同的浏览器和JavaScript运行时环境对这些新特性的支持程度各不相同。这就导致开发人员在编写代码时需要考虑到目标环境的兼容性问题。

Babel的作用就是解决这个问题。它可以将使用了最新语法和特性的JavaScript代码转换为向后兼容的代码,以便在旧版本的浏览器环和境中运行。它可以将ES6、ES7、ES8等新版本的JavaScript代码转换为ES5或更早版本的代码,同时还可以处理一些其他的转换,如JSX转换、TypeScript转换等。

Babel的工作原理是通过解析源代码,构建抽象语法树(AST),然后根据配置文件中的规则进行转换。开发人员可以根据自己的需求配置Babel,选择需要的转换插件和预设,以及指定目标环境的兼容性要求。

总的来说,Babel是一个非常强大的工具,可以帮助开发人员在不同的JavaScript环境中编写兼容性更好的代码,提高开发效率和代码质量


 Babel VS SWC

Babel和SWC都是用于转换JavaScript代码的工具,但它们有一些区别和特点。

  1. 性能:SWC在性能方面通常比Babel更快。SWC是用Rust编写的,它使用了更高效的算法和数据结构,因此在转换大型代码库时可能会比Babel更快。

  2. 兼容性:Babel是非常成熟和广泛使用的工具,它支持广泛的JavaScript语法和特性转换,并且有大量的插件和预设可供选择。SWC相对较新,尽管它也支持许多常见的语法和特性转换,但可能没有像Babel那样广泛的生态系统。

  3. 生态系统:Babel拥有庞大的生态系统,有许多插件和预设可供选择,可以满足各种不同的需求。SWC的生态系统相对较小,但随着其不断发展,预计会有更多的插件和工具出现。

  4. 配置和使用:Babel的配置相对较复杂,需要使用.babelrcbabel.config.js等文件来指定转换规则和插件。SWC的配置相对简单,可以通过命令行参数或配置文件来指定转换规则。

综上所述,Babel是一个成熟且广泛使用的工具,适用于大多数JavaScript项目,具有丰富的插件和预设。SWC则是一个性能更高的新兴工具,适用于对性能要求较高的项目,但其生态系统

更改使用 swc 解析 

 pnpm add -D swc-loader  @swc/core  @swc/cli

  1. library:这个配置项用于指定库的名称。它可以是一个字符串,也可以是一个对象。如果是一个字符串,那么这个字符串将作为全局变量暴露给浏览器环境,可以通过这个全局变量来访问库的功能。如果是一个对象,那么可以通过对象的属性来访问库的功能。

  2. libraryTarget:这个配置项用于指定库的打包方式。它可以是以下几种值之一:

    • "var":将库作为一个变量声明,可以通过变量来访问库的功能。
    • "this":将库作为 this 对象的一个属性,可以通过 this 对象来访问库的功能。
    • "window":将库作为 window 对象的一个属性,可以通过 window 对象来访问库的功能。
    • "global":将库作为 global 对象的一个属性,可以通过 global 对象来访问库的功能。
    • "commonjs":将库作为一个 CommonJS 模块导出,可以通过 require 函数来引入库的功能。
    • "commonjs2":将库作为一个 CommonJS2 模块导出,可以通过 require 函数来引入库的功能。
    • "amd":将库作为一个 AMD 模块导出,可以通过 AMD 的模块加载器来引入库的功能。
    • "umd":将库作为一个 UMD 模块导出,可以在各种环境下使用不同的模块器加载来引入库的功能。
  3. umdNamedDefine:这个配置项用于指定是否为 UMD 模块导出的库提供一个命名的模块定义。如果设置为 true,那么在 AMD 或者 CommonJS 环境下引入库时,会使用一个命名的模块定义;如果设置为 false,那么会使用匿名的模块定义。

修改webpack.config.js 

不支持 export import 使用 swc 完成

const { Configuration } = require("webpack");
const path = require("path");
/*** @type {Configuration} //配置智能提示*/
const config = {entry: "./src/index.ts", //入口文件//出口output: {//   文件名filename: "wujie.js",//   出口文件目录path: path.resolve(__dirname, "./lib"),},//配置打包忽略的文件externals: {vue: "vue",wujie: "wujie",library: "Wujie",libraryTarget: "umd",umdNamedDefine: true,},// 模式源码的方式mode: "none",module: {// 打包规则rules: [{test: /\.ts$/, //解析tsloader: "swc-loader",},],},
};module.exports = config;

 使用swc 完成 esm 模式  (export--import)

配置 esm 命令

{"name": "wujie-vue3","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","lib": "webpack","esm": " swc src/index.ts -d esm"},"keywords": [],"author": "","license": "ISC","dependencies": {"wujie": "^1.0.21"},"devDependencies": {"@swc/cli": "^0.1.63","@swc/core": "^1.3.100","swc-loader": "^0.2.3","ts-loader": "^9.5.1","typescript": "^5.3.2","vue": "^3.3.10","webpack": "^5.89.0","webpack-cli": "^5.1.4"}
}

生成 .swcrc文件

{"$schema": "https://json.schemastore.org/swcrc","jsc": {"parser": {"syntax": "typescript",},"target": "es5","loose": false,"externalHelpers": false,// Requires v1.2.50 or upper and requires target to be es2016 or upper."keepClassNames": false},"minify": false
}

执行命令 

pnpm run esm

发布到npm

更改package.json

version:发布的版本

main:配置 main 入口文件地址

module :配置import 入口地址

files:发布的文件

{"name": "wujie-vue3-setups","version": "0.0.1","description": "","main": "lib/wujie.js","module": "esm/wujie.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","lib": "webpack","esm": " swc src/index.ts -d esm"},"files": ["lib","esm","index.d.ts"],"keywords": [],"author": "","license": "ISC","dependencies": {"wujie": "^1.0.21"},"devDependencies": {"@swc/cli": "^0.1.63","@swc/core": "^1.3.100","swc-loader": "^0.2.3","ts-loader": "^9.5.1","typescript": "^5.3.2","vue": "^3.3.10","webpack": "^5.89.0","webpack-cli": "^5.1.4"}
}

创建npm账户


如果你还没有npm账户,你需要先创建一个。前往npm官方网站注册一个账户。

注意:记住你填写的用户名、邮箱、密码,等下你在本地是需要用这些信息登录的。

登录npm


在本地登录你刚刚注册的账号

如果是npm,最后还会给你的邮箱发个验证码,填上之后再回车,才算真正登录成功。

执行 npm login,输入用户名、密码以及你注册时的邮箱。

使用以下命令在终端中登录到你的npm账户:

npm login


 这将提示你输入你的npm用户名、密码和邮箱地址。

切换npm源


因为我们要发布到官方源上面,所以要确保源地址为官方地址 http://registry.npmjs.org 或 https://registry.npmjs.com,

可以通过 npm config get registry 命令查看当前 registry 源。

推荐使用nrm管理本地npm源。

全局安装 nrm:  npm install -g nrm

查看npm源:nrm ls
会把所有的源都列出来,其中带*的是当前使用的源

添加npm源:nrm add xxx http://xxxnpm.cn/
xxx 是你给这个源起的名字,后面跟上源的URL 

 

 删除源:nrm del xxx
xxx 是你给这个源起的名字

发布到npm


最后,运行以下命令来发布你的Vue 3组件到npm:

npm publish

这篇关于微前端 ---- wujie-vue3 原理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/464815

相关文章

Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案

《Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案》:本文主要介绍Vue3组件中getCurrentInstance()获取App实例,但是返回nu... 目录vue3组件中getCurrentInstajavascriptnce()获取App实例,但是返回n

Spring Boot循环依赖原理、解决方案与最佳实践(全解析)

《SpringBoot循环依赖原理、解决方案与最佳实践(全解析)》循环依赖指两个或多个Bean相互直接或间接引用,形成闭环依赖关系,:本文主要介绍SpringBoot循环依赖原理、解决方案与最... 目录一、循环依赖的本质与危害1.1 什么是循环依赖?1.2 核心危害二、Spring的三级缓存机制2.1 三

C#中async await异步关键字用法和异步的底层原理全解析

《C#中asyncawait异步关键字用法和异步的底层原理全解析》:本文主要介绍C#中asyncawait异步关键字用法和异步的底层原理全解析,本文给大家介绍的非常详细,对大家的学习或工作具有一... 目录C#异步编程一、异步编程基础二、异步方法的工作原理三、代码示例四、编译后的底层实现五、总结C#异步编程

JS+HTML实现在线图片水印添加工具

《JS+HTML实现在线图片水印添加工具》在社交媒体和内容创作日益频繁的今天,如何保护原创内容、展示品牌身份成了一个不得不面对的问题,本文将实现一个完全基于HTML+CSS构建的现代化图片水印在线工具... 目录概述功能亮点使用方法技术解析延伸思考运行效果项目源码下载总结概述在社交媒体和内容创作日益频繁的

前端CSS Grid 布局示例详解

《前端CSSGrid布局示例详解》CSSGrid是一种二维布局系统,可以同时控制行和列,相比Flex(一维布局),更适合用在整体页面布局或复杂模块结构中,:本文主要介绍前端CSSGri... 目录css Grid 布局详解(通俗易懂版)一、概述二、基础概念三、创建 Grid 容器四、定义网格行和列五、设置行

前端下载文件时如何后端返回的文件流一些常见方法

《前端下载文件时如何后端返回的文件流一些常见方法》:本文主要介绍前端下载文件时如何后端返回的文件流一些常见方法,包括使用Blob和URL.createObjectURL创建下载链接,以及处理带有C... 目录1. 使用 Blob 和 URL.createObjectURL 创建下载链接例子:使用 Blob

Vuex Actions多参数传递的解决方案

《VuexActions多参数传递的解决方案》在Vuex中,actions的设计默认只支持单个参数传递,这有时会限制我们的使用场景,下面我将详细介绍几种处理多参数传递的解决方案,从基础到高级,... 目录一、对象封装法(推荐)二、参数解构法三、柯里化函数法四、Payload 工厂函数五、TypeScript

Go 语言中的select语句详解及工作原理

《Go语言中的select语句详解及工作原理》在Go语言中,select语句是用于处理多个通道(channel)操作的一种控制结构,它类似于switch语句,本文给大家介绍Go语言中的select语... 目录Go 语言中的 select 是做什么的基本功能语法工作原理示例示例 1:监听多个通道示例 2:带

鸿蒙中@State的原理使用详解(HarmonyOS 5)

《鸿蒙中@State的原理使用详解(HarmonyOS5)》@State是HarmonyOSArkTS框架中用于管理组件状态的核心装饰器,其核心作用是实现数据驱动UI的响应式编程模式,本文给大家介绍... 目录一、@State在鸿蒙中是做什么的?二、@Spythontate的基本原理1. 依赖关系的收集2.

Vue3使用router,params传参为空问题

《Vue3使用router,params传参为空问题》:本文主要介绍Vue3使用router,params传参为空问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录vue3使用China编程router,params传参为空1.使用query方式传参2.使用 Histo