`[配置项](/zh-cn/configure)保持一致。如果产生冲突,以先执行的一方为准。
>
+> 2、如果子应用开启了shadowDOM,则预加载中的`disableScopecss`需要设置为true
diff --git a/docs/zh-cn/route.md b/docs/zh-cn/route.md
index 6b03d1cfc..05e33e9ce 100644
--- a/docs/zh-cn/route.md
+++ b/docs/zh-cn/route.md
@@ -3,7 +3,7 @@
### url属性和子应用路由的关系
答:没有关系!
-micro-app的url属性指向html的地址,它只是用来获取html,不会对子应用产生影响。
+micro-app的url属性指向html的地址,它只是用来获取html。
基座应用和子应用本质是在同一个页面渲染,所以影响到子应用路由的是浏览器地址。
@@ -13,7 +13,7 @@ micro-app的url属性指向html的地址,它只是用来获取html,不会对
基座应用会匹配`page1`并渲染对应的组件,子应用也是一样,浏览器地址会同时影响到基座应用和子应用,因为每个应用都有一套自己的路由系统,它们是可以共存的,不会冲突。
-此时我们要渲染子应用`http://www.xxx.com/`的`page1`页面,那么url属性填写的不是`http://www.xxx.com/page1/`,而是`http://www.xxx.com/`。
+此时我们要渲染子应用`http://www.xxx.com/`的`page1`页面,那么url属性填写的是`http://www.xxx.com/`,而不是`http://www.xxx.com/page1/`。
```html
// http://www.xxx.com/ 会兜底到 http://www.xxx.com/index.html
@@ -23,15 +23,27 @@ micro-app的url属性指向html的地址,它只是用来获取html,不会对
### 路由配置
-如果子应用是单页面应用,那么不需要关心路由的问题。
-
-如果是子应用多页面,需要正确配置路由,否则容易出错,以下是需要注意的点:
+路由配置非常容易出问题,下面列出了一些注意点:
+**路由类型**
- 1、基座是hash路由,子应用也必须是hash路由
- 2、基座是history路由,子应用可以是hash或history路由
-- 3、基座路由匹配的path不能使用严格匹配
-- 4、子应用根据基座路由分配的path添加路由前缀
-- 5、如果基座是history路由,子应用是hash路由,不需要设置路由前缀
+
+**路由前缀(baseurl)**
+- 1、如果基座是history路由,子应用是hash路由,不需要设置路由前缀
+- 2、vue-router在hash模式下不支持置base添加路由前缀,需要创建一个空的路由页面,将其它路由作为它的children
+
+```js
+const routes = [
+ {
+ path: window.__MICRO_APP_BASE_URL__ || '/',
+ component: Home,
+ children: [
+ // 其他的路由都写到这里
+ ],
+ },
+]
+```
**示例**
diff --git a/docs/zh-cn/start.md b/docs/zh-cn/start.md
index b56de6bca..9139c84f7 100755
--- a/docs/zh-cn/start.md
+++ b/docs/zh-cn/start.md
@@ -96,7 +96,7 @@ export function MyPage () {
### 子应用
-1、添加路由前缀
+1、添加路由前缀(如果基座应用是history路由,子应用是hash路由,不需要设置路由前缀,这一步可以省略)
diff --git a/examples/children/react16/src/router.js b/examples/children/react16/src/router.js
index 92118a6f9..840487d43 100644
--- a/examples/children/react16/src/router.js
+++ b/examples/children/react16/src/router.js
@@ -1,5 +1,5 @@
import React, { lazy, Suspense } from 'react'
-import { BrowserRouter, Switch, Route, Redirect, Link } from 'react-router-dom'
+import { BrowserRouter, Switch, Route, Redirect, Link, HashRouter } from 'react-router-dom'
import Page1 from './pages/page1/page1'
import { Menu } from 'antd';
import { MailOutlined, AppstoreOutlined } from '@ant-design/icons';
diff --git a/examples/children/vite/vite.config.js b/examples/children/vite/vite.config.js
index a2f086529..cef4d30f9 100644
--- a/examples/children/vite/vite.config.js
+++ b/examples/children/vite/vite.config.js
@@ -35,5 +35,5 @@ export default defineConfig({
outDir: 'vite',
},
clearScreen: false,
- base: `${process.env.NODE_ENV === 'production' ? 'https://cangdu.org' : ''}/micro-app/vite/`,
+ base: `${process.env.NODE_ENV === 'production' ? 'https://zeroing.jd.com' : ''}/micro-app/vite/`,
})
diff --git a/examples/children/vue2/src/main.js b/examples/children/vue2/src/main.js
index 4dd3f78b3..0e82f4239 100644
--- a/examples/children/vue2/src/main.js
+++ b/examples/children/vue2/src/main.js
@@ -11,16 +11,10 @@ import App from './App.vue'
Vue.config.productionTip = false
Vue.use(ElementUI)
-
-function getBaseName () {
- // 基座是history路由,子应用是hash路由,不需要设置路由前缀
- return '/'
-}
-
const router = new VueRouter({
- options: {
- base: getBaseName(),
- },
+ // vue-router在hash模式下不支持base,可以用一个根页面进行包裹
+ // base: window.__MICRO_APP_BASE_URL__ || '/',
+ // mode: 'history',
routes,
})
diff --git a/examples/children/vue2/src/pages/root.vue b/examples/children/vue2/src/pages/root.vue
new file mode 100644
index 000000000..6fef8edbe
--- /dev/null
+++ b/examples/children/vue2/src/pages/root.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
diff --git a/examples/children/vue2/src/router.js b/examples/children/vue2/src/router.js
index 4f4081157..d7e817114 100644
--- a/examples/children/vue2/src/router.js
+++ b/examples/children/vue2/src/router.js
@@ -1,19 +1,29 @@
import Vue from 'vue';
import VueRouter from 'vue-router';
+import Root from './pages/root.vue';
import Home from './pages/page1.vue';
Vue.use(VueRouter);
const routes = [
{
+ // 因为vue-router在hash模式下无法设置base,如果基座和子应用都是hash路由,需要创建一个空的路由页面作为根页面,用于设置路由前缀
+ // 如果基座应用是history模式则不需要使用root组件包裹
+ // path: window.__MICRO_APP_BASE_URL__ || '/',
path: '/',
- name: 'home',
- component: Home,
- },
- {
- path: '/page2',
- name: 'page2',
- component: () => import(/* webpackChunkName: "page2" */ './pages/page2.vue'),
+ component: Root,
+ children: [
+ {
+ path: '/',
+ name: 'home',
+ component: Home,
+ },
+ {
+ path: '/page2',
+ name: 'page2',
+ component: () => import(/* webpackChunkName: "page2" */ './pages/page2.vue'),
+ },
+ ],
},
];
diff --git a/examples/children/vue3/src/router.js b/examples/children/vue3/src/router.js
index c46844ca4..fda3c7152 100644
--- a/examples/children/vue3/src/router.js
+++ b/examples/children/vue3/src/router.js
@@ -1,4 +1,4 @@
-import { createRouter, createWebHistory } from 'vue-router'
+import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import Home from './pages/page1.vue';
const routes = createRouter({
diff --git a/examples/main-vue2/src/pages/vue2.vue b/examples/main-vue2/src/pages/vue2.vue
index 2e7ff08b9..9c442dea1 100644
--- a/examples/main-vue2/src/pages/vue2.vue
+++ b/examples/main-vue2/src/pages/vue2.vue
@@ -2,12 +2,12 @@
发送数据
-
-
+ name='vue2'
+ url='http://localhost:4001/micro-app/vue2'
+ :data='data'
+ >
+
+
diff --git a/src/constants.ts b/src/constants.ts
index 7b283d456..d71014fc6 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -3,7 +3,7 @@ export enum ObservedAttrName {
URL = 'url',
}
-// 应用状态
+// app status
export enum appStatus {
NOT_LOADED = 'NOT_LOADED',
LOADING_SOURCE_CODE = 'LOADING_SOURCE_CODE',
@@ -14,7 +14,7 @@ export enum appStatus {
UNMOUNT = 'UNMOUNT',
}
-// 生命周期
+// lifecycles
export enum lifeCycles {
CREATED = 'created',
BEFOREMOUNT = 'beforemount',
diff --git a/src/create_app.ts b/src/create_app.ts
index e78068eac..eab49cfe6 100644
--- a/src/create_app.ts
+++ b/src/create_app.ts
@@ -12,10 +12,10 @@ import SandBox from './sandbox'
import { defer } from './libs/utils'
import dispatchLifecyclesEvent, { dispatchUnmountToMicroApp } from './interact/lifecycles_event'
-// 微应用实例
+// micro app instances
export const appInstanceMap = new Map()
-// CreateApp构造函数入参
+// params of CreateApp
export interface CreateAppParam {
name: string
url: string
@@ -29,7 +29,7 @@ export interface CreateAppParam {
export default class CreateApp implements AppInterface {
private status: string = appStatus.NOT_LOADED
- private loadSourceLevel: -1|0|1|2 = 0 // level为2,资源加载完成
+ private loadSourceLevel: -1|0|1|2 = 0
isPrefetch = false
name: string
url: string
@@ -46,7 +46,7 @@ export default class CreateApp implements AppInterface {
this.container = container ?? null
this.inline = inline ?? false
this.baseurl = baseurl ?? ''
- // 初始化时非必传👆
+ // optional during init👆
this.name = name
this.url = url
this.useSandbox = useSandbox
@@ -62,14 +62,14 @@ export default class CreateApp implements AppInterface {
}
}
- // 加载资源
+ // Load resources
loadSourceCode (): void {
this.status = appStatus.LOADING_SOURCE_CODE
extractHtml(this)
}
/**
- * 资源加载完成,非预加载和卸载时执行mount操作
+ * When resource is loaded, mount app if it is not prefetch or unmount
*/
onLoad (html: HTMLElement): void {
if (++this.loadSourceLevel === 2) {
@@ -84,7 +84,7 @@ export default class CreateApp implements AppInterface {
}
/**
- * 加载html资源出错
+ * Error loading HTML
* @param e Error
*/
onLoadError (e: Error): void {
@@ -96,10 +96,10 @@ export default class CreateApp implements AppInterface {
}
/**
- * 初始化资源完成后进行渲染
- * @param container 容器
- * @param inline 是否使用内联模式
- * @param baseurl 路由前缀,每个应用的前缀都是不同的,兜底为空字符串
+ * mount app
+ * @param container app container
+ * @param inline js runs in inline mode
+ * @param baseurl route prefix, default is ''
*/
mount (
container?: HTMLElement | ShadowRoot,
@@ -155,8 +155,8 @@ export default class CreateApp implements AppInterface {
}
/**
- * 应用卸载
- * @param destory 是否完全销毁,删除缓存资源
+ * unmount app
+ * @param destory completely destroyed, delete cache resources
*/
unmount (destory: boolean): void {
if (this.status === appStatus.LOAD_SOURCE_ERROR) {
@@ -168,7 +168,7 @@ export default class CreateApp implements AppInterface {
this.name,
lifeCycles.UNMOUNT,
)
- // 向微应用发送卸载事件,在沙盒清空之前&声明周期执行之后触发
+ // Send an unmount event to the micro application, which is triggered before the sandbox is cleared & after the unmount lifecycle is executed
dispatchUnmountToMicroApp(this.name)
this.sandBox?.stop()
this.container = null
@@ -178,7 +178,7 @@ export default class CreateApp implements AppInterface {
}
/**
- * 阻断应用正常渲染的错误钩子
+ * app rendering error
* @param e Error
*/
onerror (e: Error): void {
@@ -190,7 +190,7 @@ export default class CreateApp implements AppInterface {
)
}
- // 获取应用状态
+ // get app status
getAppStatus (): string {
return this.status
}
diff --git a/src/interact/event_center.ts b/src/interact/event_center.ts
index 16baf49c1..f95ea3114 100755
--- a/src/interact/event_center.ts
+++ b/src/interact/event_center.ts
@@ -8,7 +8,7 @@ type eventInfo = {
export default class EventCenter {
eventList = new Map()
- // 判断名称是否正确
+ // whether the name is legal
isLegalName (name: string): boolean {
if (!name) {
console.error(
@@ -21,10 +21,10 @@ export default class EventCenter {
}
/**
- * 绑定监听函数
- * @param name 事件名称
- * @param f 绑定函数
- * @param autoTrigger 在初次绑定监听函数时有缓存数据,是否需要主动触发一次,默认为false
+ * add listener
+ * @param name event name
+ * @param f listener
+ * @param autoTrigger If there is cached data when first bind listener, whether it needs to trigger, default is false
*/
on (name: string, f: CallableFunction, autoTrigger = false): void {
if (this.isLegalName(name)) {
@@ -42,7 +42,7 @@ export default class EventCenter {
}
this.eventList.set(name, eventInfo)
} else if (autoTrigger && Object.getOwnPropertyNames(eventInfo.data).length) {
- // 如果数据池中有数据,绑定时主动触发一次
+ // auto trigger when data not null
f(eventInfo.data)
}
@@ -50,7 +50,7 @@ export default class EventCenter {
}
}
- // 解除绑定,但数据不清空
+ // remove listener, but the data is not cleared
off (name: string, f?: CallableFunction): void {
if (this.isLegalName(name)) {
const eventInfo = this.eventList.get(name)
@@ -64,7 +64,7 @@ export default class EventCenter {
}
}
- // 发送数据
+ // dispatch data
dispatch (name: string, data: Record): void {
if (this.isLegalName(name)) {
if (toString.call(data) !== '[object Object]') {
@@ -74,7 +74,7 @@ export default class EventCenter {
}
let eventInfo = this.eventList.get(name)
if (eventInfo) {
- // 当数据不相等时才更新
+ // Update when the data is not equal
if (eventInfo.data !== data) {
eventInfo.data = data
for (const f of eventInfo.callbacks) {
@@ -91,7 +91,7 @@ export default class EventCenter {
}
}
- // 获取数据
+ // get data
getData (name: string): Record | null {
const eventInfo = this.eventList.get(name)
return eventInfo?.data ?? null
diff --git a/src/interact/index.ts b/src/interact/index.ts
index b1a7b37a1..d786fec27 100644
--- a/src/interact/index.ts
+++ b/src/interact/index.ts
@@ -5,29 +5,29 @@ import { removeDomScope } from '../libs/utils'
const eventCenter = new EventCenter()
/**
- * 格式化事件名称
- * @param appName 应用名称
- * @param fromBaseApp 是否从基座应用发送数据
+ * Format event name
+ * @param appName app.name
+ * @param fromBaseApp is from base app
*/
function formatEventName (appName: string, fromBaseApp: boolean): string {
if (typeof appName !== 'string' || !appName) return ''
return fromBaseApp ? `__from_base_app_${appName}__` : `__from_micro_app_${appName}__`
}
-// 全局数据通信
+// Global data
class EventCenterForGlobal {
/**
- * 添加全局数据监听
- * @param cb 绑定函数
- * @param autoTrigger 在初次绑定监听函数时有缓存数据,是否需要主动触发一次,默认为false
+ * add listener of global data
+ * @param cb listener
+ * @param autoTrigger If there is cached data when first bind listener, whether it needs to trigger, default is false
*/
addGlobalDataListener (cb: CallableFunction, autoTrigger?: boolean): void {
eventCenter.on('global', cb, autoTrigger)
}
/**
- * 解除全局数据监听函数
- * @param cb 绑定函数
+ * remove listener of global data
+ * @param cb listener
*/
removeGlobalDataListener (cb: CallableFunction): void {
if (typeof cb === 'function') {
@@ -36,37 +36,37 @@ class EventCenterForGlobal {
}
/**
- * 发送数据
- * @param data 对象数据
+ * dispatch global data
+ * @param data data
*/
setGlobalData (data: Record): void {
eventCenter.dispatch('global', data)
}
/**
- * 清空所有全局数据绑定函数
+ * clear all listener of global data
*/
clearGlobalDataListener (): void {
eventCenter.off('global')
}
}
-// 基座应用的数据通信方法集合
+// Event center for base app
export class EventCenterForBaseApp extends EventCenterForGlobal {
/**
- * 添加数据监听
- * @param appName 子应用名称
- * @param cb 绑定函数
- * @param autoTrigger 在初次绑定监听函数时有缓存数据,是否需要主动触发一次,默认为false
+ * add listener
+ * @param appName app.name
+ * @param cb listener
+ * @param autoTrigger If there is cached data when first bind listener, whether it needs to trigger, default is false
*/
addDataListener (appName: string, cb: CallableFunction, autoTrigger?: boolean): void {
eventCenter.on(formatEventName(appName, false), cb, autoTrigger)
}
/**
- * 解除监听函数
- * @param appName 子应用名称
- * @param cb 绑定函数
+ * remove listener
+ * @param appName app.name
+ * @param cb listener
*/
removeDataListener (appName: string, cb: CallableFunction): void {
if (typeof cb === 'function') {
@@ -75,33 +75,33 @@ export class EventCenterForBaseApp extends EventCenterForGlobal {
}
/**
- * 主动获取子应用或基座传递的数据
- * @param appName 子应用名称
- * @param fromBaseApp 是否获取基座应用发送给子应用的数据,默认false
+ * get data from micro app or base app
+ * @param appName app.name
+ * @param fromBaseApp whether get data from base app, default is false
*/
getData (appName: string, fromBaseApp = false): Record | null {
return eventCenter.getData(formatEventName(appName, fromBaseApp))
}
/**
- * 向指定子应用发送数据
- * @param appName 子应用名称
- * @param data 对象数据
+ * Dispatch data to the specified micro app
+ * @param appName app.name
+ * @param data data
*/
setData (appName: string, data: Record): void {
eventCenter.dispatch(formatEventName(appName, true), data)
}
/**
- * 清空某个应用的监听函数
- * @param appName 子应用名称
+ * clear all listener for specified micro app
+ * @param appName app.name
*/
clearDataListener (appName: string): void {
eventCenter.off(formatEventName(appName, false))
}
}
-// 子应用的数据通信方法集合
+// Event center for micro app
export class EventCenterForMicroApp extends EventCenterForGlobal {
appName: string
constructor (appName: string) {
@@ -110,17 +110,17 @@ export class EventCenterForMicroApp extends EventCenterForGlobal {
}
/**
- * 监听基座应用发送的数据
- * @param cb 绑定函数
- * @param autoTrigger 在初次绑定监听函数时有缓存数据,是否需要主动触发一次,默认为false
+ * add listener, monitor the data sent by the base app
+ * @param cb listener
+ * @param autoTrigger If there is cached data when first bind listener, whether it needs to trigger, default is false
*/
addDataListener (cb: CallableFunction, autoTrigger?: boolean): void {
eventCenter.on(formatEventName(this.appName, true), cb, autoTrigger)
}
/**
- * 解除监听函数
- * @param cb 绑定函数
+ * remove listener
+ * @param cb listener
*/
removeDataListener (cb: CallableFunction): void {
if (typeof cb === 'function') {
@@ -129,15 +129,15 @@ export class EventCenterForMicroApp extends EventCenterForGlobal {
}
/**
- * 主动获取来自基座的数据
+ * get data from base app
*/
getData (): Record | null {
return eventCenter.getData(formatEventName(this.appName, true))
}
/**
- * 向基座应用发送数据
- * @param data 对象数据
+ * dispatch data to base app
+ * @param data data
*/
dispatch (data: Record): void {
removeDomScope()
@@ -161,7 +161,7 @@ export class EventCenterForMicroApp extends EventCenterForGlobal {
}
/**
- * 清空当前子应用绑定的所有监听函数
+ * clear all listeners
*/
clearDataListener (): void {
eventCenter.off(formatEventName(this.appName, true))
diff --git a/src/interact/lifecycles_event.ts b/src/interact/lifecycles_event.ts
index 4af01b82b..0811b098b 100644
--- a/src/interact/lifecycles_event.ts
+++ b/src/interact/lifecycles_event.ts
@@ -17,11 +17,11 @@ function eventHandler (event: CustomEvent, element: HTMLElement): void {
}
/**
- * 发送生命周期事件
- * @param element 容器元素
- * @param appName 应用名称
- * @param lifecycleName 生命周期名称
- * @param error 错误钩子的参数
+ * dispatch lifeCycles event
+ * @param element container
+ * @param appName app.name
+ * @param lifecycleName lifeCycle name
+ * @param error param from error hook
*/
export default function dispatchLifecyclesEvent (
element: HTMLElement,
@@ -49,7 +49,7 @@ export default function dispatchLifecyclesEvent (
})
eventHandler(event, element)
- // 全局钩子
+ // global hooks
// @ts-ignore
if (typeof microApp.lifeCycles?.[lifecycleName] === 'function') {
// @ts-ignore
@@ -60,8 +60,8 @@ export default function dispatchLifecyclesEvent (
}
/**
- * 向微应用发送卸载事件
- * @param appName 应用名称
+ * Dispatch unmount event to micro app
+ * @param appName app.name
*/
export function dispatchUnmountToMicroApp (appName: string): void {
const event = new CustomEvent(`unmount-${appName}`)
diff --git a/src/libs/additional.ts b/src/libs/additional.ts
index e9de1c585..d92367b8a 100644
--- a/src/libs/additional.ts
+++ b/src/libs/additional.ts
@@ -14,14 +14,14 @@ function unmountAppInline (): void {
appInstanceMap.clear()
}
-// 循环内嵌时子应用卸载后辈应用
+// if micro-app run in micro application, delete all next generation application when unmount event received
export function listenUmountAppInline (): void {
if (window.__MICRO_APP_ENVIRONMENT__) {
window.addEventListener('unmount', unmountAppInline, false)
}
}
-// 解除监听
+// release listener
export function replaseUnmountAppInline (): void {
if (window.__MICRO_APP_ENVIRONMENT__) {
window.removeEventListener('unmount', unmountAppInline, false)
diff --git a/src/libs/utils.ts b/src/libs/utils.ts
index e826b0a7f..ea04dc15b 100644
--- a/src/libs/utils.ts
+++ b/src/libs/utils.ts
@@ -27,8 +27,8 @@ export const rawDocument = new Function('return document')()
export const version = '__VERSION__'
/**
- * 格式化log信息
- * @param msg log信息
+ * Format log msg
+ * @param msg log msg
*/
export function formatLogMessage (msg: string): string {
if (typeof msg === 'string') {
@@ -39,32 +39,32 @@ export function formatLogMessage (msg: string): string {
}
/**
- * 延迟执行
- * @param fn 回调函数
- * @param args 入参
+ * async execution
+ * @param fn callback
+ * @param args params
*/
export function defer (fn: Func, ...args: any[]): void {
Promise.resolve().then(fn.bind(null, ...args))
}
/**
- * 添加地址协议
- * @param url 地址
+ * Add address protocol
+ * @param url address
*/
export function addProtocol (url: string): string {
return url.startsWith('//') ? `${location.protocol}${url}` : url
}
/**
- * 格式化URL地址
- * @param url 地址
+ * Format URL address
+ * @param url address
*/
export function formatURL (url: string | null): string {
if (typeof url !== 'string' || !url) return ''
try {
const { origin, pathname } = new URL(addProtocol(url))
- // 如果以.html结尾,则不需要补全 /
+ // If it ends with .html, don’t need to add /
if (/\.html$/.test(pathname)) {
return `${origin}${pathname}`
}
@@ -77,7 +77,7 @@ export function formatURL (url: string | null): string {
}
/**
- * 获取的地址的有效域名,如 https://xxx/xx/xx.html 格式化为 https://xxx/xx/
+ * Get valid address, such as https://xxx/xx/xx.html to https://xxx/xx/
* @param url app.url
*/
export function getEffectivePath (url: string): string {
@@ -91,9 +91,9 @@ export function getEffectivePath (url: string): string {
}
/**
- * 补全静态资源相对地址
- * @param path 静态资源地址
- * @param baseURI 基础地址 -- app.url
+ * Complete address
+ * @param path address
+ * @param baseURI base url(app.url)
*/
export function CompletionPath (path: string, baseURI: string): string {
if (/^((((ht|f)tps?)|file):)?\/\//.test(path)) return path
@@ -104,8 +104,9 @@ export function CompletionPath (path: string, baseURI: string): string {
}
/**
- * 获取link资源所在文件夹,用于补全css中的相对地址
- * @param linkpath link地址
+ * Get the folder where the link resource is located,
+ * which is used to complete the relative address in the css
+ * @param linkpath full link address
*/
export function getLinkFileDir (linkpath: string): string {
const pathArr = linkpath.split('/')
@@ -114,11 +115,11 @@ export function getLinkFileDir (linkpath: string): string {
}
/**
- * promise流
- * @param promiseList promise数组,必传
- * @param successsCb 成功回调,必传
- * @param errorCb 失败回调,必传
- * @param finallyCb 结束回调,必传
+ * promise stream
+ * @param promiseList promise list
+ * @param successsCb success callback
+ * @param errorCb failed callback
+ * @param finallyCb finally callback
*/
export function promiseStream (
promiseList: Array | T>,
@@ -157,18 +158,18 @@ export function promiseStream (
})
}
-// 检测浏览器是否支持module script
+// Check whether the browser supports module script
export function isSupportModuleScript (): boolean {
const s = document.createElement('script')
return 'noModule' in s
}
-// 创建随机symbol字符串
+// Create a random symbol string
export function createNonceStr (): string {
return Math.random().toString(36).substr(2, 15)
}
-// 数组去重
+// Array deduplication
export function unique (array: any[]): any[] {
return array.filter(function (this: Record, item) {
return item in this ? false : (this[item] = true)
@@ -190,35 +191,35 @@ export const requestIdleCallback = window.requestIdleCallback ||
}
/**
- * 记录当前正在运行的appName
+ * Record the currently running app.name
*/
let currentMicroAppName: string | null = null
export function setCurrentAppName (appName: string | null): void {
currentMicroAppName = appName
}
-// 获取当前运行的应用名称
+// get the currently running app.name
export function getCurrentAppName (): string | null {
return currentMicroAppName
}
-// 清除appName绑定
+// Clear appName
export function removeDomScope (): void {
setCurrentAppName(null)
}
-// 是否是safari浏览器
+// is safari browser
export function isSafari (): boolean {
return /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent)
}
-// 是否是函数类型
+// is function
export function isFunction (target: unknown): boolean {
return typeof target === 'function'
}
/**
- * 创建纯净的无绑定的元素
+ * Create pure elements
*/
export function pureCreateElement (tagName: K, options?: ElementCreationOptions): HTMLElementTagNameMap[K] {
const element = rawDocument.createElement(tagName, options)
diff --git a/src/micro_app_element.ts b/src/micro_app_element.ts
index 33e8c7661..f8e59d876 100644
--- a/src/micro_app_element.ts
+++ b/src/micro_app_element.ts
@@ -23,14 +23,14 @@ export default class MicroAppElement extends HTMLElement implements MicroAppElem
isWating = false
cacheData: Record | null = null
- // 👇可配置项
- // shadowDom 开启shadowDOM,默认为false
- // destory 卸载时是否强制删除缓存资源,默认为false
- // inline js以内联script方式运行,默认为false
- // disableScopecss 禁用css隔离,默认为false
- // disableSandbox 停用js沙盒,默认为false
- // macro 用于解决vue3的异步渲染问题,和预加载的入参保持一致,默认为false
- // baseUrl 路由前缀,默认为 ''
+ // 👇Configuration
+ // shadowDom: use shadowDOM, default is false
+ // destory: whether delete cache resources when unmount, default is false
+ // inline: whether js runs in inline script mode, default is false
+ // disableScopecss: whether disable css scoped, default is false
+ // disableSandbox: whether disable sandbox, default is false
+ // macro: used to solve the async render problem of vue3, default is false
+ // baseUrl: route prefix, default is ''
connectedCallback (): void {
if (++MicroAppElement.microAppCount === 1) {
@@ -108,8 +108,7 @@ export default class MicroAppElement extends HTMLElement implements MicroAppElem
}
/**
- * 处理初始化后name或url发生变化
- * 只要name或url发生变化,则将旧应用完全卸载,并渲染新的应用
+ * handle for change of name an url after element inited
*/
handleAttributeUpdate = (): void => {
this.isWating = false
@@ -118,7 +117,7 @@ export default class MicroAppElement extends HTMLElement implements MicroAppElem
if (this.legalAttribute('name', attrName) && this.legalAttribute('url', attrUrl)) {
const existApp = appInstanceMap.get(attrName!)
if (attrName !== this.name && existApp) {
- // 处理已缓存的非预加载app
+ // handling of cached and non-prefetch apps
if (existApp.getAppStatus() !== appStatus.UNMOUNT && !existApp.isPrefetch) {
this.setAttribute('name', this.name)
return console.error(
@@ -133,12 +132,12 @@ export default class MicroAppElement extends HTMLElement implements MicroAppElem
this.url = attrUrl
;(this.shadowRoot ?? this).innerHTML = ''
/**
- * existApp存在
- * 如果attrName和this.name相等,则existApp已经被卸载
- * 如果attrName和this.name不相等,则existApp为预加载或已卸载
+ * when existApp not undefined
+ * if attrName and this.name are equal, existApp has been unmounted
+ * if attrName and this.name are not equal, existApp is prefetch or unmounted
*/
if (existApp && existApp.url === attrUrl) {
- // app直接挂载
+ // mount app
this.handleAppMount(existApp)
} else {
this.handleCreate()
@@ -150,9 +149,9 @@ export default class MicroAppElement extends HTMLElement implements MicroAppElem
}
/**
- * 判断元素属性是否符合条件
- * @param name 属性名称
- * @param val 属性值
+ * judge the attribute is correct
+ * @param name attribute name
+ * @param val attribute value
*/
legalAttribute (name: string, val: AttrType): boolean {
if (typeof val !== 'string' || !val) {
@@ -166,7 +165,7 @@ export default class MicroAppElement extends HTMLElement implements MicroAppElem
return true
}
- // 挂载应用
+ // mount app
handleAppMount (app: AppInterface): void {
app.isPrefetch = false
defer(() => app.mount(
@@ -176,7 +175,7 @@ export default class MicroAppElement extends HTMLElement implements MicroAppElem
))
}
- // 创建应用
+ // create app instance
handleCreate (): void {
const instance: AppInterface = new CreateApp({
name: this.name!,
@@ -193,8 +192,8 @@ export default class MicroAppElement extends HTMLElement implements MicroAppElem
}
/**
- * 卸载应用
- * @param destory 是否完全销毁
+ * unmount app
+ * @param destory delete cache resources when unmount
*/
handleUnmount (destory: boolean): void {
const app = appInstanceMap.get(this.name!)
@@ -202,9 +201,9 @@ export default class MicroAppElement extends HTMLElement implements MicroAppElem
}
/**
- * 获取配置结果
- * 全局的优先级最低
- * @param name 名称
+ * Get configuration results
+ * Global setting is lowest priority
+ * @param name Configuration item name
*/
getDisposeResult (name: string): boolean {
// @ts-ignore
@@ -212,7 +211,7 @@ export default class MicroAppElement extends HTMLElement implements MicroAppElem
}
/**
- * 基座应用传入的数据
+ * Data from the base application
*/
set data (value: Record | null) {
if (this.name) {
@@ -223,7 +222,7 @@ export default class MicroAppElement extends HTMLElement implements MicroAppElem
}
/**
- * data取值只在jsx-custom-event中使用一次
+ * get data only used in jsx-custom-event once
*/
get data (): Record | null {
if (this.name) {
@@ -236,8 +235,8 @@ export default class MicroAppElement extends HTMLElement implements MicroAppElem
}
/**
- * 定义元素
- * @param tagName 元素名称
+ * define element
+ * @param tagName element name
*/
export function defineElement (tagName: string): boolean {
if (window.customElements.get(tagName)) {
diff --git a/src/polyfill/jsx-custom-event.ts b/src/polyfill/jsx-custom-event.ts
index e488b7535..d004d8c8a 100644
--- a/src/polyfill/jsx-custom-event.ts
+++ b/src/polyfill/jsx-custom-event.ts
@@ -3,7 +3,7 @@ import React from 'react'
type MicroElementType = HTMLElement & Record
-// 生命周期事件
+// lifecycles
const eventLifeCycles = ['oncreated', 'onbeforemount', 'onmounted', 'onunmount', 'onerror', 'ondatachange']
export default function jsxCustomEvent (
@@ -14,7 +14,7 @@ export default function jsxCustomEvent (
const newProps = Object.assign({}, props)
if (/^micro-app(-\S+)?/.test(type as string) && props) {
- // 初始化和卸载、更新时都会执行
+ // ref will call when create, update, unmount
newProps.ref = (element: MicroElementType | null) => {
if (typeof props.ref === 'function') {
props.ref(element)
@@ -22,9 +22,9 @@ export default function jsxCustomEvent (
(props.ref as any).current = element
}
- // 卸载和更新时,element为null
+ // when unmount and update the element is null
if (element) {
- // 前后数据不同时才更新数据,保持和其它框架(如vue)一致
+ // Update data when the prev and next data are different
if (toString.call(props.data) === '[object Object]' && element.data !== props.data) {
element.data = props.data
}
diff --git a/src/prefetch.ts b/src/prefetch.ts
index d50590135..9d9c4cd0f 100644
--- a/src/prefetch.ts
+++ b/src/prefetch.ts
@@ -24,22 +24,20 @@ function filterPreFetchTarget (apps: T[]): T[] {
}
/**
- * 预加载
* preFetch([
* {
* name: string,
* url: string,
- * disableScopecss: boolean,
- * disableSandbox: boolean,
- * macro: boolean,
- * shadowDOM: boolean,
+ * disableScopecss?: boolean,
+ * disableSandbox?: boolean,
+ * macro?: boolean,
* },
* ...
* ])
- * 注意:
- * 1、预加载是异步的,在浏览器空闲时才会执行
- * 2、预加载的 disableScopecss、disableSandbox、macro、shadowDOM 和micro-app组件要保持一致,如果冲突,谁先执行则以谁为准
- * @param apps 应用列表
+ * Note:
+ * 1: preFetch is asynchronous and is performed only when the browser is idle
+ * 2: disableScopecss, disableSandbox, macro must be same with micro-app element, if conflict, the one who executes first shall prevail
+ * @param apps micro apps
*/
export default function preFetch (apps: prefetchParamList): void {
requestIdleCallback(() => {
@@ -49,10 +47,7 @@ export default function preFetch (apps: prefetchParamList): void {
const app = new CreateApp({
name: item.name,
url: item.url,
- scopecss: !(
- (item.disableScopecss ?? microApp.disableScopecss) ||
- (item.shadowDOM ?? microApp.shadowDOM)
- ),
+ scopecss: !(item.disableScopecss ?? microApp.disableScopecss),
useSandbox: !(item.disableSandbox ?? microApp.disableSandbox),
macro: item.macro ?? microApp.macro,
})
diff --git a/src/sandbox/effect.ts b/src/sandbox/effect.ts
index 131c641e1..a5e8eb429 100644
--- a/src/sandbox/effect.ts
+++ b/src/sandbox/effect.ts
@@ -1,6 +1,7 @@
import type { microWindowType } from '@micro-app/types'
import { getCurrentAppName, formatLogMessage } from '../libs/utils'
+// save raw methods
const rawWindowAddEventListener = window.addEventListener
const rawWindowRemoveEventListener = window.removeEventListener
const rawSetInterval = window.setInterval
@@ -11,11 +12,11 @@ const rawClearTimeout = window.clearTimeout
const rawDocumentAddEventListener = document.addEventListener
const rawDocumentRemoveEventListener = document.removeEventListener
-// document.onclick绑定列表,每个应用的绑定函数是唯一的
+// document.onclick binding list, the binding function of each application is unique
const documentClickListMap = new Map()
let hasRewriteDocumentOnClick = false
/**
- * 重写document.onclick,只执行一次
+ * Rewrite document.onclick and execute it only once
*/
function overwriteDocumentOnClick (): void {
hasRewriteDocumentOnClick = true
@@ -63,7 +64,7 @@ function overwriteDocumentOnClick (): void {
}
/**
- * document 的事件是全局共享的,在子应用卸载时我们需要清空这些副作用事件绑定
+ * The document event is globally, we need to clear these event bindings when micro application unmounted
*/
const documentEventListenerMap = new Map>>()
export function effectDocumentEvent (): void {
@@ -111,17 +112,16 @@ export function effectDocumentEvent (): void {
}
}
-// 清空document事件代理
+// Clear the document event agent
export function releaseEffectDocumentEvent (): void {
document.addEventListener = rawDocumentAddEventListener
document.removeEventListener = rawDocumentRemoveEventListener
}
/**
- * 格式化特定事件名称
- * @param type 事件名称
- * @param microWindow 原型对象
- * @returns string
+ * Format event name
+ * @param type event name
+ * @param microWindow micro window
*/
function formatEventType (type: string, microWindow: microWindowType): string {
if (type === 'unmount') {
@@ -131,8 +131,8 @@ function formatEventType (type: string, microWindow: microWindowType): string {
}
/**
- * 注册和监听副作用事件
- * @param microWindow 原型对象
+ * Rewrite side-effect events
+ * @param microWindow micro window
*/
export default function effect (microWindow: microWindowType): CallableFunction {
const eventListenerMap = new Map>()
@@ -198,7 +198,7 @@ export default function effect (microWindow: microWindowType): CallableFunction
}
return () => {
- // 清空window绑定事件
+ // Clear window binding events
if (eventListenerMap.size) {
eventListenerMap.forEach((listenerList, type) => {
if (listenerList.size) {
@@ -210,7 +210,7 @@ export default function effect (microWindow: microWindowType): CallableFunction
eventListenerMap.clear()
}
- // 清空定时器
+ // Clear timers
if (intervalIdList.size) {
intervalIdList.forEach((intervalId: number) => {
rawClearInterval(intervalId)
@@ -227,10 +227,10 @@ export default function effect (microWindow: microWindowType): CallableFunction
const appName = microWindow.__MICRO_APP_NAME__
- // 清空当前子应用通过document.onclick绑定的函数
+ // Clear the function bound by micro application through document.onclick
documentClickListMap.delete(appName)
- // 清空document绑定事件
+ // Clear document binding event
const documentAppListenersMap = documentEventListenerMap.get(appName)
if (documentAppListenersMap) {
documentAppListenersMap.forEach((listenerList, type) => {
diff --git a/src/sandbox/index.ts b/src/sandbox/index.ts
index 2a01c17a6..aae834423 100644
--- a/src/sandbox/index.ts
+++ b/src/sandbox/index.ts
@@ -23,14 +23,14 @@ type injectDataType = {
rawDocument: Document
}
-// 可以逃逸到外层window的变量
+// Variables that can escape to rawWindow
const staticEscapeProperties: PropertyKey[] = [
'System',
'__cjsWrapper',
'__REACT_ERROR_OVERLAY_GLOBAL_HOOK__',
]
-// 一些只能赋值到原window上的变量
+// Variables that can only assigned to rawWindow
const escapeSetterKeyList: PropertyKey[] = [
'location',
]
@@ -49,7 +49,7 @@ const unscopables = {
}
/**
- * 宏任务延迟执行,解决vue3的部分渲染问题
+ * macro task to solve the rendering problem of vue3
*/
let macroTimer: number
function macroTask (fn: TimerHandler): void {
@@ -58,26 +58,26 @@ function macroTask (fn: TimerHandler): void {
}
export default class SandBox implements SandBoxInterface {
- static activeCount = 0 // 正在运行的沙盒数量
- active = false // 当前沙盒运行状态
+ static activeCount = 0 // number of active sandbox
+ active = false // sandbox state
proxyWindow: WindowProxy & injectDataType
releaseEffect: CallableFunction
- // 强隔离的全局变量(只能在沙箱中获取和设置的属性,不会兜底到外层window)
+ // Scoped global Properties(Properties that can only get and set in microWindow, will not escape to rawWindow)
scopeProperties: PropertyKey[] = ['webpackJsonp']
- // 可以泄漏到外部window的全局变量
+ // Properties that can be escape to rawWindow
escapeProperties: PropertyKey[] = []
- microWindow = {} as Window & injectDataType // 代理原型
- injectedKeys: Set = new Set() // proxyWindow新添加的属性
- escapeKeys: Set = new Set() // 泄漏到外部window的变量,卸载时清除
+ microWindow = {} as Window & injectDataType // Proxy target
+ injectedKeys: Set = new Set() // Properties newly added to microWindow
+ escapeKeys: Set = new Set() // Properties escape to rawWindow, cleared when unmount
constructor (appName: string, url: string, macro: boolean) {
const descriptorTargetMap = new Map()
const hasOwnProperty = (key: PropertyKey) => this.microWindow.hasOwnProperty(key) || rawWindow.hasOwnProperty(key)
- // 通过插件系统获取隔离属性和可逃逸属性
+ // get scopeProperties and escapeProperties from plugins
this.getScopeProperties(appName)
- // 注入全局变量
+ // inject global properties
this.inject(this.microWindow, appName, url)
- // 重写全局事件监听&定时器
+ // Rewrite global event listener & timeout
this.releaseEffect = effect(this.microWindow)
this.proxyWindow = new Proxy(this.microWindow, {
@@ -89,7 +89,7 @@ export default class SandBox implements SandBoxInterface {
}
if (key === 'top' || key === 'parent') {
- if (rawWindow === rawWindow.parent) { // 不在iframe
+ if (rawWindow === rawWindow.parent) { // not in iframe
return this.proxyWindow
}
return Reflect.get(rawWindow, key) // iframe
@@ -236,8 +236,8 @@ export default class SandBox implements SandBoxInterface {
}
/**
- * 通过插件系统获取隔离属性和可逃逸属性
- * @param appName 应用名称
+ * get scopeProperties and escapeProperties from plugins
+ * @param appName app name
*/
getScopeProperties (appName: string): void {
if (typeof microApp.plugins !== 'object') return
@@ -270,9 +270,9 @@ export default class SandBox implements SandBoxInterface {
}
/**
- * 向原型window注入全局变量
- * @param microWindow 原型window
- * @param appName 应用名称
+ * nject global properties to microWindow
+ * @param microWindow micro window
+ * @param appName app name
* @param url app url
*/
inject (microWindow: microWindowType, appName: string, url: string): void {
diff --git a/src/source/fetch.ts b/src/source/fetch.ts
index 952b3e09a..1939af184 100644
--- a/src/source/fetch.ts
+++ b/src/source/fetch.ts
@@ -2,10 +2,10 @@ import { isFunction } from '../libs/utils'
import microApp from '../micro_app'
/**
- * 获取静态资源
- * @param url 静态资源地址
- * @param appName 应用名称
- * @param config 配置项
+ * fetch source of html, js, css
+ * @param url source path
+ * @param appName app name
+ * @param config config of fetch
*/
export function fetchSource (url: string, appName: string, options = {}): Promise {
if (isFunction(microApp.fetch)) {
diff --git a/src/source/index.ts b/src/source/index.ts
index 0eca40568..53580c525 100644
--- a/src/source/index.ts
+++ b/src/source/index.ts
@@ -6,7 +6,7 @@ import { extractScriptElement, fetchScriptsFromHtml } from './scripts'
import scopedCSS from './scoped_css'
/**
- * 将html字符串转换为dom
+ * transform html string to dom
* @param str string dom
*/
function getWrapElement (str: string): HTMLElement {
@@ -18,10 +18,10 @@ function getWrapElement (str: string): HTMLElement {
}
/**
- * 递归处理每一个子元素
- * @param parent 父元素
- * @param app 应用实例
- * @param microAppHead micro-app-head标签
+ * Recursively process each child element
+ * @param parent parent element
+ * @param app app
+ * @param microAppHead micro-app-head element
*/
function flatChildren (
parent: HTMLElement,
@@ -62,9 +62,9 @@ function flatChildren (
}
/**
- * 提取link和script,绑定style作用域
- * @param htmlStr html字符串
- * @param app 应用实例
+ * Extract link and script, bind style scope
+ * @param htmlStr html string
+ * @param app app
*/
function extractSourceDom (htmlStr: string, app: AppInterface) {
const wrapElement = getWrapElement(htmlStr)
@@ -95,8 +95,8 @@ function extractSourceDom (htmlStr: string, app: AppInterface) {
}
/**
- * 提取并格式化html
- * @param app 应用实例
+ * Get and format html
+ * @param app app
*/
export default function extractHtml (app: AppInterface): void {
fetchSource(app.url, app.name, { cache: 'no-cache' }).then((htmlStr: string) => {
diff --git a/src/source/links.ts b/src/source/links.ts
index 7eb6a879f..9f54c3d59 100644
--- a/src/source/links.ts
+++ b/src/source/links.ts
@@ -15,16 +15,16 @@ import {
dispatchOnErrorEvent,
} from './load_event'
-// 全局link,跨应用复用
+// Global links, reuse across apps
export const globalLinks = new Map()
/**
- * 提取link标签
- * @param link link标签
- * @param parent link父级容器
- * @param app 实例
- * @param microAppHead micro-app-head标签,初始化时必传
- * @param isDynamic 是否是动态插入
+ * Extract link elements
+ * @param link link element
+ * @param parent parent element of link
+ * @param app app
+ * @param microAppHead micro-app-head element
+ * @param isDynamic dynamic insert
*/
export function extractLinkFromHtml (
link: HTMLLinkElement,
@@ -41,7 +41,7 @@ export function extractLinkFromHtml (
if (!isDynamic) {
replaceComment = document.createComment(`the link with href=${href} move to micro-app-head as style element`)
const placeholderComment = document.createComment(`placeholder for link with href=${href}`)
- // style标签统一放入microAppHead
+ // all style elements insert into microAppHead
microAppHead!.appendChild(placeholderComment)
app.source.links.set(href, {
code: '',
@@ -70,9 +70,9 @@ export function extractLinkFromHtml (
}
/**
- * 获取link远程资源
- * @param wrapElement 容器
- * @param app 应用实例
+ * Get link remote resources
+ * @param wrapElement htmlDom
+ * @param app app
* @param microAppHead micro-app-head
*/
export function fetchLinksFromHtml (
@@ -103,12 +103,12 @@ export function fetchLinksFromHtml (
}
/**
- * 请求link资源成功,将placeholder替换为style标签
- * @param url 资源地址
- * @param info 资源详情
- * @param data 资源内容
+ * fetch link succeeded, replace placeholder with style tag
+ * @param url resource address
+ * @param info resource link info
+ * @param data code
* @param microAppHead micro-app-head
- * @param app 应用实例
+ * @param app app
*/
export function fetchLinkSuccess (
url: string,
@@ -132,12 +132,12 @@ export function fetchLinkSuccess (
}
/**
- * 获取动态创建的link资源
- * @param url link地址
+ * get css from dynamic link
+ * @param url link address
* @param info info
- * @param app 应用实例
- * @param originLink 原link标签
- * @param replaceStyle style映射
+ * @param app app
+ * @param originLink origin link element
+ * @param replaceStyle style element which replaced origin link
*/
export function foramtDynamicLink (
url: string,
diff --git a/src/source/patch.ts b/src/source/patch.ts
index 17759dd0b..138005b5b 100644
--- a/src/source/patch.ts
+++ b/src/source/patch.ts
@@ -26,6 +26,7 @@ declare global {
}
}
+// save raw methods
const rawSetAttribute = Element.prototype.setAttribute
const rawAppendChild = Node.prototype.appendChild
const rawInsertBefore = Node.prototype.insertBefore
@@ -44,14 +45,14 @@ const rawGetElementsByClassName = Document.prototype.getElementsByClassName
const rawGetElementsByTagName = Document.prototype.getElementsByTagName
const rawGetElementsByName = Document.prototype.getElementsByName
-// 记录元素与映射元素
+// Record element and map element
const dynamicElementInMicroAppMap = new WeakMap()
/**
- * 处理新建的node,格式化style、link、script标签
- * @param parent 父元素
- * @param child 新增的元素
- * @param app 应用实例
+ * Process the new node and format the style, link and script element
+ * @param parent parent node
+ * @param child new node
+ * @param app app
*/
function handleNewNode (parent: Node, child: Node, app: AppInterface): Node {
if (child instanceof HTMLStyleElement) {
@@ -101,11 +102,11 @@ function handleNewNode (parent: Node, child: Node, app: AppInterface): Node {
)
if (url && info) {
- if (info.code) { // 内联script
+ if (info.code) { // inline script
const replaceElement = runScript(url, info.code, app, info.module, true)
dynamicElementInMicroAppMap.set(child, replaceElement)
return replaceElement
- } else { // 外部script
+ } else { // remote script
const replaceElement = runDynamicScript(url, info, app, child)
dynamicElementInMicroAppMap.set(child, replaceElement)
return replaceElement
@@ -120,12 +121,12 @@ function handleNewNode (parent: Node, child: Node, app: AppInterface): Node {
}
/**
- * 针对插入head和body的元素进行处理,其它情况正常执行
- * @param app 实例
- * @param method 原方法
- * @param parent 父元素
- * @param targetChild 经过格式化的目标元素
- * @param passiveChild insertBefore replaceChild的第二个参数
+ * Handle the elements inserted into head and body, and execute normally in other cases
+ * @param app app
+ * @param method raw method
+ * @param parent parent node
+ * @param targetChild target node
+ * @param passiveChild second param of insertBefore and replaceChild
*/
function invokePrototypeMethod (
app: AppInterface,
@@ -135,14 +136,14 @@ function invokePrototypeMethod (
passiveChild?: Node | null,
): any {
/**
- * 如果passiveChild不是子元素,则 insertBefore replaceChild 会有问题,此时降级处理为 appendchild
- * 类似:document.head.insertBefore(targetChild, document.head.childNodes[0])
+ * If passiveChild is not the child node, insertBefore replaceChild will have a problem, at this time, it will be degraded to appendChild
+ * E.g: document.head.insertBefore(targetChild, document.head.childNodes[0])
*/
if (parent instanceof HTMLHeadElement) {
const microAppHead = app.container!.querySelector('micro-app-head')!
/**
- * 1、passiveChild 存在,则必然为 insertBefore 或 replaceChild
- * 2、removeChild时,targetChild不一定在microAppHead或者head中
+ * 1. If passivechild exists, it must be insertBefore or replacechild
+ * 2. When removeChild, targetChild may not be in microAppHead or head
*/
if (passiveChild && !microAppHead.contains(passiveChild)) {
return rawAppendChild.call(microAppHead, targetChild)
@@ -175,17 +176,17 @@ function invokePrototypeMethod (
return rawMethod.call(parent, targetChild, passiveChild)
}
-// 获取映射元素
+// Get the map element
function getMappingNode (node: Node): Node {
return dynamicElementInMicroAppMap.get(node) ?? node
}
/**
- * 新增元素通用处理方法
- * @param parent 父元素
- * @param newChild 新增元素
- * @param passiveChild 可能存在的passive元素
- * @param rawMethod 原方法
+ * method of handle new node
+ * @param parent parent node
+ * @param newChild new node
+ * @param passiveChild passive node
+ * @param rawMethod raw method
*/
function commonElementHander (
parent: Node,
@@ -226,12 +227,12 @@ function commonElementHander (
}
/**
- * 重写元素原型链方法
+ * Rewrite element prototype method
*/
export function patchElementPrototypeMethods (): void {
patchDocument()
- // 重写setAttribute
+ // Rewrite setAttribute
Element.prototype.setAttribute = function setAttribute (key: string, value: string): void {
if (/^micro-app(-\S+)?/i.test(this.tagName) && key === 'data') {
if (toString.call(value) === '[object Object]') {
@@ -263,7 +264,7 @@ export function patchElementPrototypeMethods (): void {
}
}
- // 添加元素👇
+ // prototype methods of add element👇
Node.prototype.appendChild = function appendChild (newChild: T): T {
return commonElementHander(this, newChild, null, rawAppendChild)
}
@@ -293,7 +294,7 @@ export function patchElementPrototypeMethods (): void {
}
}
- // 删除元素👇
+ // prototype methods of delete element👇
Node.prototype.removeChild = function removeChild (oldChild: T): T {
if (oldChild?.__MICRO_APP_NAME__) {
const app = appInstanceMap.get(oldChild.__MICRO_APP_NAME__)
@@ -313,8 +314,8 @@ export function patchElementPrototypeMethods (): void {
}
/**
- * 将微应用中新建的元素打标
- * @param element 新建的元素
+ * Mark the newly created element in the micro application
+ * @param element new element
*/
function markElement (element: T): T {
const appName = getCurrentAppName()
@@ -324,9 +325,9 @@ function markElement (element: T): T
return element
}
-// document相关方法
+// methods of document
function patchDocument () {
- // 创建元素👇
+ // create element 👇
Document.prototype.createElement = function createElement (
tagName: string,
options?: ElementCreationOptions,
@@ -349,7 +350,7 @@ function patchDocument () {
return markElement(element)
}
- // 查询元素👇
+ // query element👇
function querySelector (selectors: string): any {
const appName = getCurrentAppName()
if (!appName || selectors === 'head' || selectors === 'body') {
@@ -369,7 +370,7 @@ function patchDocument () {
Document.prototype.querySelector = querySelector
Document.prototype.querySelectorAll = querySelectorAll
- // querySelector 不支持数字开头
+ // querySelector does not support the beginning of a number
Document.prototype.getElementById = function getElementById (key: string): HTMLElement | null {
const appName = getCurrentAppName()
if (!appName || /^\d/.test(key)) {
@@ -420,7 +421,7 @@ function releasePatchDocument (): void {
Document.prototype.getElementsByName = rawGetElementsByName
}
-// 解除绑定
+// release patch
export function releasePatches (): void {
setCurrentAppName(null)
releasePatchDocument()
@@ -433,7 +434,7 @@ export function releasePatches (): void {
Element.prototype.prepend = rawPrepend
}
-// 设置micro-app、micro-app-body的样式
+// Set the style of micro-app-head and micro-app-body
let hasRejectMicroAppStyle = false
export function rejectMicroAppStyle (): void {
if (!hasRejectMicroAppStyle) {
diff --git a/src/source/scoped_css.ts b/src/source/scoped_css.ts
index 455b6d69c..983b6c938 100644
--- a/src/source/scoped_css.ts
+++ b/src/source/scoped_css.ts
@@ -10,8 +10,8 @@ enum CSSRuleType {
}
/**
- * 绑定css作用域
- * 特殊情况:
+ * Bind css scope
+ * Special case:
* 1. html-abc | abc-html
* 2. html body.abc
* 3. abchtml | htmlabc | abcbody | bodyabc
@@ -37,7 +37,7 @@ function scopedStyleRule (rule: CSSStyleRule, prefix: string): string {
return cssText.replace(/^[\s\S]+{/, (selectors) => {
return selectors.replace(/(^|,)([^,]+)/g, (all, $1, $2) => {
if (builtInRootSelectorRE.test($2)) {
- // body[name=xx]|body.xx|body#xx 等都不需要转换
+ // body[name=xx]|body.xx|body#xx etc. do not need to handle
return all.replace(builtInRootSelectorRE, prefix)
}
return `${$1} ${prefix} ${$2.replace(/^\s*/, '')}`
@@ -46,11 +46,11 @@ function scopedStyleRule (rule: CSSStyleRule, prefix: string): string {
}
/**
- * 补全静态资源地址
- * @param cssText css内容
- * @param baseURI 域名
- * @param textContent 原始内容
- * @param linkpath link资源地址,如果是link转换为的style,会带有linkpath
+ * Complete static resource address
+ * @param cssText css content
+ * @param baseURI domain name
+ * @param textContent origin content
+ * @param linkpath link resource address, if it is the style converted from link, it will have linkpath
*/
function scopedHost (
cssText: string,
@@ -83,7 +83,7 @@ function scopedHost (
})
}
-// 处理media 和 supports
+// handle media and supports
function scopedPackRule (
rule: CSSMediaRule | CSSSupportsRule,
prefix: string,
@@ -94,9 +94,9 @@ function scopedPackRule (
}
/**
- * 依次处理每个cssRule
+ * Process each cssrule
* @param rules cssRule
- * @param prefix 前缀
+ * @param prefix prefix as micro-app[name=xxx]
*/
function scopedRule (rules: CSSRule[], prefix: string): string {
let result = ''
@@ -121,7 +121,7 @@ function scopedRule (rules: CSSRule[], prefix: string): string {
}
/**
- * 绑定css通用方法
+ * common method of bind CSS
*/
function commonAction (
templateStyle: HTMLStyleElement,
@@ -139,9 +139,9 @@ function commonAction (
linkpath,
)
/**
- * 解决部分safari浏览器下content引号丢失的问题
- * 参考文档 https://developer.mozilla.org/zh-CN/docs/Web/CSS/content
- * 如果依然有问题,推荐使用attr()方案降级处理
+ * Solve the problem of missing content quotes in some Safari browsers
+ * docs: https://developer.mozilla.org/zh-CN/docs/Web/CSS/content
+ * If there are still problems, it is recommended to use the attr()
*/
if (isSafari()) {
result = result.replace(/([;{]\s*content:\s*)([^\s"][^";}]*)/gm, (all, $1, $2) => {
@@ -160,9 +160,9 @@ function commonAction (
let templateStyle: HTMLStyleElement = rawDocument.body.querySelector('#micro-app-template-style')
/**
- * 绑定css作用域
- * @param styleElement 目标style元素
- * @param appName 应用名称
+ * scopedCSS
+ * @param styleElement target style element
+ * @param appName app name
*/
export default function scopedCSS (styleElement: HTMLStyleElement, appName: string): HTMLStyleElement {
const app = appInstanceMap.get(appName)
@@ -182,7 +182,7 @@ export default function scopedCSS (styleElement: HTMLStyleElement, appName: stri
} else {
const observer = new MutationObserver(function () {
observer.disconnect()
- // styled-component 暂时不处理
+ // styled-component will not be processed temporarily
if (
(!styleElement.textContent && styleElement.sheet?.cssRules?.length) ||
styleElement.hasAttribute('data-styled')
diff --git a/src/source/scripts.ts b/src/source/scripts.ts
index 29398349c..04328bc41 100644
--- a/src/source/scripts.ts
+++ b/src/source/scripts.ts
@@ -19,16 +19,16 @@ import {
} from './load_event'
import microApp from '../micro_app'
-// 全局script,跨应用复用
+// Global scripts, reuse across apps
export const globalScripts = new Map()
const supportModuleScript = isSupportModuleScript()
/**
- * 提取script标签
- * @param script script标签
- * @param parent 父级容器
- * @param app 实例
- * @param isDynamic 是否动态插入
+ * Extract script elements
+ * @param script script element
+ * @param parent parent element of script
+ * @param app app
+ * @param isDynamic dynamic insert
*/
export function extractScriptElement (
script: HTMLScriptElement,
@@ -45,7 +45,7 @@ export function extractScriptElement (
(!supportModuleScript && script.type === 'module')
) {
replaceComment = document.createComment(`${script.noModule ? 'noModule' : 'module'} script ignored by micro-app`)
- } else if (src) { // 远程script
+ } else if (src) { // remote script
src = CompletionPath(src, app.url)
const info = {
code: '',
@@ -62,7 +62,7 @@ export function extractScriptElement (
} else {
return { url: src, info }
}
- } else if (script.textContent) { // 内联script
+ } else if (script.textContent) { // inline script
const nonceStr: string = createNonceStr()
const info = {
code: script.textContent,
@@ -90,9 +90,9 @@ export function extractScriptElement (
}
/**
- * 获取script远程资源
- * @param wrapElement 容器
- * @param app 实例
+ * Get remote resources of script
+ * @param wrapElement htmlDom
+ * @param app app
*/
export function fetchScriptsFromHtml (
wrapElement: HTMLElement,
@@ -131,10 +131,10 @@ export function fetchScriptsFromHtml (
}
/**
- * 请求js成功,记录code值
- * @param url script地址
- * @param info 详情
- * @param data 资源内容
+ * fetch js succeeded, record the code value
+ * @param url script address
+ * @param info resource script info
+ * @param data code
*/
export function fetchScriptSuccess (
url: string,
@@ -149,9 +149,9 @@ export function fetchScriptSuccess (
}
/**
- * mount生命周期中执行js
- * @param scriptList html中的script列表
- * @param app 应用实例
+ * Execute js in the mount lifecycle
+ * @param scriptList script list
+ * @param app app
*/
export function execScripts (scriptList: Map, app: AppInterface): void {
const scriptListEntries: Array<[string, sourceScriptInfo]> = Array.from(scriptList.entries())
@@ -184,11 +184,11 @@ export function execScripts (scriptList: Map, app: App
}
/**
- * 获取动态创建的远程js
- * @param url js地址
+ * Get dynamically created remote script
+ * @param url script address
* @param info info
- * @param app 应用
- * @param originScript 原script标签
+ * @param app app
+ * @param originScript origin script element
*/
export function runDynamicScript (
url: string,
@@ -242,12 +242,12 @@ export function runDynamicScript (
}
/**
- * 运行代码
- * @param url 文件地址
- * @param code js代码
- * @param app 应用实例
- * @param module 是否是module标签
- * @param isDynamic 动态创建的script标签
+ * run code
+ * @param url script address
+ * @param code js code
+ * @param app app
+ * @param module type='module' of script
+ * @param isDynamic dynamically created script
*/
export function runScript (
url: string,
@@ -274,11 +274,10 @@ export function runScript (
}
/**
- * 绑定js作用域
- * @param url js地址
- * @param code 代码内容
- * @param app 应用实例
- * @returns string
+ * bind js scope
+ * @param url script address
+ * @param code code
+ * @param app app
*/
function bindScope (
url: string,
@@ -296,12 +295,11 @@ function bindScope (
}
/**
- * 调用插件处理文件
- * @param url js地址
- * @param code 代码
- * @param appName 应用名称
- * @param plugins 插件列表
- * @returns string
+ * Call the plugin to process the file
+ * @param url script address
+ * @param code code
+ * @param appName app name
+ * @param plugins plugin list
*/
function usePlugins (url: string, code: string, appName: string, plugins: plugins): string {
if (toString.call(plugins.global) === '[object Array]') {