Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: insertBefore加入script逻辑 #592

Merged
merged 6 commits into from
May 21, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 51 additions & 3 deletions src/sandbox/patchers/dynamicHeadAppend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ function getNewInsertBefore(...args: any[]) {
const element = newChild as any;
if (element.tagName) {
// eslint-disable-next-line prefer-const
let [appName, appWrapperGetter, singular, dynamicStyleSheetElements] = args;
let [appName, appWrapperGetter, proxy, singular, dynamicStyleSheetElements] = args;

const storedContainerInfo = element[attachProxySymbol];
if (storedContainerInfo) {
Expand All @@ -191,6 +191,11 @@ function getNewInsertBefore(...args: any[]) {
dynamicStyleSheetElements = storedContainerInfo.dynamicStyleSheetElements;
}

// have storedContainerInfo means it invoked by a micro app
const invokedByMicroApp = storedContainerInfo && !singular;
const wrapper = appWrapperGetter();
const referenceNode = wrapper.contains(refChild) ? refChild : null;

switch (element.tagName) {
case LINK_TAG_NAME:
case STYLE_TAG_NAME: {
Expand All @@ -207,14 +212,56 @@ function getNewInsertBefore(...args: any[]) {

if (activated) {
dynamicStyleSheetElements.push(stylesheetElement);
const wrapper = appWrapperGetter();
const referenceNode = wrapper.contains(refChild) ? refChild : null;

return rawHeadInsertBefore.call(wrapper, stylesheetElement, referenceNode) as T;
}

return rawHeadInsertBefore.call(this, element, refChild) as T;
}
case SCRIPT_TAG_NAME: {
if (!invokedByMicroApp) {
return rawHeadInsertBefore.call(this, element, refChild) as T;
}

const { src, text } = element as HTMLScriptElement;

const { fetch } = frameworkConfiguration;

if (src) {
execScripts(null, [src], proxy, { fetch, strictGlobal: !singular }).then(
() => {
// we need to invoke the onload event manually to notify the event listener that the script was completed
// here are the two typical ways of dynamic script loading
// 1. element.onload callback way, which webpack and loadjs used, see https://github.com/muicss/loadjs/blob/master/src/loadjs.js#L138
// 2. addEventListener way, which toast-loader used, see https://github.com/pyrsmk/toast/blob/master/src/Toast.ts#L64
const loadEvent = new CustomEvent('load');
if (isFunction(element.onload)) {
element.onload(loadEvent);
} else {
element.dispatchEvent(loadEvent);
}
},
() => {
const errorEvent = new CustomEvent('error');
if (isFunction(element.onerror)) {
element.onerror(errorEvent);
} else {
element.dispatchEvent(errorEvent);
}
},
);

const dynamicScriptCommentElement = document.createComment(`dynamic script ${src} replaced by qiankun`);
return rawHeadInsertBefore.call(appWrapperGetter(), dynamicScriptCommentElement, referenceNode) as T;
}

execScripts(null, [`<script>${text}</script>`], proxy, { strictGlobal: !singular }).then(
element.onload,
element.onerror,
);
const dynamicInlineScriptCommentElement = document.createComment('dynamic inline script replaced by qiankun');
return rawHeadInsertBefore.call(appWrapperGetter(), dynamicInlineScriptCommentElement, referenceNode) as T;
}
default:
break;
}
Expand Down Expand Up @@ -298,6 +345,7 @@ export default function patch(
HTMLHeadElement.prototype.insertBefore = getNewInsertBefore(
appName,
appWrapperGetter,
proxy,
singular,
dynamicStyleSheetElements,
);
Expand Down