Skip to content

Commit

Permalink
perf: context global variables set method change
Browse files Browse the repository at this point in the history
  • Loading branch information
hubert committed Dec 27, 2024
1 parent 1a2e301 commit 26dd24f
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 122 deletions.
32 changes: 10 additions & 22 deletions packages/module-loader/src/createLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import * as VueDemi from 'vue-demi';
import { createModuleLoader } from './core/moduleLoader';
import { createComponentLoader } from './core/componentLoader';
import { ModuleLoaderSymbol, setActiveLoader, setOptions, addErrorHandler, removeErrorHandler } from './register';
import { getUmdResolver } from './resolvers/umd';
import { createUmdResolver } from './resolvers/umd';

// Types
import type { ModuleLoader, GetResolver } from './types';
import type { ModuleLoader, Resolver, ResolverCreator } from './types';

/**
* create module loader
Expand All @@ -15,27 +15,15 @@ export function createLoader<Props extends Record<string, any> = any, Context =
/**
* remote module resolver, default to umd resolver
*/
resolver?: GetResolver<Context>;
/**
* container to append script, default is append to body in client side
*/
container?: string | ((proxy: Context) => Element);
/**
* global variables to expose to remote module
*/
globals?: Record<string, any>;
} = {},
resolver?: Resolver<Context> | ResolverCreator<Context>;
} & Partial<Parameters<ResolverCreator<Context>>[0]> = {},
) {
const _resolver = options.resolver?.(options.container) ?? (getUmdResolver(options.container as any) as any);

// Set global variables
const proxy = _resolver.context;
if (!proxy.VueDemi) {
proxy.VueDemi = VueDemi;
}
if (options.globals) {
Object.assign(proxy, options.globals);
}
const { resolver, ...resolverOptions } = options;
const _resolver = resolver
? typeof resolver === 'function'
? resolver(resolverOptions)
: resolver
: (createUmdResolver(resolverOptions as any) as Resolver<any>);

const loader: ModuleLoader<Props, Context> = VueDemi.markRaw({
install(app) {
Expand Down
2 changes: 1 addition & 1 deletion packages/module-loader/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ export * from './types';
export * from './globalExtensions';
export { setDebug } from './env';
export { registerSubModules, registerComponents } from './register';
export { defineResolver } from './resolver';
export { defineResolverCreator as defineResolver } from './resolver';
8 changes: 6 additions & 2 deletions packages/module-loader/src/resolver.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import type { GetResolver } from './types';
import type { Resolver, ResolverCreator } from './types';

export function defineResolver<Context>(resolver: GetResolver<Context>): GetResolver<Context> {
export function defineResolverCreator<Context>(resolverCreator: ResolverCreator<Context>): ResolverCreator<Context> {
return resolverCreator;
}

export function defineResolver<Context>(resolver: Resolver<Context>): Resolver<Context> {
return resolver;
}
9 changes: 5 additions & 4 deletions packages/module-loader/src/resolvers/cjs.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import warning from 'warning';
import { debug } from '../env';
import { defineResolver } from '../resolver';
import { defineResolverCreator } from '../resolver';

// Types
import { Context as vmContext } from 'vm';
import { ClientRequest, IncomingMessage } from 'http';

function createSandbox() {
function createSandbox(globalVariables: Record<string, any> = {}) {
const sandbox: Record<string, any> = {
...globalVariables,
Buffer: Buffer,
require: require,
console: console,
Expand Down Expand Up @@ -43,8 +44,8 @@ function tryGetCwd(path: any) {
return cwd;
}

export const getCjsResolver = defineResolver<vmContext>((container) => {
const proxy = createSandbox();
export const createCjsResolver = defineResolverCreator<vmContext>(({ globalVariables }) => {
const proxy = createSandbox(globalVariables);
return {
context: proxy,
execScript(entry) {
Expand Down
141 changes: 72 additions & 69 deletions packages/module-loader/src/resolvers/umd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/
import warning from 'warning';
import { debug } from '../env';
import { defineResolver } from '../resolver';
import { defineResolverCreator } from '../resolver';

const isIE11 = typeof navigator !== 'undefined' && navigator.userAgent.indexOf('Trident') !== -1;

Expand Down Expand Up @@ -70,81 +70,84 @@ function noteGlobalProps(global: WindowProxy) {
const scriptsCache = new Map<string, any>();
const stylesCache = new Map<string, HTMLLinkElement>();

function createSandbox() {
function createSandbox(globalVariables: Record<string, any> = {}) {
// TODO: load in sandbox
const global: WindowProxy = window;
Object.assign(global, globalVariables);
return global;
}

export const getUmdResolver = defineResolver<WindowProxy>((container = (proxy) => proxy.document.body) => {
const proxy = createSandbox();
return {
context: proxy,
execScript(entry) {
if (scriptsCache.has(entry)) return Promise.resolve(scriptsCache.get(entry)); // 从 catch 中获取
export const createUmdResolver = defineResolverCreator<WindowProxy>(
({ container = (proxy) => proxy.document.body, globalVariables }) => {
const proxy = createSandbox(globalVariables);
return {
context: proxy,
execScript(entry) {
if (scriptsCache.has(entry)) return Promise.resolve(scriptsCache.get(entry)); // 从 catch 中获取

const selector = typeof container === 'string' ? proxy.document.querySelector(container) : container(proxy);
if (!selector) {
return Promise.reject(new Error(`[@vue-async/module-loader] The container to append script is not found.`));
}

return new Promise((resolve, reject) => {
noteGlobalProps(proxy);

const script = proxy.document.createElement('script');
script.src = entry;
script.onload = () => {
const propName = getGlobalProp(proxy);
const exports = propName ? proxy[propName] || {} : {};
scriptsCache.set(entry, exports); // add to catch
resolve(exports);
};
script.onerror = (err) => {
warning(!debug, `[@vue-async/module-loader] script had a problem to create, entry:${entry}`);
selector.removeChild(script); // remove script
reject(new Error(`script load error, error: ${err.toString()}`));
};

selector!.appendChild(script);
});
},
async addStyles(styles: string[]) {
if (styles.length) {
const selector = typeof container === 'string' ? proxy.document.querySelector(container) : container(proxy);
if (!selector) {
return Promise.reject(new Error(`[@vue-async/module-loader] The container to append link is not found.`));
return Promise.reject(new Error(`[@vue-async/module-loader] The container to append script is not found.`));
}
await Promise.all(
styles.map((href) => {
if (stylesCache.has(href)) return Promise.resolve(); // 从 catch 中获取

return new Promise<void>((resolve, reject) => {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = href;
link.onload = () => {
stylesCache.set(href, link);
resolve();
};
link.onerror = (err) => {
warning(!debug, `[@vue-async/module-loader] href had a problem to create, href${href}`);
selector.removeChild(link); // remove link
reject(new Error(`style load error, error: ${err.toString()}`));
};
selector.appendChild(link);
});
}),
);
}
},
removeStyles(styles: string[]) {
if (styles.length) {
styles.forEach((href) => {
const link = stylesCache.get(href);
link?.remove();

return new Promise((resolve, reject) => {
noteGlobalProps(proxy);

const script = proxy.document.createElement('script');
script.src = entry;
script.onload = () => {
const propName = getGlobalProp(proxy);
const exports = propName ? proxy[propName] || {} : {};
scriptsCache.set(entry, exports); // add to catch
resolve(exports);
};
script.onerror = (err) => {
warning(!debug, `[@vue-async/module-loader] script had a problem to create, entry:${entry}`);
selector.removeChild(script); // remove script
reject(new Error(`script load error, error: ${err.toString()}`));
};

selector!.appendChild(script);
});
}
},
};
});
},
async addStyles(styles: string[]) {
if (styles.length) {
const selector = typeof container === 'string' ? proxy.document.querySelector(container) : container(proxy);
if (!selector) {
return Promise.reject(new Error(`[@vue-async/module-loader] The container to append link is not found.`));
}
await Promise.all(
styles.map((href) => {
if (stylesCache.has(href)) return Promise.resolve(); // 从 catch 中获取

return new Promise<void>((resolve, reject) => {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = href;
link.onload = () => {
stylesCache.set(href, link);
resolve();
};
link.onerror = (err) => {
warning(!debug, `[@vue-async/module-loader] href had a problem to create, href${href}`);
selector.removeChild(link); // remove link
reject(new Error(`style load error, error: ${err.toString()}`));
};
selector.appendChild(link);
});
}),
);
}
},
removeStyles(styles: string[]) {
if (styles.length) {
styles.forEach((href) => {
const link = stylesCache.get(href);
link?.remove();
});
}
},
};
},
);
56 changes: 32 additions & 24 deletions packages/module-loader/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ export interface ModuleLoader<Props extends Record<string, any> = any, Context =
/**
* Resolver
*/
resolver: ReturnType<GetResolver<Context>> & {
context: Context;
};
resolver: Resolver<Context>;
/**
* App linked to this ModuleLoader instance
* @internal
Expand Down Expand Up @@ -210,32 +208,42 @@ export type Lifecycles = {
export type ErrorHandler = (error: Error, module: InnerRegistrableModule) => void;

/**
* Loader resolver
* Resolver
*/
export interface GetResolver<Context = any> {
export interface Resolver<Context = any> {
/**
* Get resolver
* @param container container to append script, default is append to body in client side
* execution context
*/
(container?: string | ((proxy: Context) => Element)): {
/**
* execution context
*/
context: Context;
/**
* execute script
* @param entry remote script src
*/
execScript<R = unknown>(entry: string): R | Promise<R>;
context: Context;
/**
* execute script
* @param entry remote script src
*/
execScript<R = unknown>(entry: string): R | Promise<R>;
/**
* add styles
* @param styles style href
*/
addStyles(styles: string[]): void | Promise<void>;
/**
* remove styles
* @param styles style href
*/
removeStyles(styles: string[]): void | Promise<void>;
}

export interface ResolverCreator<Context = any> {
/**
* create resolver
*/
(options: {
/**
* add styles
* @param styles style href
* container container to append script, default is append to body in client side
*/
addStyles(styles: string[]): void | Promise<void>;
container?: string | ((proxy: Context) => Element);
/**
* remove styles
* @param styles style href
* global variables to extend to resolver context
*/
removeStyles(styles: string[]): void | Promise<void>;
};
globalVariables?: Record<string, any>;
}): Resolver<Context>;
}

0 comments on commit 26dd24f

Please sign in to comment.