Skip to content

Worker boot: Parallelize WP.zip and PHP.wasm download #1668

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
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
28 changes: 18 additions & 10 deletions packages/php-wasm/progress/src/lib/emscripten-download-monitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,16 @@ export class EmscriptenDownloadMonitor extends EventTarget {
async monitorFetch(fetchPromise: Promise<Response>): Promise<Response> {
const response = await fetchPromise;
const onProgress = (event: CustomEvent<DownloadProgress>) => {
this.#notify(response.url, event.detail.loaded, event.detail.total);
this.#setFileProgress(
response.url,
event.detail.loaded,
event.detail.total
);
this.dispatchEvent(
new CustomEvent('progress', {
detail: this.progress,
})
);
};
return cloneResponseMonitorProgress(response, onProgress);
}
Expand All @@ -62,7 +71,7 @@ export class EmscriptenDownloadMonitor extends EventTarget {
* @param loaded The number of bytes of that file loaded so far.
* @param fileSize The total number of bytes in the loaded file.
*/
#notify(file: string, loaded: number, fileSize: number) {
#setFileProgress(file: string, loaded: number, fileSize: number) {
const fileName = new URL(file, 'http://example.com').pathname
.split('/')
.pop()!;
Expand All @@ -81,14 +90,13 @@ export class EmscriptenDownloadMonitor extends EventTarget {
}

this.#progress[fileName] = loaded;
this.dispatchEvent(
new CustomEvent('progress', {
detail: {
loaded: sumValues(this.#progress),
total: sumValues(this.#assetsSizes),
},
})
);
}

get progress() {
return {
loaded: sumValues(this.#progress),
total: sumValues(this.#assetsSizes),
};
}
}

Expand Down
21 changes: 9 additions & 12 deletions packages/php-wasm/progress/src/lib/progress-tracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@ export interface ProgressTrackerOptions {
fillTime?: number;
}

/**
* Custom event providing information about a loading process.
*/
export type LoadingEvent = CustomEvent<{
export type LoadingProgress = {
/** The number representing how much was loaded. */
loaded: number;
/** The number representing how much needs to loaded in total. */
total: number;
}>;
};

/**
* Custom event providing information about a loading process.
*/
export type LoadingEvent = CustomEvent<LoadingProgress>;

/**
* Custom event providing progress details.
Expand Down Expand Up @@ -286,13 +288,8 @@ export class ProgressTracker extends EventTarget {
return this._progressObserver;
}

get loadingListener() {
if (!this._loadingListener) {
this._loadingListener = (event: LoadingEvent) => {
this.set((event.detail.loaded / event.detail.total) * 100);
};
}
return this._loadingListener;
setFromProgressDetails(details: LoadingProgress) {
this.set((details.loaded / details.total) * 100);
}

pipe(receiver: ProgressReceiver) {
Expand Down
6 changes: 5 additions & 1 deletion packages/php-wasm/universal/src/lib/php-worker.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { EmscriptenDownloadMonitor } from '@php-wasm/progress';
import { EmscriptenDownloadMonitor, LoadingProgress } from '@php-wasm/progress';
import { PHP } from './php';
import { PHPRequestHandler } from './php-request-handler';
import { PHPResponse } from './php-response';
Expand Down Expand Up @@ -129,6 +129,10 @@ export class PHPWorker implements LimitedPHPApi {
.requestHandler!.internalUrlToPath(internalUrl);
}

async getDownloadProgress(): Promise<LoadingProgress | undefined> {
return _private.get(this)!.monitor?.progress;
}

/**
* The onDownloadProgress event listener.
*/
Expand Down
4 changes: 3 additions & 1 deletion packages/playground/blueprints/src/lib/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,9 @@ export abstract class FetchResource extends Resource {
}
response = await cloneResponseMonitorProgress(
response,
this.progress?.loadingListener ?? noop
this.progress
? (e) => this.progress?.setFromProgressDetails(e.detail)
: noop
);
if (response.status !== 200) {
throw new Error(`Could not download "${url}"`);
Expand Down
6 changes: 5 additions & 1 deletion packages/playground/client/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,12 @@ async function doStartPlaygroundWeb(
) as PlaygroundClient;
await playground.isConnected();
progressTracker.pipe(playground);
const currentProgress = (await playground.getDownloadProgress())!;
const downloadPHPandWP = progressTracker.stage();
await playground.onDownloadProgress(downloadPHPandWP.loadingListener);
downloadPHPandWP.setFromProgressDetails(currentProgress);
await playground.onDownloadProgress((e) => {
downloadPHPandWP.setFromProgressDetails(e.detail);
});
await playground.isReady();
downloadPHPandWP.finish();
return playground;
Expand Down
21 changes: 11 additions & 10 deletions packages/playground/remote/src/lib/worker-thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,21 +366,22 @@ try {
LOGGED_IN_SALT: randomString(40),
NONCE_SALT: randomString(40),
};
const wordPressZip = wordPressAvailableInOPFS
? undefined
: new File([await (await wordPressRequest!).blob()], 'wp.zip');

const sqliteIntegrationPluginZip = new File(
[await (await sqliteIntegrationRequest).blob()],
'sqlite.zip'
);

const knownRemoteAssetPaths = new Set<string>();
const requestHandler = await bootWordPress({
siteUrl: setURLScope(wordPressSiteUrl, scope).toString(),
createPhpRuntime,
wordPressZip,
sqliteIntegrationPluginZip,
// Do not await the WordPress download or the sqlite integration download.
// Let bootWordPress start the PHP runtime download first, and then await
// all the ZIP files right before they're used.
wordPressZip: wordPressAvailableInOPFS
? undefined
: wordPressRequest!
.then((r) => r.blob())
.then((b) => new File([b], 'wp.zip')),
sqliteIntegrationPluginZip: sqliteIntegrationRequest
.then((r) => r.blob())
.then((b) => new File([b], 'sqlite.zip')),
spawnHandler: spawnHandlerFactory,
sapiName: startupOptions.sapiName,
constants,
Expand Down
Loading