wujie-vue3原理
底层使用的还是 wujie 的 startApp 方法,只不过用vue3的方式封装了一下。 通讯方式使用的是 wujie 的 bus 事件总线。发布订阅模式。
项目初始化
config
src
index.ts
type.ts
index.d.ts
package.json
tsconfig.json
webpack.config.js
package.json
json
{
"name": "@biye/wujie-vue-setup",
"version": "1.0.0",
"description": "",
"main": "lib/index.js",
"module": "esm/index.js",
"scripts": {
"build": "webpack",
"esm": "swc src/index.ts -d esm"
},
"files": [
"lib",
"esm",
"index.d.ts"
],
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"wujie": "^1.0.22"
},
"devDependencies": {
"@swc/core": "^1.6.0",
"swc-loader": "^0.2.6",
"ts-loader": "^9.5.1",
"typescript": "^5.4.5",
"vue": "^3.4.29",
"webpack": "^5.92.0",
"webpack-cli": "^5.1.4"
}
}
files 配置 上传到npm时需要上传的文件夹和文件 module 配置 esm格式的文件 main 配置 其他格式引入的文件
使用swc来编译ts文件,是传统的ts-loader编译速度的70倍,是用rust写的。
参考swc官网 https://swc.rs/
webpack配置文件
js
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'), // 输出的文件目录
library: 'Wujie', // 外部使用我们包时 需要使用的变量名
libraryTarget: 'umd', // 输出的文件格式
umdNamedDefine: true,
},
externals: { // vue 和 wujie 不要打包 排除一下
vue: 'vue',
wujie: 'wujie',
},
mode: 'none', // 源码的方式打包 不要压缩
cache: true,
module: {
rules: [
{
test: /\.ts$/, //解析ts
// loader: 'swc-loader', //使用新技术swc-loader compiled successfully in 140 ms
loader: 'ts-loader', //ts-loader 很慢 compiled successfully in 3613 ms
},
],
},
}
module.exports = config
配置 Configuration 可以让webpack配置文件有智能提示 使用的是注解的方式。 打包后的文件使用umd格式,umd打包生成的文件支持 amd cmd commonjs 和全局变量的方式,但是不支持esm。 使用 swc 编译成esm格式,参考swc官网 https://swc.rs/ 需要有个 .swcrc 配置文件
json
/* https://swc.rs/ */
{
"$schema": "https://swc.rs/schema.json",
"jsc": {
"parser": {
// "syntax": "ecmascript", // 需要改成typescript
"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
}
src/index.ts
ts
import { startApp, bus } from 'wujie'
import { h, defineComponent, onMounted, getCurrentInstance, onBeforeUnmount, watch } from 'vue'
import type { App, PropType } from 'vue'
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: Props, { emit }) {
const instance = getCurrentInstance()
const handlerEmit = (event: string, ...args: any[]) => {
emit(event, ...args)
}
const init = () => {
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,
})
}
onMounted(() => {
bus.$onAll(handlerEmit) //添加事件订阅
//初始化无界
init()
})
watch([props.name, props.url], () => {
init()
})
onBeforeUnmount(() => {
bus.$offAll(handlerEmit) //取消事件订阅
})
return () =>
h(
'div',
{
style: {
width: props.width || 200,
height: props.height || 200,
},
ref: 'wujie',
},
''
)
},
})
WuJie.install = (app: App) => {
app.component('wujie', WuJie)
}
export default WuJie
src/type.ts
ts
import type { plugin } from 'wujie'
type lifecycle = (appWindow: Window) => any
interface Props {
width?: string
height?: string
/** 唯一性用户必须保证 */
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 }
index.d.ts
ts
// 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
index.d.ts
ts
// 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