From 90a9612d08f1c60d2c75d9352ee1a8ce2ada3ab4 Mon Sep 17 00:00:00 2001
From: bailicangdu <1264889788@qq.com>
Date: Wed, 20 Oct 2021 15:59:33 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E4=BA=86module=20scr?=
=?UTF-8?q?ipt=E7=9A=84=E6=89=A7=E8=A1=8C=E6=96=B9=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
examples/children/react16/src/index.js | 13 ++++-
examples/main-react16/src/global.jsx | 15 +++++-
examples/main-react16/src/pages/vite/vite.js | 10 +++-
src/libs/utils.ts | 4 +-
src/source/scripts.ts | 51 ++++++++++++--------
5 files changed, 66 insertions(+), 27 deletions(-)
diff --git a/examples/children/react16/src/index.js b/examples/children/react16/src/index.js
index dd93cc38d..8f8f42d2a 100644
--- a/examples/children/react16/src/index.js
+++ b/examples/children/react16/src/index.js
@@ -100,5 +100,14 @@ if (window.__MICRO_APP_ENVIRONMENT__) {
// const dynamicScript1 = document.createElement('script')
// dynamicScript1.setAttribute('type', 'module')
-// dynamicScript1.textContent = 'console.warn("inline module")'
-// document.head.appendChild(dynamicScript1)
+// // dynamicScript1.textContent = 'console.warn("inline module")'
+// dynamicScript1.setAttribute('src', 'http://127.0.0.1:8080/test.js')
+// dynamicScript1.onload = () => {
+// console.log('动态module加载完成了')
+// }
+// document.body.appendChild(dynamicScript1)
+
+console.log('__micro_app_environment__', window.__micro_app_environment__)
+console.log('__micro_app_name__', window.__micro_app_name__)
+console.log('__full_public_path__', window.__full_public_path__)
+console.log('baseurl', window.baseurl)
diff --git a/examples/main-react16/src/global.jsx b/examples/main-react16/src/global.jsx
index c2339477d..d70bf79a8 100644
--- a/examples/main-react16/src/global.jsx
+++ b/examples/main-react16/src/global.jsx
@@ -37,7 +37,20 @@ microApp.start({
// console.log('vue2插件', url, options)
return code
}
- }],
+ },
+ {
+ loader (code) {
+ code = `
+ window.__micro_app_environment__ = window.__MICRO_APP_ENVIRONMENT__
+ window.__micro_app_name__ = window.__MICRO_APP_NAME__
+ window.__full_public_path__ = window.__MICRO_APP_PUBLIC_PATH__
+ window.baseurl = window.__MICRO_APP_BASE_ROUTE__
+ ;${code}
+ `
+ return code
+ }
+ }
+ ],
modules: {
react16: [{
scopeProperties: ['3', '4'],
diff --git a/examples/main-react16/src/pages/vite/vite.js b/examples/main-react16/src/pages/vite/vite.js
index c25e9d0ae..6d836bee1 100644
--- a/examples/main-react16/src/pages/vite/vite.js
+++ b/examples/main-react16/src/pages/vite/vite.js
@@ -12,6 +12,12 @@ const antIcon =
function vite () {
const [data, changeData] = useState({from: '来自基座的初始化数据'})
const [showLoading, hideLoading] = useState(true)
+
+ function handleMounted () {
+ hideLoading(false)
+ console.log('生命周期: vite 渲染完成了')
+ }
+
return (
{/*
@@ -32,9 +38,9 @@ function vite () {
// url={`http://127.0.0.1:8080/micro-app/vite/`}
data={data}
// onBeforemount={() => hideLoading(false)}
- onMounted={() => hideLoading(false)}
+ onMounted={handleMounted}
// destory
- inline
+ // inline
disableSandbox
>
diff --git a/src/libs/utils.ts b/src/libs/utils.ts
index 1ed5cbefb..b44127ccc 100644
--- a/src/libs/utils.ts
+++ b/src/libs/utils.ts
@@ -170,8 +170,8 @@ export function isSupportModuleScript (): boolean {
}
// Create a random symbol string
-export function createNonceStr (): string {
- return Math.random().toString(36).substr(2, 15)
+export function createNonceSrc (): string {
+ return 'inline-' + Math.random().toString(36).substr(2, 15)
}
// Array deduplication
diff --git a/src/source/scripts.ts b/src/source/scripts.ts
index 7f3da400b..f519b6ef7 100644
--- a/src/source/scripts.ts
+++ b/src/source/scripts.ts
@@ -9,7 +9,7 @@ import { fetchSource } from './fetch'
import {
CompletionPath,
promiseStream,
- createNonceStr,
+ createNonceSrc,
pureCreateElement,
defer,
logError,
@@ -21,6 +21,8 @@ import {
import microApp from '../micro_app'
import globalEnv from '../libs/global_env'
+type moduleCallBack = Func & { moduleCount?: number }
+
// Global scripts, reuse across apps
export const globalScripts = new Map
()
@@ -69,7 +71,7 @@ export function extractScriptElement (
return { url: src, info }
}
} else if (script.textContent) { // inline script
- const nonceStr: string = createNonceStr()
+ const nonceStr: string = createNonceSrc()
const info = {
code: script.textContent,
isExternal: false,
@@ -158,12 +160,12 @@ export function fetchScriptSuccess (
* Execute js in the mount lifecycle
* @param scriptList script list
* @param app app
- * @param callback callback for umd mode
+ * @param initedHook callback for umd mode
*/
export function execScripts (
scriptList: Map,
app: AppInterface,
- callback: Func,
+ initedHook: moduleCallBack,
): void {
const scriptListEntries: Array<[string, sourceScriptInfo]> = Array.from(scriptList.entries())
const deferScriptPromise: Array|string> = []
@@ -177,6 +179,8 @@ export function execScripts (
deferScriptPromise.push(info.code)
}
deferScriptInfo.push([url, info])
+
+ if (info.module) initedHook.moduleCount = initedHook.moduleCount ? ++initedHook.moduleCount : 1
} else {
runScript(url, info.code, app, info.module, false)
}
@@ -187,15 +191,15 @@ export function execScripts (
Promise.all(deferScriptPromise).then((res: string[]) => {
res.forEach((code, index) => {
const [url, info] = deferScriptInfo[index]
- runScript(url, info.code = info.code || code, app, info.module, false, callback)
+ runScript(url, info.code = info.code || code, app, info.module, false, initedHook)
})
- callback(true)
+ initedHook(typeof initedHook.moduleCount === 'undefined')
}).catch((err) => {
logError(err)
- callback(true)
+ initedHook(true)
})
} else {
- callback(true)
+ initedHook(true)
}
}
@@ -206,7 +210,7 @@ export function execScripts (
* @param app app
* @param module type='module' of script
* @param isDynamic dynamically created script
- * @param callback callback from execScripts for first exec
+ * @param callback callback of module script
*/
export function runScript (
url: string,
@@ -214,7 +218,7 @@ export function runScript (
app: AppInterface,
module: boolean,
isDynamic: boolean,
- callback?: Func,
+ callback?: moduleCallBack,
): any {
try {
code = bindScope(url, code, app, module)
@@ -245,18 +249,20 @@ export function runDynamicRemoteScript (
app: AppInterface,
originScript: HTMLScriptElement,
): HTMLScriptElement | Comment {
+ const dispatchScriptOnLoadEvent = () => dispatchOnLoadEvent(originScript)
+
if (app.source.scripts.has(url)) {
const existInfo: sourceScriptInfo = app.source.scripts.get(url)!
- defer(() => dispatchOnLoadEvent(originScript))
- return runScript(url, existInfo.code, app, info.module, true)
+ if (!info.module) defer(dispatchScriptOnLoadEvent)
+ return runScript(url, existInfo.code, app, info.module, true, dispatchScriptOnLoadEvent)
}
if (globalScripts.has(url)) {
const code = globalScripts.get(url)!
info.code = code
app.source.scripts.set(url, info)
- defer(() => dispatchOnLoadEvent(originScript))
- return runScript(url, code, app, info.module, true)
+ if (!info.module) defer(dispatchScriptOnLoadEvent)
+ return runScript(url, code, app, info.module, true, dispatchScriptOnLoadEvent)
}
let replaceElement: Comment | HTMLScriptElement
@@ -273,14 +279,14 @@ export function runDynamicRemoteScript (
try {
code = bindScope(url, code, app, info.module)
if (app.inline || info.module) {
- setInlinScriptContent(url, code, info.module, replaceElement as HTMLScriptElement)
+ setInlinScriptContent(url, code, info.module, replaceElement as HTMLScriptElement, dispatchScriptOnLoadEvent)
} else {
Function(code)()
}
} catch (e) {
console.error('[micro-app from runDynamicScript]', e, url)
}
- dispatchOnLoadEvent(originScript)
+ if (!info.module) dispatchOnLoadEvent(originScript)
}).catch((err) => {
logError(err)
dispatchOnErrorEvent(originScript)
@@ -295,22 +301,27 @@ export function runDynamicRemoteScript (
* @param code js code
* @param module type='module' of script
* @param scriptElement target script element
- * @param callback callback from execScripts for first exec
+ * @param callback callback of module script
*/
function setInlinScriptContent (
url: string,
code: string,
module: boolean,
scriptElement: HTMLScriptElement,
- callback?: Func,
+ callback?: moduleCallBack,
): void {
if (module) {
// module script is async, transform it to a blob for subsequent operations
const blob = new Blob([code], { type: 'text/javascript;charset=utf-8' })
scriptElement.src = URL.createObjectURL(blob)
scriptElement.setAttribute('type', 'module')
- scriptElement.setAttribute('originSrc', url)
- callback && (scriptElement.onload = callback)
+ if (!url.startsWith('inline-')) {
+ scriptElement.setAttribute('originSrc', url)
+ }
+ if (callback) {
+ callback.moduleCount && callback.moduleCount--
+ scriptElement.onload = callback.bind(scriptElement, callback.moduleCount === 0)
+ }
} else {
scriptElement.textContent = code
}