Skip to content

Commit

Permalink
feat: make loadEntry and beforeLoad runs parallelly
Browse files Browse the repository at this point in the history
  • Loading branch information
kuitos committed Oct 23, 2023
1 parent e7d788e commit aaafbf5
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 38 deletions.
6 changes: 6 additions & 0 deletions .changeset/ninety-rivers-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@qiankunjs/loader": patch
"qiankun": patch
---

feat: add transformer options for app loader
39 changes: 13 additions & 26 deletions packages/loader/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import type { Sandbox } from '@qiankunjs/sandbox';
import { qiankunHeadTagName } from '@qiankunjs/sandbox';
import type { BaseTranspilerOpts } from '@qiankunjs/shared';
import {
Deferred,
isValidJavaScriptType,
moduleResolver as defaultModuleResolver,
QiankunError,
transpileAssets,
} from '@qiankunjs/shared';
import { Deferred, moduleResolver as defaultModuleResolver, QiankunError, transpileAssets } from '@qiankunjs/shared';
import { TagTransformStream } from './TagTransformStream';
import { isUrlHasOwnProtocol } from './utils';
import WritableDOMStream from './writable-dom';
Expand All @@ -23,8 +17,8 @@ type Entry = HTMLEntry;
// execute: (executor?: Promise<K>) => Promise<K>;
// };
//
export type ImportOpts = {
decoder?: (chunk: string) => string;
export type LoaderOpts = {
transformer?: TransformStream<string, string>;
nodeTransformer?: typeof transpileAssets;
} & BaseTranspilerOpts & { sandbox?: Sandbox };

Expand All @@ -33,14 +27,11 @@ export type ImportOpts = {
* @param container
* @param opts
*/
export async function loadEntry<T>(
entry: Entry,
container: HTMLElement,
opts: ImportOpts,
): Promise<[Promise<void>, Promise<T | void>]> {
export async function loadEntry<T>(entry: Entry, container: HTMLElement, opts: LoaderOpts): Promise<T | void> {
const {
fetch,
nodeTransformer = transpileAssets,
transformer,
sandbox,
moduleResolver = (url: string) => {
return defaultModuleResolver(url, container, document.head);
Expand All @@ -50,12 +41,16 @@ export async function loadEntry<T>(
const res = isUrlHasOwnProtocol(entry) ? await fetch(entry) : new Response(entry);
if (res.body) {
let noExternalScript = true;
const firstScriptStartLoadDeferred = new Deferred<void>();
const entryScriptLoadedDeferred = new Deferred<T | void>();
const entryHTMLLoadedDeferred = new Deferred<void>();

void res.body
.pipeThrough(new TextDecoderStream())
let readableStream = res.body.pipeThrough(new TextDecoderStream());

if (transformer) {
readableStream = readableStream.pipeThrough(transformer);
}

void readableStream
.pipeThrough(
new TagTransformStream(
[
Expand All @@ -79,14 +74,6 @@ export async function loadEntry<T>(

const script = transformedNode as unknown as HTMLScriptElement;

if (
firstScriptStartLoadDeferred.status === 'pending' &&
script.tagName === 'SCRIPT' &&
isValidJavaScriptType(script.type)
) {
firstScriptStartLoadDeferred.resolve();
}

/*
* If the entry script is executed, we can complete the entry process in advance
* otherwise we need to wait until the last script is executed.
Expand Down Expand Up @@ -150,7 +137,7 @@ export async function loadEntry<T>(
}
});

return [firstScriptStartLoadDeferred.promise, entryScriptLoadedDeferred.promise];
return entryScriptLoadedDeferred.promise;
}

throw new QiankunError(`entry ${entry} response body is empty!`);
Expand Down
17 changes: 7 additions & 10 deletions packages/qiankun/src/core/loadApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @author Kuitos
* @since 2023-04-25
*/
import type { ImportOpts } from '@qiankunjs/loader';
import type { LoaderOpts } from '@qiankunjs/loader';
import { loadEntry } from '@qiankunjs/loader';
import type { Sandbox } from '@qiankunjs/sandbox';
import { createSandboxContainer } from '@qiankunjs/sandbox';
Expand All @@ -28,7 +28,7 @@ export default async function loadApp<T extends ObjectType>(
lifeCycles?: LifeCycles<T>,
) {
const { name: appName, entry, container } = app;
const { fetch = window.fetch, sandbox, globalContext = window } = configuration || {};
const { fetch = window.fetch, sandbox, globalContext = window, transformer } = configuration || {};

const markName = `[qiankun] App ${appName} Loading`;
if (process.env.NODE_ENV === 'development') {
Expand Down Expand Up @@ -56,13 +56,10 @@ export default async function loadApp<T extends ObjectType>(
unmountSandbox = () => sandboxContainer.unmount();
}

const containerOpts: ImportOpts = { fetch, sandbox: sandboxInstance };
const containerOpts: LoaderOpts = { fetch, sandbox: sandboxInstance, transformer };

const lifecyclesPromise = loadEntry<MicroAppLifeCycles>(entry, microAppContainer, containerOpts);

const [firstScriptStartLoadPromise, entryScriptLoadedPromise] = await loadEntry<MicroAppLifeCycles>(
entry,
microAppContainer,
containerOpts,
);
const assetPublicPath = calcPublicPath(entry);
const {
beforeUnmount = [],
Expand All @@ -73,10 +70,10 @@ export default async function loadApp<T extends ObjectType>(
} = mergeWith({}, getAddOns(global, assetPublicPath), lifeCycles, (v1, v2) =>
concat((v1 ?? []) as LifeCycleFn<T>, (v2 ?? []) as LifeCycleFn<T>),
);
await firstScriptStartLoadPromise;
// FIXME Due to the asynchronous execution of loadEntry, the DOM of the sub-app is inserted synchronously through appendChild, and inline scripts are also executed synchronously. Therefore, the beforeLoad may need to rely on transformer configuration to coordinate and ensure the order of asynchronous operations.
await execHooksChain(toArray(beforeLoad), app, global);

const lifecycles = await entryScriptLoadedPromise;
const lifecycles = await lifecyclesPromise;
if (!lifecycles) throw new QiankunError(`${appName} entry ${entry} load failed as it not export lifecycles`);
const { bootstrap, mount, unmount, update } = getLifecyclesFromExports(
lifecycles,
Expand Down
4 changes: 2 additions & 2 deletions packages/qiankun/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @author Kuitos
* @since 2023-04-25
*/
import type { BaseLoaderOpts } from '@qiankunjs/shared';
import type { LoaderOpts } from '@qiankunjs/loader';
import type { LifeCycles as ParcelLifeCycles, Parcel, RegisterApplicationConfig } from 'single-spa';

declare global {
Expand Down Expand Up @@ -41,7 +41,7 @@ export type RegistrableApp<T extends ObjectType> = LoadableApp<T> & {
activeRule: RegisterApplicationConfig['activeWhen'];
};

export type AppConfiguration = Partial<BaseLoaderOpts> & {
export type AppConfiguration = Pick<LoaderOpts, 'fetch' | 'transformer'> & {
sandbox?: boolean;
globalContext?: WindowProxy;
};
Expand Down

0 comments on commit aaafbf5

Please sign in to comment.