From 26dd24fb5b448e20bc86887e8cd2fd40c6ae9555 Mon Sep 17 00:00:00 2001 From: hubert Date: Fri, 27 Dec 2024 18:14:42 +0800 Subject: [PATCH] perf: context global variables set method change --- packages/module-loader/src/createLoader.ts | 32 ++--- packages/module-loader/src/index.ts | 2 +- packages/module-loader/src/resolver.ts | 8 +- packages/module-loader/src/resolvers/cjs.ts | 9 +- packages/module-loader/src/resolvers/umd.ts | 141 ++++++++++---------- packages/module-loader/src/types.ts | 56 ++++---- 6 files changed, 126 insertions(+), 122 deletions(-) diff --git a/packages/module-loader/src/createLoader.ts b/packages/module-loader/src/createLoader.ts index c76509c..9b0aedf 100644 --- a/packages/module-loader/src/createLoader.ts +++ b/packages/module-loader/src/createLoader.ts @@ -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 @@ -15,27 +15,15 @@ export function createLoader = any, Context = /** * remote module resolver, default to umd resolver */ - resolver?: GetResolver; - /** - * 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; - } = {}, + resolver?: Resolver | ResolverCreator; + } & Partial>[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); const loader: ModuleLoader = VueDemi.markRaw({ install(app) { diff --git a/packages/module-loader/src/index.ts b/packages/module-loader/src/index.ts index cd0d470..e141d9d 100644 --- a/packages/module-loader/src/index.ts +++ b/packages/module-loader/src/index.ts @@ -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'; diff --git a/packages/module-loader/src/resolver.ts b/packages/module-loader/src/resolver.ts index dd1c010..ef5a085 100644 --- a/packages/module-loader/src/resolver.ts +++ b/packages/module-loader/src/resolver.ts @@ -1,5 +1,9 @@ -import type { GetResolver } from './types'; +import type { Resolver, ResolverCreator } from './types'; -export function defineResolver(resolver: GetResolver): GetResolver { +export function defineResolverCreator(resolverCreator: ResolverCreator): ResolverCreator { + return resolverCreator; +} + +export function defineResolver(resolver: Resolver): Resolver { return resolver; } diff --git a/packages/module-loader/src/resolvers/cjs.ts b/packages/module-loader/src/resolvers/cjs.ts index d4a0428..3564edf 100644 --- a/packages/module-loader/src/resolvers/cjs.ts +++ b/packages/module-loader/src/resolvers/cjs.ts @@ -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 = {}) { const sandbox: Record = { + ...globalVariables, Buffer: Buffer, require: require, console: console, @@ -43,8 +44,8 @@ function tryGetCwd(path: any) { return cwd; } -export const getCjsResolver = defineResolver((container) => { - const proxy = createSandbox(); +export const createCjsResolver = defineResolverCreator(({ globalVariables }) => { + const proxy = createSandbox(globalVariables); return { context: proxy, execScript(entry) { diff --git a/packages/module-loader/src/resolvers/umd.ts b/packages/module-loader/src/resolvers/umd.ts index 237f952..5d07d79 100644 --- a/packages/module-loader/src/resolvers/umd.ts +++ b/packages/module-loader/src/resolvers/umd.ts @@ -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; @@ -70,81 +70,84 @@ function noteGlobalProps(global: WindowProxy) { const scriptsCache = new Map(); const stylesCache = new Map(); -function createSandbox() { +function createSandbox(globalVariables: Record = {}) { // TODO: load in sandbox const global: WindowProxy = window; + Object.assign(global, globalVariables); return global; } -export const getUmdResolver = defineResolver((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( + ({ 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((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((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(); + }); + } + }, + }; + }, +); diff --git a/packages/module-loader/src/types.ts b/packages/module-loader/src/types.ts index 199c6ef..fae8405 100644 --- a/packages/module-loader/src/types.ts +++ b/packages/module-loader/src/types.ts @@ -16,9 +16,7 @@ export interface ModuleLoader = any, Context = /** * Resolver */ - resolver: ReturnType> & { - context: Context; - }; + resolver: Resolver; /** * App linked to this ModuleLoader instance * @internal @@ -210,32 +208,42 @@ export type Lifecycles = { export type ErrorHandler = (error: Error, module: InnerRegistrableModule) => void; /** - * Loader resolver + * Resolver */ -export interface GetResolver { +export interface Resolver { /** - * 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(entry: string): R | Promise; + context: Context; + /** + * execute script + * @param entry remote script src + */ + execScript(entry: string): R | Promise; + /** + * add styles + * @param styles style href + */ + addStyles(styles: string[]): void | Promise; + /** + * remove styles + * @param styles style href + */ + removeStyles(styles: string[]): void | Promise; +} + +export interface ResolverCreator { + /** + * 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; + container?: string | ((proxy: Context) => Element); /** - * remove styles - * @param styles style href + * global variables to extend to resolver context */ - removeStyles(styles: string[]): void | Promise; - }; + globalVariables?: Record; + }): Resolver; }