@empjs/bridge-vue2 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +200 -0
- package/dist/index.cjs +214 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +174 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# EMP Bridge Vue2
|
|
2
|
+
|
|
3
|
+
EMP Bridge Vue2 是一个用于在 React 应用中集成 Vue2 组件的桥接工具,它解决了 React 与 Vue2 之间组件共享和通信的问题。
|
|
4
|
+
|
|
5
|
+
## 功能特点
|
|
6
|
+
|
|
7
|
+
- 支持在 React 应用中使用 Vue2 组件
|
|
8
|
+
- 提供简单的 API 用于生产者和消费者之间的通信
|
|
9
|
+
- 自动处理 React 与 Vue2 之间的渲染和卸载方法差异
|
|
10
|
+
- 支持插件系统扩展 Vue2 功能
|
|
11
|
+
|
|
12
|
+
## 安装
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# 使用 npm
|
|
16
|
+
npm install @empjs/bridge-vue2
|
|
17
|
+
|
|
18
|
+
# 使用 yarn
|
|
19
|
+
yarn add @empjs/bridge-vue2
|
|
20
|
+
|
|
21
|
+
# 使用 pnpm
|
|
22
|
+
pnpm add @empjs/bridge-vue2
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 基本用法
|
|
26
|
+
|
|
27
|
+
### 生产者(Vue2 应用导出组件)
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
// 在 Vue2 应用中
|
|
31
|
+
import Vue from 'vue';
|
|
32
|
+
|
|
33
|
+
// 创建要共享的 Vue2 组件
|
|
34
|
+
const HelloVue = {
|
|
35
|
+
name: 'HelloVue',
|
|
36
|
+
props: {
|
|
37
|
+
name: {
|
|
38
|
+
type: String,
|
|
39
|
+
default: 'Vue2'
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
template: '<div>Hello from {{ name }}!</div>'
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// 导出组件
|
|
46
|
+
export default HelloVue;
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 消费者(React 应用使用 Vue2 组件)
|
|
50
|
+
|
|
51
|
+
```jsx
|
|
52
|
+
// 在 React 应用中
|
|
53
|
+
import React from 'react';
|
|
54
|
+
import { createRemoteAppComponent } from '@empjs/bridge-react';
|
|
55
|
+
import { createBridgeComponent } from '@empjs/bridge-vue2';
|
|
56
|
+
|
|
57
|
+
// 导入远程 Vue2 组件
|
|
58
|
+
import v2App from 'v2h/HelloVue';
|
|
59
|
+
|
|
60
|
+
// 获取全局 Vue 实例(通过适配器注入)
|
|
61
|
+
const { EMP_ADAPTER_VUE_v2 } = window;
|
|
62
|
+
const { Vue } = EMP_ADAPTER_VUE_v2;
|
|
63
|
+
|
|
64
|
+
// 创建 Vue2 桥接组件
|
|
65
|
+
const BridgeComponent = createBridgeComponent(v2App, { Vue });
|
|
66
|
+
|
|
67
|
+
// 创建可在 React 中使用的组件
|
|
68
|
+
export const RemoteVue2App = createRemoteAppComponent(BridgeComponent, { React });
|
|
69
|
+
|
|
70
|
+
// 在 React 应用中使用
|
|
71
|
+
function App() {
|
|
72
|
+
return (
|
|
73
|
+
<div>
|
|
74
|
+
<h1>My React App</h1>
|
|
75
|
+
<RemoteVue2App name="vue2 in React" />
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## 热更新支持
|
|
82
|
+
|
|
83
|
+
在开发环境中,您必须在 `bootstrap.ts` 添加热更新支持:
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
// 只在热更新时加载 vue-2-hmr 模块
|
|
87
|
+
if (module.hot) {
|
|
88
|
+
console.log('vue-2-hmr', module);
|
|
89
|
+
import('src/adapter/vue-2-hmr');
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
vue-2-hmr: 预载组件
|
|
94
|
+
```js
|
|
95
|
+
import 'v2h/HelloVue'
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## API 参考
|
|
99
|
+
|
|
100
|
+
### createBridgeComponent
|
|
101
|
+
|
|
102
|
+
用于生产者包装 Vue2 组件。
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
function createBridgeComponent(
|
|
106
|
+
Component: any,
|
|
107
|
+
options: {
|
|
108
|
+
Vue?: any;
|
|
109
|
+
plugin?: (vue: any) => void;
|
|
110
|
+
instanceOptions?: {
|
|
111
|
+
store?: any;
|
|
112
|
+
router?: any;
|
|
113
|
+
[key: string]: any;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
): BridgeProvider
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
参数:
|
|
120
|
+
- `Component`: 要导出的 Vue2 组件
|
|
121
|
+
- `options`: Vue2 相关配置
|
|
122
|
+
- `Vue`: Vue2 实例
|
|
123
|
+
- `plugin`: (可选) 用于扩展 Vue 功能的插件函数
|
|
124
|
+
- `instanceOptions`: (可选) 传递给 Vue 实例的选项
|
|
125
|
+
- `store`: (可选) Vuex store 实例
|
|
126
|
+
- `router`: (可选) Vue Router 实例
|
|
127
|
+
- 其他可能需要的 Vue 实例选项
|
|
128
|
+
|
|
129
|
+
plugin 内容参考
|
|
130
|
+
```js
|
|
131
|
+
import ElementUI from 'element-ui'
|
|
132
|
+
import Router from 'vue-router'
|
|
133
|
+
import Vuex from 'vuex'
|
|
134
|
+
import 'element-ui/lib/theme-chalk/index.css'
|
|
135
|
+
export default Vue => {
|
|
136
|
+
Vue.use(Router)
|
|
137
|
+
Vue.use(Vuex)
|
|
138
|
+
Vue.config.productionTip = false
|
|
139
|
+
Vue.use(ElementUI)
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
store 内容参考
|
|
144
|
+
> `countStore = ()=>{}` 是必须,避免后置请求报错
|
|
145
|
+
```js
|
|
146
|
+
import Vuex from 'vuex'
|
|
147
|
+
export const countStore = () =>
|
|
148
|
+
new Vuex.Store({
|
|
149
|
+
state: {
|
|
150
|
+
count: 0,
|
|
151
|
+
},
|
|
152
|
+
mutations: {
|
|
153
|
+
increment(state) {
|
|
154
|
+
state.count++
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
})
|
|
158
|
+
export default countStore
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### createRemoteAppComponent (来自 @empjs/bridge-react)
|
|
163
|
+
|
|
164
|
+
用于消费者加载远程组件。
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
function createRemoteAppComponent(
|
|
168
|
+
component: ComponentProvider,
|
|
169
|
+
reactOptions: {
|
|
170
|
+
React: any;
|
|
171
|
+
ReactDOM?: any;
|
|
172
|
+
createRoot?: Function;
|
|
173
|
+
},
|
|
174
|
+
options?: {
|
|
175
|
+
onError?: (error: Error) => void;
|
|
176
|
+
}
|
|
177
|
+
): React.ComponentType<any>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
参数:
|
|
181
|
+
- `component`: 组件提供者函数,通常是 `createBridgeComponent` 的返回值
|
|
182
|
+
- `reactOptions`: 当前应用的 React 相关配置
|
|
183
|
+
- `React`: React 实例
|
|
184
|
+
- `ReactDOM`: (可选) ReactDOM 实例
|
|
185
|
+
- `createRoot`: (可选) React 18+ 的 createRoot 方法
|
|
186
|
+
- `options`: (可选) 额外配置
|
|
187
|
+
- `onError`: 错误处理回调函数
|
|
188
|
+
|
|
189
|
+
## 使用场景
|
|
190
|
+
|
|
191
|
+
1. 微前端架构中 React 与 Vue2 应用的集成
|
|
192
|
+
2. 在 React 项目中复用现有的 Vue2 组件
|
|
193
|
+
3. 逐步从 Vue2 迁移到 React 的过渡阶段
|
|
194
|
+
|
|
195
|
+
## 注意事项
|
|
196
|
+
|
|
197
|
+
- 确保正确提供 Vue2 实例
|
|
198
|
+
- 组件间通信仅限于 props 传递,不支持 Vue 的 provide/inject 或 React 的 Context API 跨框架共享
|
|
199
|
+
- 在使用前需要确保 Vue2 适配器已正确加载
|
|
200
|
+
- 复杂的状态管理需要在各自框架内部处理
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
createBridgeComponent: ()=>createBridgeComponent,
|
|
28
|
+
createRemoteAppComponent: ()=>createRemoteAppComponent,
|
|
29
|
+
default: ()=>__WEBPACK_DEFAULT_EXPORT__
|
|
30
|
+
});
|
|
31
|
+
function createBridgeComponent(Component, options) {
|
|
32
|
+
const Vue = options.Vue;
|
|
33
|
+
const instanceOptions = options.instanceOptions || {};
|
|
34
|
+
return function() {
|
|
35
|
+
const instanceMap = new Map();
|
|
36
|
+
const render = (dom, props)=>{
|
|
37
|
+
if (!dom || !(dom instanceof HTMLElement)) return void console.error('[EMP-ERROR] Invalid DOM element provided to render');
|
|
38
|
+
try {
|
|
39
|
+
const existingInstance = instanceMap.get(dom);
|
|
40
|
+
if (existingInstance) {
|
|
41
|
+
if (props) try {
|
|
42
|
+
existingInstance.$options.render = (h)=>h(Component, {
|
|
43
|
+
props: props || {}
|
|
44
|
+
});
|
|
45
|
+
existingInstance.$options.propsData = props || {};
|
|
46
|
+
existingInstance.$forceUpdate();
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.warn('[EMP-WARN] Failed to update props:', error);
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
const vueContainer = document.createElement('div');
|
|
52
|
+
vueContainer.className = 'vue2-container';
|
|
53
|
+
dom.appendChild(vueContainer);
|
|
54
|
+
if (options.plugin) options.plugin(Vue);
|
|
55
|
+
const instance = new Vue({
|
|
56
|
+
propsData: props || {},
|
|
57
|
+
render: (h)=>h(Component, {
|
|
58
|
+
props: props || {}
|
|
59
|
+
}),
|
|
60
|
+
el: vueContainer,
|
|
61
|
+
beforeDestroy () {
|
|
62
|
+
if (vueContainer && vueContainer.parentNode) {
|
|
63
|
+
while(vueContainer.firstChild)vueContainer.removeChild(vueContainer.firstChild);
|
|
64
|
+
try {
|
|
65
|
+
dom.removeChild(vueContainer);
|
|
66
|
+
} catch (e) {
|
|
67
|
+
console.warn('[EMP-WARN] Failed to remove Vue container:', e);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
...instanceOptions
|
|
72
|
+
});
|
|
73
|
+
instanceMap.set(dom, instance);
|
|
74
|
+
}
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.error('[EMP-ERROR] Failed to render/update Vue component', error);
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const destroy = (dom)=>{
|
|
81
|
+
if (!dom || !(dom instanceof HTMLElement)) return void console.error('[EMP-ERROR] Invalid DOM element provided to destroy');
|
|
82
|
+
const instance = instanceMap.get(dom);
|
|
83
|
+
if (!instance) return;
|
|
84
|
+
try {
|
|
85
|
+
const vmToDestroy = instance;
|
|
86
|
+
instanceMap.delete(dom);
|
|
87
|
+
try {
|
|
88
|
+
if (dom) {
|
|
89
|
+
try {
|
|
90
|
+
if ('function' == typeof dom.replaceChildren) dom.replaceChildren();
|
|
91
|
+
} catch (replaceError) {
|
|
92
|
+
console.warn('[EMP-WARN] destroy - replaceChildren failed:', replaceError);
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
while(dom.firstChild)dom.removeChild(dom.firstChild);
|
|
96
|
+
} catch (removeError) {
|
|
97
|
+
console.warn('[EMP-WARN] destroy - removeChild failed:', removeError);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
} catch (domError) {
|
|
101
|
+
console.warn('[EMP-WARN] Error clearing DOM before destroy:', domError);
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
vmToDestroy.$destroy();
|
|
105
|
+
} catch (destroyError) {
|
|
106
|
+
console.error('[EMP-ERROR] Error during Vue instance destroy:', destroyError);
|
|
107
|
+
}
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.error('[EMP-ERROR] Failed to unmount Vue component', error);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
return {
|
|
113
|
+
render,
|
|
114
|
+
destroy
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function createRemoteAppComponent(component, vueOptions, options = {}) {
|
|
119
|
+
if (!component) throw new Error('createRemoteAppComponent: component parameter cannot be empty');
|
|
120
|
+
return {
|
|
121
|
+
name: 'Vue2RemoteAppComponent',
|
|
122
|
+
props: {
|
|
123
|
+
name: String,
|
|
124
|
+
[Symbol.toPrimitive]: Function
|
|
125
|
+
},
|
|
126
|
+
data () {
|
|
127
|
+
return {
|
|
128
|
+
provider: null,
|
|
129
|
+
providerInfo: null,
|
|
130
|
+
isMounted: false
|
|
131
|
+
};
|
|
132
|
+
},
|
|
133
|
+
methods: {
|
|
134
|
+
async loadComponent () {
|
|
135
|
+
try {
|
|
136
|
+
if ('function' == typeof component) {
|
|
137
|
+
const result = component();
|
|
138
|
+
if (result instanceof Promise) {
|
|
139
|
+
const module = await result;
|
|
140
|
+
this.providerInfo = module.default;
|
|
141
|
+
} else this.providerInfo = component;
|
|
142
|
+
}
|
|
143
|
+
if (this.isMounted && this.$el) this.renderComponent();
|
|
144
|
+
} catch (error) {
|
|
145
|
+
if (options.onError) options.onError(error);
|
|
146
|
+
console.error('[EMP-ERROR] Failed to load component', error);
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
renderComponent () {
|
|
150
|
+
if (!this.providerInfo || !this.$el) return;
|
|
151
|
+
try {
|
|
152
|
+
if (!this.provider && this.providerInfo) this.provider = this.providerInfo();
|
|
153
|
+
if (!this.provider) return void console.warn('[EMP-WARN] Provider not available yet');
|
|
154
|
+
const props = this.$props || this.$options.propsData || {};
|
|
155
|
+
if (props && 'object' == typeof props) this.provider.render(this.$el, props);
|
|
156
|
+
else this.provider.render(this.$el, {});
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.error('[EMP-ERROR] Failed to render component', error);
|
|
159
|
+
if (options.onError) options.onError(error);
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
unmountComponent () {
|
|
163
|
+
if (this.provider && this.$el) try {
|
|
164
|
+
try {
|
|
165
|
+
while(this.$el.firstChild)this.$el.removeChild(this.$el.firstChild);
|
|
166
|
+
} catch (clearError) {
|
|
167
|
+
console.error('[EMP-ERROR] unmountComponent - Error during DOM clearing:', clearError);
|
|
168
|
+
}
|
|
169
|
+
this.provider.destroy(this.$el);
|
|
170
|
+
this.provider = null;
|
|
171
|
+
} catch (error) {
|
|
172
|
+
console.error('[EMP-ERROR] Failed to unmount component', error);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
mounted () {
|
|
177
|
+
this.isMounted = true;
|
|
178
|
+
if (this.providerInfo) this.renderComponent();
|
|
179
|
+
},
|
|
180
|
+
updated () {
|
|
181
|
+
if (this.provider && this.$el) {
|
|
182
|
+
const props = this.$props || this.$options.propsData || {};
|
|
183
|
+
this.provider.render(this.$el, props);
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
beforeDestroy () {
|
|
187
|
+
this.isMounted = false;
|
|
188
|
+
this.unmountComponent();
|
|
189
|
+
},
|
|
190
|
+
created () {
|
|
191
|
+
this.loadComponent();
|
|
192
|
+
},
|
|
193
|
+
render (h) {
|
|
194
|
+
return h('div');
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
const __WEBPACK_DEFAULT_EXPORT__ = {
|
|
199
|
+
createBridgeComponent,
|
|
200
|
+
createRemoteAppComponent
|
|
201
|
+
};
|
|
202
|
+
exports.createBridgeComponent = __webpack_exports__.createBridgeComponent;
|
|
203
|
+
exports.createRemoteAppComponent = __webpack_exports__.createRemoteAppComponent;
|
|
204
|
+
exports["default"] = __webpack_exports__["default"];
|
|
205
|
+
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
206
|
+
"createBridgeComponent",
|
|
207
|
+
"createRemoteAppComponent",
|
|
208
|
+
"default"
|
|
209
|
+
].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
|
|
210
|
+
Object.defineProperty(exports, '__esModule', {
|
|
211
|
+
value: true
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["webpack://@empjs/bridge-vue2/webpack/runtime/define_property_getters","webpack://@empjs/bridge-vue2/webpack/runtime/has_own_property","webpack://@empjs/bridge-vue2/webpack/runtime/make_namespace_object","webpack://@empjs/bridge-vue2/./src/index.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","export interface BridgeProviderReturn {\n render: (dom: HTMLElement, props?: Record<string, any>) => void\n destroy: (dom: HTMLElement) => void\n}\n\nexport type BridgeProvider = () => BridgeProviderReturn\nexport type AsyncBridgeProvider = () => Promise<{default: BridgeProvider}>\nexport type ComponentProvider = BridgeProvider | AsyncBridgeProvider\n\ninterface Vue2Options {\n Vue?: any\n plugin?: (vue: any) => void\n instanceOptions?: Record<string, any>\n}\n\nexport function createBridgeComponent(Component: any, options: Vue2Options): BridgeProvider {\n const Vue = options.Vue\n const instanceOptions = options.instanceOptions || {}\n\n return function (): BridgeProviderReturn {\n const instanceMap = new Map<HTMLElement, any>()\n\n const render = (dom: HTMLElement, props?: Record<string, any>): void => {\n if (!dom || !(dom instanceof HTMLElement)) {\n console.error('[EMP-ERROR] Invalid DOM element provided to render')\n return\n }\n\n try {\n const existingInstance = instanceMap.get(dom)\n\n if (existingInstance) {\n if (props) {\n try {\n existingInstance.$options.render = (h: any) => h(Component, {props: props || {}})\n existingInstance.$options.propsData = props || {}\n existingInstance.$forceUpdate()\n } catch (error) {\n console.warn('[EMP-WARN] Failed to update props:', error)\n }\n }\n } else {\n const vueContainer = document.createElement('div')\n vueContainer.className = 'vue2-container'\n dom.appendChild(vueContainer)\n if (options.plugin) {\n options.plugin(Vue)\n }\n const instance = new Vue({\n propsData: props || {},\n render: (h: any) => h(Component, {props: props || {}}),\n el: vueContainer,\n beforeDestroy() {\n if (vueContainer && vueContainer.parentNode) {\n while (vueContainer.firstChild) {\n vueContainer.removeChild(vueContainer.firstChild)\n }\n try {\n dom.removeChild(vueContainer)\n } catch (e) {\n console.warn('[EMP-WARN] Failed to remove Vue container:', e)\n }\n }\n },\n ...instanceOptions,\n })\n\n instanceMap.set(dom, instance)\n }\n } catch (error) {\n console.error('[EMP-ERROR] Failed to render/update Vue component', error)\n throw error\n }\n }\n\n const destroy = (dom: HTMLElement): void => {\n if (!dom || !(dom instanceof HTMLElement)) {\n console.error('[EMP-ERROR] Invalid DOM element provided to destroy')\n return\n }\n\n const instance = instanceMap.get(dom)\n\n if (!instance) return\n\n try {\n const vmToDestroy = instance\n instanceMap.delete(dom)\n\n try {\n if (dom) {\n try {\n if (typeof dom.replaceChildren === 'function') {\n dom.replaceChildren()\n }\n } catch (replaceError) {\n console.warn('[EMP-WARN] destroy - replaceChildren failed:', replaceError)\n }\n\n try {\n while (dom.firstChild) {\n dom.removeChild(dom.firstChild)\n }\n } catch (removeError) {\n console.warn('[EMP-WARN] destroy - removeChild failed:', removeError)\n }\n }\n } catch (domError) {\n console.warn('[EMP-WARN] Error clearing DOM before destroy:', domError)\n }\n\n try {\n vmToDestroy.$destroy()\n } catch (destroyError) {\n console.error('[EMP-ERROR] Error during Vue instance destroy:', destroyError)\n }\n } catch (error) {\n console.error('[EMP-ERROR] Failed to unmount Vue component', error)\n }\n }\n\n return {render, destroy}\n }\n}\n\nexport function createRemoteAppComponent(\n component: ComponentProvider,\n vueOptions: Vue2Options,\n options: {onError?: (error: Error) => void} = {},\n): any {\n if (!component) {\n throw new Error('createRemoteAppComponent: component parameter cannot be empty')\n }\n\n return {\n name: 'Vue2RemoteAppComponent',\n props: {\n name: String,\n [Symbol.toPrimitive]: Function,\n },\n data() {\n return {\n provider: null,\n providerInfo: null,\n isMounted: false,\n }\n },\n methods: {\n async loadComponent() {\n try {\n if (typeof component === 'function') {\n const result = component()\n\n if (result instanceof Promise) {\n const module = await result\n this.providerInfo = module.default\n } else {\n this.providerInfo = component as BridgeProvider\n }\n }\n\n if (this.isMounted && this.$el) {\n this.renderComponent()\n }\n } catch (error) {\n if (options.onError) options.onError(error as Error)\n console.error('[EMP-ERROR] Failed to load component', error)\n }\n },\n renderComponent() {\n if (!this.providerInfo || !this.$el) return\n\n try {\n if (!this.provider && this.providerInfo) {\n this.provider = this.providerInfo()\n }\n\n if (!this.provider) {\n console.warn('[EMP-WARN] Provider not available yet')\n return\n }\n\n const props = this.$props || this.$options.propsData || {}\n\n if (props && typeof props === 'object') {\n this.provider.render(this.$el, props)\n } else {\n this.provider.render(this.$el, {})\n }\n } catch (error) {\n console.error('[EMP-ERROR] Failed to render component', error)\n if (options.onError) options.onError(error as Error)\n }\n },\n unmountComponent() {\n if (this.provider && this.$el) {\n try {\n try {\n while (this.$el.firstChild) {\n this.$el.removeChild(this.$el.firstChild)\n }\n } catch (clearError) {\n console.error('[EMP-ERROR] unmountComponent - Error during DOM clearing:', clearError)\n }\n\n this.provider.destroy(this.$el)\n this.provider = null\n } catch (error) {\n console.error('[EMP-ERROR] Failed to unmount component', error)\n }\n }\n },\n },\n mounted() {\n this.isMounted = true\n if (this.providerInfo) this.renderComponent()\n },\n updated() {\n if (this.provider && this.$el) {\n const props = this.$props || this.$options.propsData || {}\n this.provider.render(this.$el, props)\n }\n },\n beforeDestroy() {\n this.isMounted = false\n this.unmountComponent()\n },\n created() {\n this.loadComponent()\n },\n render(h: any) {\n return h('div')\n },\n }\n}\n\nexport default {\n createBridgeComponent,\n createRemoteAppComponent,\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","createBridgeComponent","Component","options","Vue","instanceOptions","instanceMap","Map","render","dom","props","HTMLElement","console","existingInstance","h","error","vueContainer","document","instance","e","destroy","vmToDestroy","replaceError","removeError","domError","destroyError","createRemoteAppComponent","component","vueOptions","Error","String","Function","result","Promise","module","clearError"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface BridgeProviderReturn {
|
|
2
|
+
render: (dom: HTMLElement, props?: Record<string, any>) => void;
|
|
3
|
+
destroy: (dom: HTMLElement) => void;
|
|
4
|
+
}
|
|
5
|
+
export type BridgeProvider = () => BridgeProviderReturn;
|
|
6
|
+
export type AsyncBridgeProvider = () => Promise<{
|
|
7
|
+
default: BridgeProvider;
|
|
8
|
+
}>;
|
|
9
|
+
export type ComponentProvider = BridgeProvider | AsyncBridgeProvider;
|
|
10
|
+
interface Vue2Options {
|
|
11
|
+
Vue?: any;
|
|
12
|
+
plugin?: (vue: any) => void;
|
|
13
|
+
instanceOptions?: Record<string, any>;
|
|
14
|
+
}
|
|
15
|
+
export declare function createBridgeComponent(Component: any, options: Vue2Options): BridgeProvider;
|
|
16
|
+
export declare function createRemoteAppComponent(component: ComponentProvider, vueOptions: Vue2Options, options?: {
|
|
17
|
+
onError?: (error: Error) => void;
|
|
18
|
+
}): any;
|
|
19
|
+
declare const _default: {
|
|
20
|
+
createBridgeComponent: typeof createBridgeComponent;
|
|
21
|
+
createRemoteAppComponent: typeof createRemoteAppComponent;
|
|
22
|
+
};
|
|
23
|
+
export default _default;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
function createBridgeComponent(Component, options) {
|
|
2
|
+
const Vue = options.Vue;
|
|
3
|
+
const instanceOptions = options.instanceOptions || {};
|
|
4
|
+
return function() {
|
|
5
|
+
const instanceMap = new Map();
|
|
6
|
+
const render = (dom, props)=>{
|
|
7
|
+
if (!dom || !(dom instanceof HTMLElement)) return void console.error('[EMP-ERROR] Invalid DOM element provided to render');
|
|
8
|
+
try {
|
|
9
|
+
const existingInstance = instanceMap.get(dom);
|
|
10
|
+
if (existingInstance) {
|
|
11
|
+
if (props) try {
|
|
12
|
+
existingInstance.$options.render = (h)=>h(Component, {
|
|
13
|
+
props: props || {}
|
|
14
|
+
});
|
|
15
|
+
existingInstance.$options.propsData = props || {};
|
|
16
|
+
existingInstance.$forceUpdate();
|
|
17
|
+
} catch (error) {
|
|
18
|
+
console.warn('[EMP-WARN] Failed to update props:', error);
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
const vueContainer = document.createElement('div');
|
|
22
|
+
vueContainer.className = 'vue2-container';
|
|
23
|
+
dom.appendChild(vueContainer);
|
|
24
|
+
if (options.plugin) options.plugin(Vue);
|
|
25
|
+
const instance = new Vue({
|
|
26
|
+
propsData: props || {},
|
|
27
|
+
render: (h)=>h(Component, {
|
|
28
|
+
props: props || {}
|
|
29
|
+
}),
|
|
30
|
+
el: vueContainer,
|
|
31
|
+
beforeDestroy () {
|
|
32
|
+
if (vueContainer && vueContainer.parentNode) {
|
|
33
|
+
while(vueContainer.firstChild)vueContainer.removeChild(vueContainer.firstChild);
|
|
34
|
+
try {
|
|
35
|
+
dom.removeChild(vueContainer);
|
|
36
|
+
} catch (e) {
|
|
37
|
+
console.warn('[EMP-WARN] Failed to remove Vue container:', e);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
...instanceOptions
|
|
42
|
+
});
|
|
43
|
+
instanceMap.set(dom, instance);
|
|
44
|
+
}
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error('[EMP-ERROR] Failed to render/update Vue component', error);
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const destroy = (dom)=>{
|
|
51
|
+
if (!dom || !(dom instanceof HTMLElement)) return void console.error('[EMP-ERROR] Invalid DOM element provided to destroy');
|
|
52
|
+
const instance = instanceMap.get(dom);
|
|
53
|
+
if (!instance) return;
|
|
54
|
+
try {
|
|
55
|
+
const vmToDestroy = instance;
|
|
56
|
+
instanceMap.delete(dom);
|
|
57
|
+
try {
|
|
58
|
+
if (dom) {
|
|
59
|
+
try {
|
|
60
|
+
if ('function' == typeof dom.replaceChildren) dom.replaceChildren();
|
|
61
|
+
} catch (replaceError) {
|
|
62
|
+
console.warn('[EMP-WARN] destroy - replaceChildren failed:', replaceError);
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
while(dom.firstChild)dom.removeChild(dom.firstChild);
|
|
66
|
+
} catch (removeError) {
|
|
67
|
+
console.warn('[EMP-WARN] destroy - removeChild failed:', removeError);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
} catch (domError) {
|
|
71
|
+
console.warn('[EMP-WARN] Error clearing DOM before destroy:', domError);
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
vmToDestroy.$destroy();
|
|
75
|
+
} catch (destroyError) {
|
|
76
|
+
console.error('[EMP-ERROR] Error during Vue instance destroy:', destroyError);
|
|
77
|
+
}
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error('[EMP-ERROR] Failed to unmount Vue component', error);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
render,
|
|
84
|
+
destroy
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function createRemoteAppComponent(component, vueOptions, options = {}) {
|
|
89
|
+
if (!component) throw new Error('createRemoteAppComponent: component parameter cannot be empty');
|
|
90
|
+
return {
|
|
91
|
+
name: 'Vue2RemoteAppComponent',
|
|
92
|
+
props: {
|
|
93
|
+
name: String,
|
|
94
|
+
[Symbol.toPrimitive]: Function
|
|
95
|
+
},
|
|
96
|
+
data () {
|
|
97
|
+
return {
|
|
98
|
+
provider: null,
|
|
99
|
+
providerInfo: null,
|
|
100
|
+
isMounted: false
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
methods: {
|
|
104
|
+
async loadComponent () {
|
|
105
|
+
try {
|
|
106
|
+
if ('function' == typeof component) {
|
|
107
|
+
const result = component();
|
|
108
|
+
if (result instanceof Promise) {
|
|
109
|
+
const module = await result;
|
|
110
|
+
this.providerInfo = module.default;
|
|
111
|
+
} else this.providerInfo = component;
|
|
112
|
+
}
|
|
113
|
+
if (this.isMounted && this.$el) this.renderComponent();
|
|
114
|
+
} catch (error) {
|
|
115
|
+
if (options.onError) options.onError(error);
|
|
116
|
+
console.error('[EMP-ERROR] Failed to load component', error);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
renderComponent () {
|
|
120
|
+
if (!this.providerInfo || !this.$el) return;
|
|
121
|
+
try {
|
|
122
|
+
if (!this.provider && this.providerInfo) this.provider = this.providerInfo();
|
|
123
|
+
if (!this.provider) return void console.warn('[EMP-WARN] Provider not available yet');
|
|
124
|
+
const props = this.$props || this.$options.propsData || {};
|
|
125
|
+
if (props && 'object' == typeof props) this.provider.render(this.$el, props);
|
|
126
|
+
else this.provider.render(this.$el, {});
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error('[EMP-ERROR] Failed to render component', error);
|
|
129
|
+
if (options.onError) options.onError(error);
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
unmountComponent () {
|
|
133
|
+
if (this.provider && this.$el) try {
|
|
134
|
+
try {
|
|
135
|
+
while(this.$el.firstChild)this.$el.removeChild(this.$el.firstChild);
|
|
136
|
+
} catch (clearError) {
|
|
137
|
+
console.error('[EMP-ERROR] unmountComponent - Error during DOM clearing:', clearError);
|
|
138
|
+
}
|
|
139
|
+
this.provider.destroy(this.$el);
|
|
140
|
+
this.provider = null;
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error('[EMP-ERROR] Failed to unmount component', error);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
mounted () {
|
|
147
|
+
this.isMounted = true;
|
|
148
|
+
if (this.providerInfo) this.renderComponent();
|
|
149
|
+
},
|
|
150
|
+
updated () {
|
|
151
|
+
if (this.provider && this.$el) {
|
|
152
|
+
const props = this.$props || this.$options.propsData || {};
|
|
153
|
+
this.provider.render(this.$el, props);
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
beforeDestroy () {
|
|
157
|
+
this.isMounted = false;
|
|
158
|
+
this.unmountComponent();
|
|
159
|
+
},
|
|
160
|
+
created () {
|
|
161
|
+
this.loadComponent();
|
|
162
|
+
},
|
|
163
|
+
render (h) {
|
|
164
|
+
return h('div');
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
const src = {
|
|
169
|
+
createBridgeComponent,
|
|
170
|
+
createRemoteAppComponent
|
|
171
|
+
};
|
|
172
|
+
export { createBridgeComponent, createRemoteAppComponent, src as default };
|
|
173
|
+
|
|
174
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["webpack://@empjs/bridge-vue2/./src/index.ts"],"sourcesContent":["export interface BridgeProviderReturn {\n render: (dom: HTMLElement, props?: Record<string, any>) => void\n destroy: (dom: HTMLElement) => void\n}\n\nexport type BridgeProvider = () => BridgeProviderReturn\nexport type AsyncBridgeProvider = () => Promise<{default: BridgeProvider}>\nexport type ComponentProvider = BridgeProvider | AsyncBridgeProvider\n\ninterface Vue2Options {\n Vue?: any\n plugin?: (vue: any) => void\n instanceOptions?: Record<string, any>\n}\n\nexport function createBridgeComponent(Component: any, options: Vue2Options): BridgeProvider {\n const Vue = options.Vue\n const instanceOptions = options.instanceOptions || {}\n\n return function (): BridgeProviderReturn {\n const instanceMap = new Map<HTMLElement, any>()\n\n const render = (dom: HTMLElement, props?: Record<string, any>): void => {\n if (!dom || !(dom instanceof HTMLElement)) {\n console.error('[EMP-ERROR] Invalid DOM element provided to render')\n return\n }\n\n try {\n const existingInstance = instanceMap.get(dom)\n\n if (existingInstance) {\n if (props) {\n try {\n existingInstance.$options.render = (h: any) => h(Component, {props: props || {}})\n existingInstance.$options.propsData = props || {}\n existingInstance.$forceUpdate()\n } catch (error) {\n console.warn('[EMP-WARN] Failed to update props:', error)\n }\n }\n } else {\n const vueContainer = document.createElement('div')\n vueContainer.className = 'vue2-container'\n dom.appendChild(vueContainer)\n if (options.plugin) {\n options.plugin(Vue)\n }\n const instance = new Vue({\n propsData: props || {},\n render: (h: any) => h(Component, {props: props || {}}),\n el: vueContainer,\n beforeDestroy() {\n if (vueContainer && vueContainer.parentNode) {\n while (vueContainer.firstChild) {\n vueContainer.removeChild(vueContainer.firstChild)\n }\n try {\n dom.removeChild(vueContainer)\n } catch (e) {\n console.warn('[EMP-WARN] Failed to remove Vue container:', e)\n }\n }\n },\n ...instanceOptions,\n })\n\n instanceMap.set(dom, instance)\n }\n } catch (error) {\n console.error('[EMP-ERROR] Failed to render/update Vue component', error)\n throw error\n }\n }\n\n const destroy = (dom: HTMLElement): void => {\n if (!dom || !(dom instanceof HTMLElement)) {\n console.error('[EMP-ERROR] Invalid DOM element provided to destroy')\n return\n }\n\n const instance = instanceMap.get(dom)\n\n if (!instance) return\n\n try {\n const vmToDestroy = instance\n instanceMap.delete(dom)\n\n try {\n if (dom) {\n try {\n if (typeof dom.replaceChildren === 'function') {\n dom.replaceChildren()\n }\n } catch (replaceError) {\n console.warn('[EMP-WARN] destroy - replaceChildren failed:', replaceError)\n }\n\n try {\n while (dom.firstChild) {\n dom.removeChild(dom.firstChild)\n }\n } catch (removeError) {\n console.warn('[EMP-WARN] destroy - removeChild failed:', removeError)\n }\n }\n } catch (domError) {\n console.warn('[EMP-WARN] Error clearing DOM before destroy:', domError)\n }\n\n try {\n vmToDestroy.$destroy()\n } catch (destroyError) {\n console.error('[EMP-ERROR] Error during Vue instance destroy:', destroyError)\n }\n } catch (error) {\n console.error('[EMP-ERROR] Failed to unmount Vue component', error)\n }\n }\n\n return {render, destroy}\n }\n}\n\nexport function createRemoteAppComponent(\n component: ComponentProvider,\n vueOptions: Vue2Options,\n options: {onError?: (error: Error) => void} = {},\n): any {\n if (!component) {\n throw new Error('createRemoteAppComponent: component parameter cannot be empty')\n }\n\n return {\n name: 'Vue2RemoteAppComponent',\n props: {\n name: String,\n [Symbol.toPrimitive]: Function,\n },\n data() {\n return {\n provider: null,\n providerInfo: null,\n isMounted: false,\n }\n },\n methods: {\n async loadComponent() {\n try {\n if (typeof component === 'function') {\n const result = component()\n\n if (result instanceof Promise) {\n const module = await result\n this.providerInfo = module.default\n } else {\n this.providerInfo = component as BridgeProvider\n }\n }\n\n if (this.isMounted && this.$el) {\n this.renderComponent()\n }\n } catch (error) {\n if (options.onError) options.onError(error as Error)\n console.error('[EMP-ERROR] Failed to load component', error)\n }\n },\n renderComponent() {\n if (!this.providerInfo || !this.$el) return\n\n try {\n if (!this.provider && this.providerInfo) {\n this.provider = this.providerInfo()\n }\n\n if (!this.provider) {\n console.warn('[EMP-WARN] Provider not available yet')\n return\n }\n\n const props = this.$props || this.$options.propsData || {}\n\n if (props && typeof props === 'object') {\n this.provider.render(this.$el, props)\n } else {\n this.provider.render(this.$el, {})\n }\n } catch (error) {\n console.error('[EMP-ERROR] Failed to render component', error)\n if (options.onError) options.onError(error as Error)\n }\n },\n unmountComponent() {\n if (this.provider && this.$el) {\n try {\n try {\n while (this.$el.firstChild) {\n this.$el.removeChild(this.$el.firstChild)\n }\n } catch (clearError) {\n console.error('[EMP-ERROR] unmountComponent - Error during DOM clearing:', clearError)\n }\n\n this.provider.destroy(this.$el)\n this.provider = null\n } catch (error) {\n console.error('[EMP-ERROR] Failed to unmount component', error)\n }\n }\n },\n },\n mounted() {\n this.isMounted = true\n if (this.providerInfo) this.renderComponent()\n },\n updated() {\n if (this.provider && this.$el) {\n const props = this.$props || this.$options.propsData || {}\n this.provider.render(this.$el, props)\n }\n },\n beforeDestroy() {\n this.isMounted = false\n this.unmountComponent()\n },\n created() {\n this.loadComponent()\n },\n render(h: any) {\n return h('div')\n },\n }\n}\n\nexport default {\n createBridgeComponent,\n createRemoteAppComponent,\n}\n"],"names":["createBridgeComponent","Component","options","Vue","instanceOptions","instanceMap","Map","render","dom","props","HTMLElement","console","existingInstance","h","error","vueContainer","document","instance","e","destroy","vmToDestroy","replaceError","removeError","domError","destroyError","createRemoteAppComponent","component","vueOptions","Error","String","Symbol","Function","result","Promise","module","clearError"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@empjs/bridge-vue2",
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"description": "Emp Bridge Vue v2",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"maintainers": [
|
|
11
|
+
"xuhongbin",
|
|
12
|
+
"ckken",
|
|
13
|
+
"doerme",
|
|
14
|
+
"ron0115"
|
|
15
|
+
],
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/empjs/emp.git",
|
|
19
|
+
"directory": "packages/bridge-vue2"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"main": "dist/index.js",
|
|
25
|
+
"types": "dist/index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"import": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"default": "./dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"require": {
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"default": "./dist/index.cjs"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=16.0.0"
|
|
40
|
+
},
|
|
41
|
+
"author": "Ken",
|
|
42
|
+
"dependencies": {},
|
|
43
|
+
"devDependencies": {},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"dev": "rslib build --watch --env-mode development",
|
|
46
|
+
"build": "rslib build"
|
|
47
|
+
}
|
|
48
|
+
}
|