Skip to content

Commit

Permalink
fix: 修复script脚本属性丢失的问题 (#472)
Browse files Browse the repository at this point in the history
close #374
  • Loading branch information
yiludege authored Mar 24, 2023
1 parent af054da commit 300f4a7
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 11 deletions.
15 changes: 12 additions & 3 deletions packages/wujie-core/src/effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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(() =>
Expand Down Expand Up @@ -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()();
}
Expand Down
23 changes: 18 additions & 5 deletions packages/wujie-core/src/iframe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down
4 changes: 3 additions & 1 deletion packages/wujie-core/src/index.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -22,6 +22,8 @@ export interface ScriptObjectLoader {
crossorigin?: boolean;
/** 脚本crossorigin的类型 */
crossoriginType?: "anonymous" | "use-credentials" | "";
/** 脚本原始属性 */
attrs?: ScriptAttributes;
/** 内联script的代码 */
content?: string;
/** 执行回调钩子 */
Expand Down
15 changes: 13 additions & 2 deletions packages/wujie-core/src/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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]))
);
},
});
}
Expand Down
20 changes: 20 additions & 0 deletions packages/wujie-core/src/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ const LINK_IGNORE_REGEX = /<link(\s+|\s+.+\s+)ignore(\s*|\s+.*|=.*)>/is;
const STYLE_IGNORE_REGEX = /<style(\s+|\s+.+\s+)ignore(\s*|\s+.*|=.*)>/is;
const SCRIPT_IGNORE_REGEX = /<script(\s+|\s+.+\s+)ignore(\s*|\s+.*|=.*)>/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 {
/** 脚本地址,内联为空 */
Expand All @@ -36,6 +40,8 @@ export interface ScriptBaseObject {
crossorigin?: boolean;
/** 脚本crossorigin的类型 */
crossoriginType?: "anonymous" | "use-credentials" | "";
/** 脚本正则匹配属性 */
attrs?: ScriptAttributes;
}
export type ScriptObject = ScriptBaseObject & {
/** 内联script的代码 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -256,6 +275,7 @@ export default function processTpl(tpl: String, baseURI: String, postProcessTemp
module: isModuleScript,
crossorigin: !!isCrossOriginScript,
crossoriginType: crossOriginType,
attrs: getScriptAttrs(match),
});
}

Expand Down

0 comments on commit 300f4a7

Please sign in to comment.