|
| 1 | +// packages/wordpress-wasm/src/index.js |
| 2 | +import { |
| 3 | + postMessageExpectReply, |
| 4 | + awaitReply, |
| 5 | + responseTo, |
| 6 | + registerServiceWorker, |
| 7 | + startPHPWorkerThread, |
| 8 | + getWorkerThreadBackend |
| 9 | +} from "php-wasm-browser"; |
| 10 | + |
| 11 | +// packages/wordpress-wasm/src/config.js |
| 12 | +import { phpJsHash } from "php-wasm"; |
| 13 | +import { phpJsHash as phpJsHash2 } from "php-wasm"; |
| 14 | +var serviceWorkerUrl = "http://127.0.0.1:8777/service-worker.js"; |
| 15 | +var serviceWorkerOrigin = new URL(serviceWorkerUrl).origin; |
| 16 | +var wordPressSiteUrl = serviceWorkerOrigin; |
| 17 | +var wasmWorkerUrl = "http://127.0.0.1:8778/iframe-worker.html?0891786456959600"; |
| 18 | +var wasmWorkerBackend = "iframe"; |
| 19 | + |
| 20 | +// packages/wordpress-wasm/src/index.js |
| 21 | +async function bootWordPress({ |
| 22 | + assignScope = true, |
| 23 | + onWasmDownloadProgress |
| 24 | +}) { |
| 25 | + assertNotInfiniteLoadingLoop(); |
| 26 | + const scope = assignScope ? Math.random().toFixed(16) : void 0; |
| 27 | + const workerThread = await startPHPWorkerThread({ |
| 28 | + backend: getWorkerThreadBackend(wasmWorkerBackend, wasmWorkerUrl), |
| 29 | + absoluteUrl: wordPressSiteUrl, |
| 30 | + scope, |
| 31 | + onDownloadProgress: onWasmDownloadProgress |
| 32 | + }); |
| 33 | + await registerServiceWorker({ |
| 34 | + url: serviceWorkerUrl, |
| 35 | + broadcastChannel: new BroadcastChannel("wordpress-wasm"), |
| 36 | + onRequest: async (request) => { |
| 37 | + return await workerThread.HTTPRequest(request); |
| 38 | + }, |
| 39 | + scope |
| 40 | + }); |
| 41 | + return workerThread; |
| 42 | +} |
| 43 | +function assertNotInfiniteLoadingLoop() { |
| 44 | + let isBrowserInABrowser = false; |
| 45 | + try { |
| 46 | + isBrowserInABrowser = window.parent !== window && window.parent.IS_WASM_WORDPRESS; |
| 47 | + } catch (e) { |
| 48 | + } |
| 49 | + if (isBrowserInABrowser) { |
| 50 | + throw new Error( |
| 51 | + "The service worker did not load correctly. This is a bug, please report it on https://github.com/WordPress/wordpress-wasm/issues" |
| 52 | + ); |
| 53 | + } |
| 54 | + window.IS_WASM_WORDPRESS = true; |
| 55 | +} |
| 56 | + |
| 57 | +// packages/wordpress-wasm/src/macros.js |
| 58 | +async function login(workerThread, user = "admin", password = "password") { |
| 59 | + await workerThread.HTTPRequest({ |
| 60 | + path: workerThread.pathToInternalUrl("/wp-login.php") |
| 61 | + }); |
| 62 | + await workerThread.HTTPRequest({ |
| 63 | + path: workerThread.pathToInternalUrl("/wp-login.php"), |
| 64 | + method: "POST", |
| 65 | + _POST: { |
| 66 | + log: user, |
| 67 | + pwd: password, |
| 68 | + rememberme: "forever" |
| 69 | + } |
| 70 | + }); |
| 71 | +} |
| 72 | +async function installPlugin(workerThread, pluginZipFile, options = {}) { |
| 73 | + options = { |
| 74 | + activate: true, |
| 75 | + ...options |
| 76 | + }; |
| 77 | + const pluginForm = await workerThread.HTTPRequest({ |
| 78 | + path: workerThread.pathToInternalUrl("/wp-admin/plugin-install.php?tab=upload") |
| 79 | + }); |
| 80 | + const pluginFormPage = new DOMParser().parseFromString(pluginForm.body, "text/html"); |
| 81 | + const pluginFormData = new FormData(pluginFormPage.querySelector(".wp-upload-form")); |
| 82 | + const { pluginzip, ...postData } = Object.fromEntries(pluginFormData.entries()); |
| 83 | + if (options.activate) { |
| 84 | + const pluginInstalledResponse = await workerThread.HTTPRequest({ |
| 85 | + path: workerThread.pathToInternalUrl("/wp-admin/update.php?action=upload-plugin"), |
| 86 | + method: "POST", |
| 87 | + _POST: postData, |
| 88 | + files: { pluginzip: pluginZipFile } |
| 89 | + }); |
| 90 | + const pluginInstalledPage = new DOMParser().parseFromString(pluginInstalledResponse.body, "text/html"); |
| 91 | + const activateButtonHref = pluginInstalledPage.querySelector("#wpbody-content .button.button-primary").attributes.href.value; |
| 92 | + const activatePluginUrl = new URL( |
| 93 | + activateButtonHref, |
| 94 | + workerThread.pathToInternalUrl("/wp-admin/") |
| 95 | + ).toString(); |
| 96 | + await workerThread.HTTPRequest({ |
| 97 | + path: activatePluginUrl |
| 98 | + }); |
| 99 | + } |
| 100 | +} |
| 101 | + |
| 102 | +// packages/wordpress-wasm/src/example-app.js |
| 103 | +import { cloneResponseMonitorProgress, postMessageHandler } from "php-wasm-browser"; |
| 104 | +function setupAddressBar(wasmWorker) { |
| 105 | + const addressBar = document.querySelector("#address-bar"); |
| 106 | + wpFrame.addEventListener("load", (e) => { |
| 107 | + addressBar.value = wasmWorker.internalUrlToPath( |
| 108 | + e.currentTarget.contentWindow.location.href |
| 109 | + ); |
| 110 | + }); |
| 111 | + document.querySelector("#address-bar-form").addEventListener("submit", (e) => { |
| 112 | + e.preventDefault(); |
| 113 | + let requestedPath = addressBar.value; |
| 114 | + const isDirectory = !requestedPath.split("/").pop().includes("."); |
| 115 | + if (isDirectory && !requestedPath.endsWith("/")) { |
| 116 | + requestedPath += "/"; |
| 117 | + } |
| 118 | + wpFrame.src = wasmWorker.pathToInternalUrl( |
| 119 | + requestedPath |
| 120 | + ); |
| 121 | + }); |
| 122 | +} |
| 123 | +var FetchProgressBar = class { |
| 124 | + constructor({ |
| 125 | + expectedRequests, |
| 126 | + min = 0, |
| 127 | + max = 100 |
| 128 | + }) { |
| 129 | + this.expectedRequests = expectedRequests; |
| 130 | + this.progress = {}; |
| 131 | + this.min = min; |
| 132 | + this.max = max; |
| 133 | + this.el = document.querySelector(".progress-bar.is-finite"); |
| 134 | + const wpFrame2 = document.querySelector("#wp"); |
| 135 | + const hideProgressBar = () => { |
| 136 | + document.querySelector("body.is-loading").classList.remove("is-loading"); |
| 137 | + wpFrame2.removeEventListener("load", hideProgressBar); |
| 138 | + }; |
| 139 | + wpFrame2.addEventListener("load", hideProgressBar); |
| 140 | + } |
| 141 | + onDataChunk = ({ file, loaded, total }) => { |
| 142 | + if (Object.keys(this.progress).length === 0) { |
| 143 | + this.setFinite(); |
| 144 | + } |
| 145 | + this.progress[file] = loaded / total; |
| 146 | + const progressSum = Object.entries(this.progress).reduce( |
| 147 | + (acc, [_, percentFinished]) => acc + percentFinished, |
| 148 | + 0 |
| 149 | + ); |
| 150 | + const totalProgress = Math.min(1, progressSum / this.expectedRequests); |
| 151 | + const scaledProgressPercentage = this.min + (this.max - this.min) * totalProgress; |
| 152 | + this.setProgress(scaledProgressPercentage); |
| 153 | + }; |
| 154 | + setProgress(percent) { |
| 155 | + this.el.style.width = `${percent}%`; |
| 156 | + } |
| 157 | + setFinite() { |
| 158 | + const classList = document.querySelector( |
| 159 | + ".progress-bar-wrapper.mode-infinite" |
| 160 | + ).classList; |
| 161 | + classList.remove("mode-infinite"); |
| 162 | + classList.add("mode-finite"); |
| 163 | + } |
| 164 | +}; |
| 165 | +var wpFrame = document.querySelector("#wp"); |
| 166 | +async function main() { |
| 167 | + const preinstallPlugin = query.get("plugin"); |
| 168 | + let progressBar; |
| 169 | + let pluginResponse; |
| 170 | + if (preinstallPlugin) { |
| 171 | + pluginResponse = await fetch("/plugin-proxy?plugin=" + preinstallPlugin); |
| 172 | + progressBar = new FetchProgressBar({ |
| 173 | + expectedRequests: 3, |
| 174 | + max: 80 |
| 175 | + }); |
| 176 | + } else { |
| 177 | + progressBar = new FetchProgressBar({ expectedRequests: 2 }); |
| 178 | + } |
| 179 | + const workerThread = await bootWordPress({ |
| 180 | + onWasmDownloadProgress: progressBar.onDataChunk |
| 181 | + }); |
| 182 | + if (appMode === "browser") { |
| 183 | + setupAddressBar(workerThread); |
| 184 | + } |
| 185 | + if (preinstallPlugin) { |
| 186 | + const progressPluginResponse = cloneResponseMonitorProgress( |
| 187 | + pluginResponse, |
| 188 | + (progress) => progressBar.onDataChunk({ file: preinstallPlugin, ...progress }) |
| 189 | + ); |
| 190 | + const blob = await progressPluginResponse.blob(); |
| 191 | + const pluginFile = new File([blob], preinstallPlugin); |
| 192 | + progressBar.el.classList.add("indeterminate"); |
| 193 | + progressBar.setProgress(80); |
| 194 | + progressBar.setProgress(85); |
| 195 | + await login(workerThread, "admin", "password"); |
| 196 | + progressBar.setProgress(100); |
| 197 | + await installPlugin(workerThread, pluginFile); |
| 198 | + } |
| 199 | + if (query.get("rpc")) { |
| 200 | + console.log("Registering an RPC handler"); |
| 201 | + window.addEventListener("message", postMessageHandler(async (data) => { |
| 202 | + if (data.type === "rpc") { |
| 203 | + return await workerThread[data.method](...data.args); |
| 204 | + } else if (data.type === "go_to") { |
| 205 | + wpFrame.src = workerThread.pathToInternalUrl(data.path); |
| 206 | + } else if (data.type === "is_alive") { |
| 207 | + return true; |
| 208 | + } |
| 209 | + })); |
| 210 | + } |
| 211 | + const initialUrl = query.get("url") || "/"; |
| 212 | + wpFrame.src = workerThread.pathToInternalUrl(initialUrl); |
| 213 | +} |
| 214 | +main(); |
0 commit comments