From 300f4a7317a483364b8a82366243bfd48fdd7754 Mon Sep 17 00:00:00 2001 From: yiludege Date: Fri, 24 Mar 2023 19:54:32 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dscript=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E5=B1=9E=E6=80=A7=E4=B8=A2=E5=A4=B1=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=20(#472)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close #374 --- packages/wujie-core/src/effect.ts | 15 ++++++++++++--- packages/wujie-core/src/iframe.ts | 23 ++++++++++++++++++----- packages/wujie-core/src/index.ts | 4 +++- packages/wujie-core/src/proxy.ts | 15 +++++++++++++-- packages/wujie-core/src/template.ts | 20 ++++++++++++++++++++ 5 files changed, 66 insertions(+), 11 deletions(-) diff --git a/packages/wujie-core/src/effect.ts b/packages/wujie-core/src/effect.ts index 7137b0ed8..c3b6a70de 100644 --- a/packages/wujie-core/src/effect.ts +++ b/packages/wujie-core/src/effect.ts @@ -34,7 +34,7 @@ import { WUJIE_TIPS_REPEAT_RENDER, WUJIE_TIPS_NO_SCRIPT, } from "./constant"; -import { ScriptObject } from "./template"; +import { ScriptObject, getScriptAttrs } from "./template"; function patchCustomEvent( e: CustomEvent, @@ -274,6 +274,7 @@ function rewriteAppendOrInsertChild(opts: { crossorigin: crossOrigin !== null, crossoriginType: crossOrigin || "", ignore: isMatchUrl(src, getEffectLoaders("jsIgnores", plugins)), + attrs: getScriptAttrs(element.outerHTML), } as ScriptObject; getExternalScripts([scriptOptions], fetch, lifecycles.loadError, fiber).forEach((scriptResult) => { dynamicScriptExecStack = dynamicScriptExecStack.then(() => @@ -303,9 +304,17 @@ function rewriteAppendOrInsertChild(opts: { sandbox.execQueue.push(() => fiber ? requestIdleCallback(() => { - insertScriptToIframe({ src: null, content: text }, sandbox.iframe.contentWindow, element); + insertScriptToIframe( + { src: null, content: text, attrs: getScriptAttrs(element.outerHTML) }, + sandbox.iframe.contentWindow, + element + ); }) - : insertScriptToIframe({ src: null, content: text }, sandbox.iframe.contentWindow, element) + : insertScriptToIframe( + { src: null, content: text, attrs: getScriptAttrs(element.outerHTML) }, + sandbox.iframe.contentWindow, + element + ) ); if (!execQueueLength) sandbox.execQueue.shift()(); } diff --git a/packages/wujie-core/src/iframe.ts b/packages/wujie-core/src/iframe.ts index a095758c0..ac8a5035d 100644 --- a/packages/wujie-core/src/iframe.ts +++ b/packages/wujie-core/src/iframe.ts @@ -145,10 +145,6 @@ function patchIframeVariable(iframeWindow: Window, wujie: WuJie, appHostPath: st iframeWindow.__WUJIE_PUBLIC_PATH__ = appHostPath + "/"; iframeWindow.$wujie = wujie.provide; iframeWindow.__WUJIE_RAW_WINDOW__ = iframeWindow; - iframeWindow.__WUJIE_RAW_DOCUMENT_QUERY_SELECTOR__ = iframeWindow.Document.prototype.querySelector; - iframeWindow.__WUJIE_RAW_DOCUMENT_QUERY_SELECTOR_ALL__ = iframeWindow.Document.prototype.querySelectorAll; - iframeWindow.__WUJIE_RAW_DOCUMENT_CREATE_ELEMENT__ = iframeWindow.Document.prototype.createElement; - iframeWindow.__WUJIE_RAW_DOCUMENT_CREATE_TEXT_NODE__ = iframeWindow.Document.prototype.createTextNode; } /** @@ -610,6 +606,18 @@ function initIframeDom(iframeWindow: Window, wujie: WuJie, mainHostPath: string, ? iframeDocument.replaceChild(newDocumentElement, iframeDocument.documentElement) : iframeDocument.appendChild(newDocumentElement); iframeWindow.__WUJIE_RAW_DOCUMENT_HEAD__ = iframeDocument.head; + iframeWindow.__WUJIE_RAW_DOCUMENT_QUERY_SELECTOR__ = iframeWindow.Document.prototype.querySelector.bind( + iframeWindow.document + ); + iframeWindow.__WUJIE_RAW_DOCUMENT_QUERY_SELECTOR_ALL__ = iframeWindow.Document.prototype.querySelectorAll.bind( + iframeWindow.document + ); + iframeWindow.__WUJIE_RAW_DOCUMENT_CREATE_ELEMENT__ = iframeWindow.Document.prototype.createElement.bind( + iframeWindow.document + ); + iframeWindow.__WUJIE_RAW_DOCUMENT_CREATE_TEXT_NODE__ = iframeWindow.Document.prototype.createTextNode.bind( + iframeWindow.document + ); initBase(iframeWindow, wujie.url); patchIframeHistory(iframeWindow, appHostPath, mainHostPath); patchIframeEvents(iframeWindow); @@ -693,13 +701,18 @@ export function insertScriptToIframe( iframeWindow: Window, rawElement?: HTMLScriptElement ) { - const { src, module, content, crossorigin, crossoriginType, async, callback, onload } = + const { src, module, content, crossorigin, crossoriginType, async, attrs, callback, onload } = scriptResult as ScriptObjectLoader; const scriptElement = iframeWindow.document.createElement("script"); const nextScriptElement = iframeWindow.document.createElement("script"); const { replace, plugins, proxyLocation } = iframeWindow.__WUJIE; const jsLoader = getJsLoader({ plugins, replace }); let code = jsLoader(content, src, getCurUrl(proxyLocation)); + // 添加属性 + attrs && + Object.keys(attrs) + .filter((key) => !Object.keys(scriptResult).includes(key)) + .forEach((key) => scriptElement.setAttribute(key, String(attrs[key]))); // 内联脚本 if (content) { diff --git a/packages/wujie-core/src/index.ts b/packages/wujie-core/src/index.ts index f05db5954..e0c02d713 100644 --- a/packages/wujie-core/src/index.ts +++ b/packages/wujie-core/src/index.ts @@ -1,5 +1,5 @@ import importHTML, { processCssLoader } from "./entry"; -import { StyleObject } from "./template"; +import { StyleObject, ScriptAttributes } from "./template"; import WuJie, { lifecycle } from "./sandbox"; import { defineWujieWebComponent, addLoading } from "./shadow"; import { processAppForHrefJump } from "./sync"; @@ -22,6 +22,8 @@ export interface ScriptObjectLoader { crossorigin?: boolean; /** 脚本crossorigin的类型 */ crossoriginType?: "anonymous" | "use-credentials" | ""; + /** 脚本原始属性 */ + attrs?: ScriptAttributes; /** 内联script的代码 */ content?: string; /** 执行回调钩子 */ diff --git a/packages/wujie-core/src/proxy.ts b/packages/wujie-core/src/proxy.ts index 58cf970c8..a48c53a1b 100644 --- a/packages/wujie-core/src/proxy.ts +++ b/packages/wujie-core/src/proxy.ts @@ -126,17 +126,28 @@ export function proxyGenerator( if (ctx !== iframe.contentDocument) { return ctx[propKey]?.apply(ctx, args); } - return target.call(shadowRoot, `[id="${args[0]}"]`); + return ( + target.call(shadowRoot, `[id="${args[0]}"]`) || + iframe.contentWindow.__WUJIE_RAW_DOCUMENT_QUERY_SELECTOR__(`#${args[0]}`) + ); }, }); } if (propKey === "querySelector" || propKey === "querySelectorAll") { + const rawPropMap = { + querySelector: "__WUJIE_RAW_DOCUMENT_QUERY_SELECTOR__", + querySelectorAll: "__WUJIE_RAW_DOCUMENT_QUERY_SELECTOR_ALL__", + }; return new Proxy(shadowRoot[propKey], { apply(target, ctx, args) { if (ctx !== iframe.contentDocument) { return ctx[propKey]?.apply(ctx, args); } - return target.apply(shadowRoot, args); + // 二选一,优先shadowDom,除非采用array合并,排除base,防止对router造成影响 + return ( + target.apply(shadowRoot, args) || + (args[0] === "base" ? null : iframe.contentWindow[rawPropMap[propKey]](args[0])) + ); }, }); } diff --git a/packages/wujie-core/src/template.ts b/packages/wujie-core/src/template.ts index 7b1a7cbf1..2555196b7 100644 --- a/packages/wujie-core/src/template.ts +++ b/packages/wujie-core/src/template.ts @@ -21,7 +21,11 @@ const LINK_IGNORE_REGEX = //is; const STYLE_IGNORE_REGEX = //is; const SCRIPT_IGNORE_REGEX = //is; const CROSS_ORIGIN_REGEX = /.*\scrossorigin=?('|")?(use-credentials|anonymous)?('|")?/i; +const SCRIPT_ATTRS_REGEX = /\s+(\w+)(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^>\s]+)))?/g; +export type ScriptAttributes = { + [key: string]: string | boolean; // 所有属性都可以是字符串或布尔值类型 +}; /** 脚本对象 */ export interface ScriptBaseObject { /** 脚本地址,内联为空 */ @@ -36,6 +40,8 @@ export interface ScriptBaseObject { crossorigin?: boolean; /** 脚本crossorigin的类型 */ crossoriginType?: "anonymous" | "use-credentials" | ""; + /** 脚本正则匹配属性 */ + attrs?: ScriptAttributes; } export type ScriptObject = ScriptBaseObject & { /** 内联script的代码 */ @@ -82,6 +88,17 @@ function isValidJavaScriptType(type) { return !type || handleTypes.indexOf(type) !== -1; } +export function getScriptAttrs(attrsHtml) { + const attributes = {}; + let attrMatch; + while ((attrMatch = SCRIPT_ATTRS_REGEX.exec(attrsHtml))) { + const attrName = attrMatch[1]; + const attrValue = attrMatch[2] || attrMatch[3] || attrMatch[4] || true; + attributes[attrName] = attrValue; + } + return attributes; +} + function isModuleScriptSupported() { const s = window.document.createElement("script"); return "noModule" in s; @@ -219,12 +236,14 @@ export default function processTpl(tpl: String, baseURI: String, postProcessTemp module: isModuleScript, crossorigin: !!isCrossOriginScript, crossoriginType: crossOriginType, + attrs: getScriptAttrs(match), } : { src: matchedScriptSrc, module: isModuleScript, crossorigin: !!isCrossOriginScript, crossoriginType: crossOriginType, + attrs: getScriptAttrs(match), } ); return genScriptReplaceSymbol( @@ -256,6 +275,7 @@ export default function processTpl(tpl: String, baseURI: String, postProcessTemp module: isModuleScript, crossorigin: !!isCrossOriginScript, crossoriginType: crossOriginType, + attrs: getScriptAttrs(match), }); }