Skip to content

Commit

Permalink
Support WordPress beta and RC versions (#709)
Browse files Browse the repository at this point in the history
## Description

This pull request introduces support for WordPress beta and Release
Candidate (RC) versions in the WordPress Playground.

Closes #500.
Closes #501.
Closes #306.

## Changes

* The Dockerfile has been updated to automatically detect and keep the
default theme for each WordPress release.
* Several updates to the build scripts and JSON files have been made to
support these changes.
* The Blueprints no longer rely on a hardcoded list of supported
WordPress versions. Instead, this PR introduces a new method where
`remote.html` tells the client which versions it supports. This reduces
coupling – the same client can work with different remotes.

## Testing instructions

1. Run `npx nx recompile-wordpress:all playground-remote`
2. Verify that the Playground successfully builds the latest 4 major
WordPress versions and beta and nightly
3. Confirm the local Playground UI works well and allows switching
between the different WordPress versions
  • Loading branch information
adamziel authored Oct 18, 2023
1 parent c7e11dc commit a4d8b26
Show file tree
Hide file tree
Showing 20 changed files with 114,869 additions and 489 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ The [web bundler Dockerfile](https://github.com/WordPress/wordpress-playground/b
- Runs the WordPress installation wizard.
- Bundles WordPress as a [data dependency](./06-wasm-php-data-dependencies.md)

Build a new bundle with `nx recompile-wordpress playground-remote --preset=<version>`, e.g.:
Build a new bundle with `nx recompile-wordpress playground-remote --wp-version=<version>`, e.g.:

```
nx recompile-wordpress playground-remote --preset=6.1
nx recompile-wordpress playground-remote --wp-version=6.1
```

The bundler outputs:
Expand Down
17 changes: 2 additions & 15 deletions packages/playground/blueprints/src/lib/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,11 @@ import type { ValidateFunction } from 'ajv';

export type CompiledStep = (php: UniversalPHP) => Promise<void> | void;

const supportedWordPressVersions = [
'6.3',
'6.2',
'6.1',
'6.0',
'5.9',
'nightly',
] as const;
type supportedWordPressVersion = (typeof supportedWordPressVersions)[number];
export interface CompiledBlueprint {
/** The requested versions of PHP and WordPress for the blueprint */
versions: {
php: SupportedPHPVersion;
wp: supportedWordPressVersion;
wp: string;
};
/** The requested PHP extensions to load */
phpExtensions: SupportedPHPExtension[];
Expand Down Expand Up @@ -116,11 +107,7 @@ export function compileBlueprint(
SupportedPHPVersions,
LatestSupportedPHPVersion
),
wp: compileVersion(
blueprint.preferredVersions?.wp,
supportedWordPressVersions,
'6.3'
),
wp: blueprint.preferredVersions?.wp || 'latest',
},
phpExtensions: compilePHPExtensions(
[],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,6 @@ export async function makeEditorFrameControlled(
if (!(await php.fileExists(filePath))) {
continue;
}

await updateFile(
php,
filePath,
Expand Down
10 changes: 5 additions & 5 deletions packages/playground/compile-wordpress/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ ENV WP_ZIP_URL ${WP_ZIP_URL}
ARG OUT_FILENAME=wp
ENV OUT_FILENAME ${OUT_FILENAME}

ARG KEEP_THEME
ENV KEEP_THEME ${KEEP_THEME}

RUN mkdir /root/output

RUN set -euxo pipefail;\
Expand Down Expand Up @@ -50,7 +47,11 @@ RUN mv wordpress-static/* /root/output/$OUT_FILENAME/
# === Minify WordPress ===

# Remove non-default themes
RUN cd wordpress/wp-content/themes && \

RUN cat wordpress/wp-includes/default-constants.php | awk -F"'" "/define\( 'WP_DEFAULT_THEME'/"'{print $4}' > wordpress/.default_theme

RUN export KEEP_THEME=$(cat wordpress/.default_theme); \
cd wordpress/wp-content/themes && \
rm -r $(ls | grep -v $KEEP_THEME)

# Remove unused static files
Expand Down Expand Up @@ -186,7 +187,6 @@ RUN cp /root/esm-prefix.js /tmp/esm-prefix.js && \
export FILE_SIZE=$(stat -c%s "/root/output/$OUT_FILENAME.data") && \
cat /tmp/esm-prefix.js \
| sed "s#WP_DATA_SIZE#$FILE_SIZE#g" \
| sed "s#WP_THEME_NAME#'$KEEP_THEME'#g" \
> /root/esm-prefix.js

# Filename of the main dependency
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ export const dependenciesTotalSize = WP_DATA_SIZE;
import dependencyFilename from './WP_DATA_FILENAME?url';
export { dependencyFilename };

// The default theme name – populated by Dockerfile.
export const defaultThemeName = WP_THEME_NAME;

// Prepending this to the built php.js file manually turns it
// into an ESM module.
// This replaces the Emscripten's MODULARIZE=1 which pollutes the
Expand Down
194 changes: 127 additions & 67 deletions packages/playground/compile-wordpress/build.js
Original file line number Diff line number Diff line change
@@ -1,59 +1,16 @@
import path from 'path';
import { spawn } from 'child_process';
import yargs from 'yargs';

const presets = {
6.3: {
KEEP_THEME: 'twentytwentythree',
WP_ZIP_URL: 'https://wordpress.org/wordpress-6.3.zip',
OUT_FILENAME: 'wp-6.3',
},
6.2: {
KEEP_THEME: 'twentytwentythree',
WP_ZIP_URL: 'https://wordpress.org/wordpress-6.2.zip',
OUT_FILENAME: 'wp-6.2',
},
6.1: {
KEEP_THEME: 'twentytwentythree',
WP_ZIP_URL: 'https://wordpress.org/wordpress-6.1.1.zip',
OUT_FILENAME: 'wp-6.1',
},
'6.0': {
KEEP_THEME: 'twentytwentytwo',
WP_ZIP_URL: 'https://wordpress.org/wordpress-6.0.3.zip',
OUT_FILENAME: 'wp-6.0',
},
5.9: {
KEEP_THEME: 'twentytwentyone',
WP_ZIP_URL: 'https://wordpress.org/wordpress-5.9.5.zip',
OUT_FILENAME: 'wp-5.9',
},
nightly: {
KEEP_THEME: 'twentytwentythree',
WP_ZIP_URL: 'https://wordpress.org/nightly-builds/wordpress-latest.zip',
OUT_FILENAME: 'wp-nightly',
},
};
import { promises as fs } from 'fs';

const parser = yargs(process.argv.slice(2))
.usage('Usage: $0 [options]')
.options({
preset: {
type: 'string',
description: 'The preset to use',
choices: Object.keys(presets),
},
WP_ZIP_URL: {
type: 'string',
description: 'URL to WordPress zip file',
},
OUT_FILENAME: {
type: 'string',
description: 'Name of the output file',
},
KEEP_THEME: {
wpVersion: {
type: 'string',
description: 'Name of the theme to keep',
description:
'The WordPress version to download. Can be a major version like 6.4 or "beta" or "nightly".',
required: true,
},
['output-js']: {
type: 'string',
Expand All @@ -69,20 +26,70 @@ const parser = yargs(process.argv.slice(2))

const args = parser.argv;

const preset = presets[args.preset];
if (preset === 'undefined') {
const releasesPageResponse = await fetch(
'https://wordpress.org/download/releases/'
);
const releasesPage = await releasesPageResponse.text();

const versionInfo = {};
if (args.wpVersion === 'nightly') {
versionInfo.url =
'https://wordpress.org/nightly-builds/wordpress-latest.zip';
versionInfo.version = 'nightly';
versionInfo.majorVersion = 'nightly';
versionInfo.slug = 'nightly';
} else if (args.wpVersion === 'beta') {
const matches = releasesPage.match(
/https:\/\/wordpress\.org\/wordpress-(\d\.\d-(?:RC|beta|alpha)\d)\.zip/
);
if (!matches) {
throw new Error('Could not find a beta version');
}
versionInfo.url = matches[0];
versionInfo.version = matches[1];
versionInfo.majorVersion = matches[1].substring(0, 3);
versionInfo.slug = 'beta';
} else if (args.wpVersion.startsWith('latest')) {
const latestBranches = releasesPage
.match(/(\d\.\d) Branch/g)
.slice(0, 4)
.map((branch) => branch.replace(' Branch', ''));
const wpBranch = {
latest: latestBranches[0],
'latest-minus-1': latestBranches[1],
'latest-minus-2': latestBranches[2],
'latest-minus-3': latestBranches[3],
}[args.wpVersion];

const matches = releasesPage.match(
new RegExp(`https://wordpress.org/wordpress-(${wpBranch}\\.\\d)\\.zip`)
);
if (!matches) {
throw new Error('Could not find version ' + wpBranch);
}
versionInfo.url = matches[0];
versionInfo.version = matches[1];
versionInfo.majorVersion = matches[1].substring(0, 3);
versionInfo.slug = versionInfo.majorVersion;
} else if (args.wpVersion.match(/\d\.\d/)) {
const matches = releasesPage.match(
new RegExp(
`https://wordpress.org/wordpress-(${args.wpVersion}(?:\\.\\d)?)\\.zip`
)
);
if (!matches) {
throw new Error('Could not find version ' + args.wpVersion);
}
versionInfo.url = matches[0];
versionInfo.version = matches[1];
versionInfo.majorVersion = args.wpVersion;
versionInfo.slug = versionInfo.majorVersion;
} else {
process.stdout.write(`WP version ${requestedVersion} is not supported\n`);
process.stdout.write(await argParser.getHelp());
process.exit(1);
}

function getArg(name) {
if (preset?.[name]) {
return preset?.[name];
}
return args[name];
}

const sourceDir = path.dirname(new URL(import.meta.url).pathname);
const outputAssetsDir = path.resolve(process.cwd(), args.outputAssets);
const outputJsDir = path.resolve(process.cwd(), args.outputJs);
Expand All @@ -95,15 +102,10 @@ await asyncSpawn(
'.',
'--tag=wordpress-playground',
'--progress=plain',
...(getArg('WP_ZIP_URL')
? ['--build-arg', `WP_ZIP_URL=${getArg('WP_ZIP_URL')}`]
: []),
...(getArg('OUT_FILENAME')
? ['--build-arg', `OUT_FILENAME=${getArg('OUT_FILENAME')}`]
: []),
...(getArg('KEEP_THEME')
? ['--build-arg', `KEEP_THEME=${getArg('KEEP_THEME')}`]
: []),
'--build-arg',
`WP_ZIP_URL=${versionInfo.url}`,
'--build-arg',
`OUT_FILENAME=wp-${versionInfo.slug}`,
],
{ cwd: sourceDir, stdio: 'inherit' }
);
Expand All @@ -123,7 +125,7 @@ await asyncSpawn(
// they don't work without running cp through shell.
'sh',
'-c',
`cp -r /root/output/${getArg('OUT_FILENAME')} /output/`,
`cp -r /root/output/wp-${versionInfo.slug} /output/`,
],
{ cwd: sourceDir, stdio: 'inherit' }
);
Expand All @@ -148,6 +150,64 @@ await asyncSpawn(
{ cwd: sourceDir, stdio: 'inherit' }
);

// Update the WordPress versions JSON
const versionsPath = `${outputJsDir}/wp-versions.json`;
let versions = {};
try {
const data = await fs.readFile(versionsPath, 'utf8');
versions = JSON.parse(data);
} catch (e) {}

// Set WordPress version
versions[versionInfo.slug] = versionInfo.version;

// Sort version keys, which are strings, in an ascending order
versions = Object.keys(versions)
.sort()
.reverse()
.reduce((acc, key) => {
acc[key] = versions[key];
return acc;
}, {});

// Write the updated JSON back to the file
await fs.writeFile(versionsPath, JSON.stringify(versions, null, 2));

// Refresh get-wordpress-module.ts
const getWordPressModulePath = `${outputJsDir}/get-wordpress-module.ts`;
const getWordPressModuleContent = `
/**
* This file was auto generated by packages/playground/compile-wordpress/build.js
* DO NOT CHANGE MANUALLY!
* This file must statically exists in the project because of the way
* vite resolves imports.
*/
import SupportedWordPressVersions from './wp-versions.json';
export { SupportedWordPressVersions };
export const SupportedWordPressVersionsList = Object.keys(
SupportedWordPressVersions
) as any as string[];
export const LatestSupportedWordPressVersion =
SupportedWordPressVersionsList.filter((v) => v.match(/^\\d/))[0] as string;
export function getWordPressModule(wpVersion: string) {
switch (wpVersion) {
${Object.keys(versions)
.map(
(version) => `
case '${version}':
/** @ts-ignore */
return import('./wp-${version}.js');`
)
.join('')}
}
throw new Error('Unsupported WordPress module: ' + wpVersion);
}
`;
await fs.writeFile(getWordPressModulePath, getWordPressModuleContent);

function asyncSpawn(...args) {
return new Promise((resolve, reject) => {
const child = spawn(...args);
Expand Down
14 changes: 7 additions & 7 deletions packages/playground/remote/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,20 @@
"recompile-wordpress": {
"executor": "nx:run-commands",
"options": {
"command": "node packages/playground/compile-wordpress/build.js --preset={args.preset} --output-js=packages/playground/remote/src/wordpress --output-assets=packages/playground/remote/public",
"command": "node packages/playground/compile-wordpress/build.js --wp-version={args.wp-version} --output-js=packages/playground/remote/src/wordpress --output-assets=packages/playground/remote/public",
"parallel": false
}
},
"recompile-wordpress:all": {
"executor": "nx:run-commands",
"options": {
"commands": [
"node packages/playground/compile-wordpress/build.js --preset=5.9 --output-js=packages/playground/remote/src/wordpress --output-assets=packages/playground/remote/public",
"node packages/playground/compile-wordpress/build.js --preset=6.0 --output-js=packages/playground/remote/src/wordpress --output-assets=packages/playground/remote/public",
"node packages/playground/compile-wordpress/build.js --preset=6.1 --output-js=packages/playground/remote/src/wordpress --output-assets=packages/playground/remote/public",
"node packages/playground/compile-wordpress/build.js --preset=6.2 --output-js=packages/playground/remote/src/wordpress --output-assets=packages/playground/remote/public",
"node packages/playground/compile-wordpress/build.js --preset=6.3 --output-js=packages/playground/remote/src/wordpress --output-assets=packages/playground/remote/public",
"node packages/playground/compile-wordpress/build.js --preset=nightly --output-js=packages/playground/remote/src/wordpress --output-assets=packages/playground/remote/public"
"node packages/playground/compile-wordpress/build.js --wp-version=latest-minus-3 --output-js=packages/playground/remote/src/wordpress --output-assets=packages/playground/remote/public",
"node packages/playground/compile-wordpress/build.js --wp-version=latest-minus-2 --output-js=packages/playground/remote/src/wordpress --output-assets=packages/playground/remote/public",
"node packages/playground/compile-wordpress/build.js --wp-version=latest-minus-1 --output-js=packages/playground/remote/src/wordpress --output-assets=packages/playground/remote/public",
"node packages/playground/compile-wordpress/build.js --wp-version=latest --output-js=packages/playground/remote/src/wordpress --output-assets=packages/playground/remote/public",
"node packages/playground/compile-wordpress/build.js --wp-version=beta --output-js=packages/playground/remote/src/wordpress --output-assets=packages/playground/remote/public",
"node packages/playground/compile-wordpress/build.js --wp-version=nightly --output-js=packages/playground/remote/src/wordpress --output-assets=packages/playground/remote/public"
],
"parallel": false
}
Expand Down
1 change: 1 addition & 0 deletions packages/playground/remote/remote.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
try {
await bootPlaygroundRemote();
} catch (e) {
console.error(e);
document.body.className = 'has-error';
document.body.innerHTML = '';

Expand Down
1 change: 0 additions & 1 deletion packages/playground/remote/service-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ initializeServiceWorker({

type WPModuleDetails = {
staticAssetsDirectory: string;
defaultTheme: string;
};

const scopeToWpModule: Record<string, WPModuleDetails> = {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const workerUrl: string = new URL(moduleWorkerUrl, origin) + '';

// @ts-ignore
import serviceWorkerPath from '../../service-worker.ts?worker&url';
import { LatestSupportedWordPressVersion } from './get-wordpress-module';
import { LatestSupportedWordPressVersion } from '../wordpress/get-wordpress-module';
import type { SyncProgressCallback } from './opfs/bind-opfs';
export const serviceWorkerUrl = new URL(serviceWorkerPath, origin);

Expand Down
Loading

0 comments on commit a4d8b26

Please sign in to comment.