forked from WordPress/playground-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Playground Public API (WordPress#149)
## Description With this PR, Playground exposes a consistent communication layer for its consumers: ```ts const playground = connect( iframe.contentWindow ); playground.writeFile( '/wordpress/test.php', 'Hello, world!' ); playground.goTo( '/test.php' ); ``` It means **your app can have the same powers as the official demo**. Just note this PR does not expose any public packages yet. That will be the next step. ## Under the hood Technically, this PR: 1. Formalizes `php-wasm` public API 2. Formalizes Playground public API as an extension of the above 3. Uses the [comlink](https://github.com/GoogleChromeLabs/comlink) library to expose Playground's public API There are a few layers to this: * Playground worker initializes the PHP and WordPress and exposes an internal API using comlink * Playground "connector" HTML page consumes the worker API, extends it, and re-exposes it publicly using comlink * Playground UI is now a separate app that connects to the "connector" page and consumes its API using comlink All the public-facing features, like plugin pre-installation or import/export, are now implemented by consuming the public API. Once I [publish these features in npm](WordPress/wordpress-playground#147), consuming Playground will be as simple as importing a package. This PR also refactors the Playground website to use React – this process was indispensable in shaping the public API. ## Public API Here's the raw interface – the documentation will be shipped with the npm package and provided in this repo. ```ts interface PlaygroundAPI { absoluteUrl: string; goTo(requestedPath: string): Promise<void>; getCurrentURL(): Promise<void>; setIframeSandboxFlags(flags: string[]): Promise<void>; onNavigation(callback: (newURL: string) => void): Promise<void>; onDownloadProgress( callback: (progress: CustomEvent<ProgressEvent>) => void ): Promise<void>; getWordPressModuleDetails(): Promise<{ staticAssetsDirectory: string; defaultTheme: string; }>; pathToInternalUrl(path: string): Promise<string>; internalUrlToPath(internalUrl: string): Promise<string>; request( request: PHPServerRequest, redirects?: number ): Promise<PHPResponse>; run(request?: PHPRequest | undefined): Promise<PHPResponse>; setPhpIniPath(path: string): Promise<void>; setPhpIniEntry(key: string, value: string): Promise<void>; mkdirTree(path: string): Promise<void>; readFileAsText(path: string): Promise<string>; readFileAsBuffer(path: string): Promise<Uint8Array>; writeFile(path: string, data: string | Uint8Array): Promise<void>; unlink(path: string): Promise<void>; listFiles(path: string): Promise<string[]>; isDir(path: string): Promise<boolean>; fileExists(path: string): Promise<boolean>; } ```
- Loading branch information
Showing
89 changed files
with
4,148 additions
and
3,274 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import Comlink from 'comlink'; | ||
|
||
export function consumeAPI<APIType>(remote: Worker | Window) { | ||
setupTransferHandlers(); | ||
|
||
const endpoint = | ||
remote instanceof Worker ? remote : Comlink.windowEndpoint(remote); | ||
|
||
return Comlink.wrap<APIType>(endpoint); | ||
} | ||
|
||
type PublicAPI<Methods, PipedAPI> = Methods & PipedAPI & { isReady: () => Promise<void> }; | ||
export function exposeAPI<Methods, PipedAPI>(apiMethods?: Methods, pipedApi?: PipedAPI): | ||
[() => void, PublicAPI<Methods, PipedAPI>] | ||
{ | ||
setupTransferHandlers(); | ||
|
||
let setReady; | ||
const ready = new Promise((resolve) => { | ||
setReady = resolve; | ||
}); | ||
|
||
const methods = proxyClone(apiMethods); | ||
const exposedApi = new Proxy(methods, { | ||
get: (target, prop) => { | ||
if (prop === 'isReady') { | ||
return () => ready; | ||
} | ||
if (prop in target) { | ||
return target[prop]; | ||
} | ||
return pipedApi?.[prop]; | ||
}, | ||
}) as unknown as PublicAPI<Methods, PipedAPI>; | ||
|
||
Comlink.expose( | ||
exposedApi, | ||
typeof window !== 'undefined' | ||
? Comlink.windowEndpoint(self.parent) | ||
: undefined | ||
); | ||
return [ | ||
setReady, | ||
exposedApi, | ||
]; | ||
} | ||
|
||
function setupTransferHandlers() { | ||
Comlink.transferHandlers.set('EVENT', { | ||
canHandle: (obj): obj is CustomEvent => obj instanceof CustomEvent, | ||
serialize: (ev: CustomEvent) => { | ||
return [ | ||
{ | ||
detail: ev.detail, | ||
}, | ||
[], | ||
]; | ||
}, | ||
deserialize: (obj) => obj, | ||
}); | ||
Comlink.transferHandlers.set('FUNCTION', { | ||
canHandle: (obj: unknown): obj is Function => typeof obj === 'function', | ||
serialize(obj: Function) { | ||
console.debug('[Comlink][Performance] Proxying a function'); | ||
const { port1, port2 } = new MessageChannel(); | ||
Comlink.expose(obj, port1); | ||
return [port2, [port2]]; | ||
}, | ||
deserialize(port: any) { | ||
port.start(); | ||
return Comlink.wrap(port); | ||
}, | ||
}); | ||
} | ||
|
||
function proxyClone(object: any) { | ||
return new Proxy(object, { | ||
get(target, prop) { | ||
switch (typeof target[prop]) { | ||
case 'function': | ||
return (...args) => target[prop](...args); | ||
case 'object': | ||
if (target[prop] === null) { | ||
return target[prop]; | ||
} | ||
return proxyClone(target[prop]); | ||
case 'undefined': | ||
case 'number': | ||
case 'string': | ||
return target[prop]; | ||
default: | ||
return Comlink.proxy(target[prop]); | ||
} | ||
}, | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.