Skip to content

Commit

Permalink
fix: loadScriptsOnMainThread breaks when using a regexp
Browse files Browse the repository at this point in the history
  • Loading branch information
franpeza committed Jan 27, 2024
1 parent 02de842 commit b849e99
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 34 deletions.
2 changes: 2 additions & 0 deletions src/integration/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export { SCRIPT_TYPE } from '../lib/utils';
export type {
PartytownConfig,
PartytownForwardProperty,
PartytownForwardPropertyWithSettings,
PartytownForwardPropertySettings,
ApplyHook,
GetHook,
SetHook,
Expand Down
11 changes: 2 additions & 9 deletions src/integration/snippet.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
import { serializeConfig } from '../lib/utils';
import type { PartytownConfig } from '../lib/types';

export const createSnippet = (config: PartytownConfig | undefined | null, snippetCode: string) => {
const { forward = [], ...filteredConfig } = config || {};

const configStr = JSON.stringify(filteredConfig, (k, v) => {
if (typeof v === 'function') {
v = String(v);
if (v.startsWith(k + '(')) {
v = 'function ' + v;
}
}
return v;
});
const configStr = serializeConfig(filteredConfig);

return [
`!(function(w,p,f,c){`,
Expand Down
11 changes: 2 additions & 9 deletions src/lib/sandbox/read-main-platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
isValidMemberName,
len,
noop,
serializeConfig,
} from '../utils';
import { config, docImpl, libPath, mainWindow } from './main-globals';
import {
Expand Down Expand Up @@ -61,15 +62,7 @@ export const readMainPlatform = () => {
readImplementation('Node', textNode),
];

const $config$ = JSON.stringify(config, (k, v) => {
if (typeof v === 'function') {
v = String(v);
if (v.startsWith(k + '(')) {
v = 'function ' + v;
}
}
return v;
});
const $config$ = serializeConfig(config);

const initWebWorkerData: InitWebWorkerData = {
$config$,
Expand Down
7 changes: 6 additions & 1 deletion src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export type InterfaceMember =

export interface WebWorkerContext {
$asyncMsgTimer$?: any;
$config$: PartytownConfig;
$config$: PartytownInternalConfig;
$importScripts$: (...urls: string[]) => void;
$initWindowMedia$?: InitWindowMedia;
$interfaces$: InterfaceInfo[];
Expand Down Expand Up @@ -522,6 +522,10 @@ export interface PartytownConfig {
nonce?: string;
}

export type PartytownInternalConfig = Omit<PartytownConfig, 'loadScriptsOnMainThread'> & {
loadScriptsOnMainThread?: ['regexp' | 'string', string][];
};

export type PartytownForwardPropertySettings = {
preserveBehavior?: boolean;
};
Expand Down Expand Up @@ -715,6 +719,7 @@ export interface WorkerInstance {
}

export interface WorkerNode extends WorkerInstance, Node {
id?: string | undefined | null;
type: string | undefined;
}

Expand Down
41 changes: 41 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import type {
ApplyPath,
MainWindow,
PartytownConfig,
PartytownForwardProperty,
PartytownForwardPropertySettings,
PartytownForwardPropertyWithSettings,
PartytownInternalConfig,
RandomId,
StringIndexable,
} from './types';
Expand Down Expand Up @@ -205,3 +207,42 @@ export const emptyObjectValue = (propertyName: string): [] | {} => {

return {};
};

function escapeRegExp(input: string) {
return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

export function testIfMustLoadScriptOnMainThread(
config: PartytownInternalConfig,
value: string
): boolean {
return (
config.loadScriptsOnMainThread
?.map(([type, value]) => new RegExp(type === 'string' ? escapeRegExp(value) : value))
.some((regexp) => regexp.test(value)) ?? false
);
}

export function serializeConfig(config: PartytownConfig) {
return JSON.stringify(config, (key, value) => {
if (typeof value === 'function') {
value = String(value);
if (value.startsWith(key + '(')) {
value = 'function ' + value;
}
}
if (key === 'loadScriptsOnMainThread') {
value = (
value as Required<PartytownConfig | PartytownInternalConfig>['loadScriptsOnMainThread']
).map((scriptUrl) =>
Array.isArray(scriptUrl)
? scriptUrl
: [
typeof scriptUrl === 'string' ? 'string' : 'regexp',
typeof scriptUrl === 'string' ? scriptUrl : scriptUrl.source,
]
) satisfies Required<PartytownInternalConfig>['loadScriptsOnMainThread'];
}
return value;
});
}
17 changes: 10 additions & 7 deletions src/lib/web-worker/init-web-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import {
webWorkerlocalStorage,
webWorkerSessionStorage,
} from './worker-constants';
import type { InitWebWorkerData } from '../types';
import type { PartytownConfig } from '@builder.io/partytown/integration';
import type { InitWebWorkerData, PartytownInternalConfig } from '../types';

export const initWebWorker = (initWebWorkerData: InitWebWorkerData) => {
const config: PartytownConfig = (webWorkerCtx.$config$ = JSON.parse(initWebWorkerData.$config$));
const config: PartytownInternalConfig = (webWorkerCtx.$config$ = JSON.parse(
initWebWorkerData.$config$
));
const locOrigin = initWebWorkerData.$origin$;
webWorkerCtx.$importScripts$ = importScripts.bind(self);
webWorkerCtx.$interfaces$ = initWebWorkerData.$interfaces$;
Expand All @@ -24,9 +25,11 @@ export const initWebWorker = (initWebWorkerData: InitWebWorkerData) => {
delete (self as any).postMessage;
delete (self as any).WorkerGlobalScope;

(commaSplit('resolveUrl,get,set,apply') as any).map((configName: keyof PartytownConfig) => {
if (config[configName]) {
config[configName] = new Function('return ' + config[configName])();
(commaSplit('resolveUrl,get,set,apply') as any).map(
(configName: keyof PartytownInternalConfig) => {
if (config[configName]) {
config[configName] = new Function('return ' + config[configName])();
}
}
});
);
};
9 changes: 7 additions & 2 deletions src/lib/web-worker/worker-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ import {
webWorkerCtx,
WinIdKey,
} from './worker-constants';
import { defineConstructorName, SCRIPT_TYPE, SCRIPT_TYPE_EXEC } from '../utils';
import {
defineConstructorName,
SCRIPT_TYPE,
SCRIPT_TYPE_EXEC,
testIfMustLoadScriptOnMainThread,
} from '../utils';
import { getInstanceStateValue } from './worker-state';
import { insertIframe, runScriptContent } from './worker-exec';
import { isScriptJsType } from './worker-script';
Expand Down Expand Up @@ -59,7 +64,7 @@ export const createNodeCstr = (
// @ts-ignore
const scriptId = newNode.id;
const loadOnMainThread =
scriptId && config.loadScriptsOnMainThread?.includes?.(scriptId);
scriptId && testIfMustLoadScriptOnMainThread(config, scriptId);

if (loadOnMainThread) {
setter(newNode, ['type'], 'text/javascript');
Expand Down
8 changes: 3 additions & 5 deletions src/lib/web-worker/worker-script.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { definePrototypePropertyDescriptor } from '../utils';
import { definePrototypePropertyDescriptor, testIfMustLoadScriptOnMainThread } from '../utils';
import { getInstanceStateValue, setInstanceStateValue } from './worker-state';
import { getter, setter } from './worker-proxy';
import { HTMLSrcElementDescriptorMap } from './worker-src-element';
Expand Down Expand Up @@ -26,10 +26,8 @@ export const patchHTMLScriptElement = (WorkerHTMLScriptElement: any, env: WebWor
setter(this, ['dataset', 'ptsrc'], orgUrl);
}

if (this.type && config.loadScriptsOnMainThread) {
const shouldExecuteScriptViaMainThread = config.loadScriptsOnMainThread.some(
(scriptUrl) => new RegExp(scriptUrl).test(url)
);
if (this.type) {
const shouldExecuteScriptViaMainThread = testIfMustLoadScriptOnMainThread(config, url);

if (shouldExecuteScriptViaMainThread) {
setter(this, ['type'], 'text/javascript');
Expand Down
3 changes: 2 additions & 1 deletion tests/unit/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { suite as uvuSuite } from 'uvu';
import type {
MainWindow,
PartytownConfig,
PartytownInternalConfig,
PartytownWebWorker,
WebWorkerEnvironment,
WinId,
Expand Down Expand Up @@ -73,7 +74,7 @@ export interface TestContext {
location: Location;
loc: any;
worker: TestWorker;
config: PartytownConfig;
config: PartytownInternalConfig;
env: WebWorkerEnvironment;
snippetCode: string;
run: (code: string) => any;
Expand Down

0 comments on commit b849e99

Please sign in to comment.