From 24bf94176c439f04286dc6afc1e13f3806c4d587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Mon, 29 Apr 2024 21:07:56 +0200 Subject: [PATCH] Use the Simply Static plugin for static site generation Playground now supports a loopback request and libcurl, which means we can use Simply Static to generate a static site. --- build-static-site.sh | 15 +++ generate-static-site.js | 108 ------------------ ...wp-now.json => blueprint-static-site.json} | 30 +++-- wp-content/plugins/wp-docs-plugin/plugin.php | 74 ------------ 4 files changed, 34 insertions(+), 193 deletions(-) create mode 100644 build-static-site.sh delete mode 100644 generate-static-site.js rename wp-content/{blueprint-wp-now.json => blueprint-static-site.json} (66%) diff --git a/build-static-site.sh b/build-static-site.sh new file mode 100644 index 0000000..def3c3b --- /dev/null +++ b/build-static-site.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +bun \ + --config=/Users/cloudnik/.bunfig.toml \ + ../playground/packages/playground/cli/src/cli.ts \ + run-blueprint \ + --mount=./wp-content/plugins/wp-docs-plugin:/wordpress/wp-content/plugins/wp-docs-plugin \ + --mount=./wp-content/plugins/export-static-site:/wordpress/wp-content/plugins/export-static-site \ + --mount=./wp-content/html-pages:/wordpress/wp-content/html-pages \ + --mount=./wp-content/uploads:/wordpress/wp-content/uploads \ + --mount=./wp-content/themes/playground-docs:/wordpress/wp-content/themes/playground-docs \ + --mount=./output:/output \ + --blueprint=./wp-content/blueprint-static-site.json \ + --wp=6.5 \ + --php=8.0 \ diff --git a/generate-static-site.js b/generate-static-site.js deleted file mode 100644 index 94a9d81..0000000 --- a/generate-static-site.js +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Static Site Generator for wp-now - * - * How does it work? - * 1. The JavaScript crawler requests /logout/ to, well, log out. - * 2. The /sitemap/ endpoint returns a list of all Posts with post_type=page and their URLs - * 3. A JavaScript crawler requests each of those pages and writes the rendered HTML to the out directory - * 4. All full-qualified site URLs are replaced with an absolute path - * 5. The JavaScript crawler sends a request to /zip-wp-files/ to create wp.zip with wp-includes and wp-content inside (without PHP files) - * 6. The JavaScript crawler unzips wp.zip in the out directory, shipping the missing static assets - * - * It's weird process – that's because of wp-now's limitations. - * @ee https://github.com/WordPress/playground-tools/issues/238 - */ - -const { exec } = require('child_process'); -const fs = require('fs'); - -const outdir = process.argv[2] || __dirname + '/out'; -const PATH_PREFIX = process.env.PATH_PREFIX || '/'; - -console.log(`Generating static site with ${PATH_PREFIX} prefix to: ${outdir}`); -// Run the start-site.sh script -const startSiteProcess = exec('bash start-site.sh'); - -// Listen for the output of the script -startSiteProcess.stdout.on('data', (data) => { - const output = data.toString(); - process.stdout.write(output); - - // Check if the output contains the "Server running at" message - if (output.includes('Server running at')) { - // Extract the URL from the output - const urlMatch = output.match(/Server running at (.+)/); - const url = urlMatch[1]; - - // Render the static site - renderStaticSite(url).finally(() => { - // Kill the start-site.sh script - console.log('Done!'); - startSiteProcess.kill(9); - process.exit(0); - }); - } -}); - -async function renderStaticSite(siteUrl) { - // @TODO: Prevent wp-now from forcefully logging the user in - await fetch(`${siteUrl}/logout/`); - const sitemap = await fetch(`${siteUrl}/sitemap/`).then((response) => response.json()); - for (const { url, title, isFrontPage } of sitemap) { - let page = await fetch(`${url}`).then((response) => response.text()); - let filePath = `${outdir}${url.replace(siteUrl, '')}`; - let fileDir = '', fileName = ''; - if (filePath.endsWith('/')) { - fileName = 'index.html'; - fileDir = filePath; - } else { - fileDir = filePath.substring(0, filePath.lastIndexOf('/')); - fileName = filePath.substring(filePath.lastIndexOf('/') + 1) + '.html'; - } - - // Create the directory if it doesn't exist - if (!fs.existsSync(fileDir)) { - fs.mkdirSync(fileDir, { recursive: true }); - } - - // Write the page content to a file - page = normalizeUrls(page, siteUrl, PATH_PREFIX); - fs.writeFileSync(`${fileDir}/${fileName}`, page); - - if (isFrontPage) { - fs.writeFileSync(`${outdir}/index.html`, ``); - } - } - - // @TODO: Share the filesystem instead of going through zips. - // For example, support explicit mountpoints. - await fetch(`${siteUrl}/zip-wp-files/`); - await new Promise((resolve, reject) => { - exec(`unzip -o ./wp-content/wp.zip -d ${outdir}`, (error, stdout, stderr) => { - if (error) { - console.error('Error unzipping wp.zip:', error); - reject(error); - } else { - console.log('wp.zip unzipped successfully'); - resolve(); - } - }); - }); -} - -function normalizeUrls(html, siteUrl, targetUrl) { - if (!targetUrl.endsWith('/')) { - targetUrl += '/'; - } - if (!siteUrl.endsWith('/')) { - siteUrl += '/'; - } - html = html.replaceAll(siteUrl, targetUrl); - html = html.replace('//localhost', ''); - return html; -} - -// Handle any errors from the start-site.sh script -startSiteProcess.on('error', (error) => { - console.error('Error running start-site.sh:', error); -}); diff --git a/wp-content/blueprint-wp-now.json b/wp-content/blueprint-static-site.json similarity index 66% rename from wp-content/blueprint-wp-now.json rename to wp-content/blueprint-static-site.json index a92e9f1..727c0c9 100644 --- a/wp-content/blueprint-wp-now.json +++ b/wp-content/blueprint-static-site.json @@ -37,16 +37,24 @@ "slug": "gutenberg" } }, - { - "step": "installPlugin", - "pluginZipFile": { - "resource": "wordpress.org/plugins", - "slug": "simply-static" - } - }, - { - "step": "activatePlugin", - "pluginPath": "wp-docs-plugin/plugin.php" - } + { + "step": "installPlugin", + "pluginZipFile": { + "resource": "wordpress.org/plugins", + "slug": "simply-static" + } + }, + { + "step": "activatePlugin", + "pluginPath": "wp-docs-plugin/plugin.php" + }, + { + "step": "activatePlugin", + "pluginPath": "export-static-site/export-static-site.php" + }, + { + "step": "runPHP", + "code": " 'publish', - 'posts_per_page' => -1, - 'post_type' => $page_type - ) - )); - } - - $sitemap = []; - // Loop through pages and print URLs - foreach($pages as $page) { - $sitemap[] = [ - 'url' => get_permalink($page->ID), - 'title' => $page->post_title, - 'isFrontPage' => $page->ID == $frontpage_id, - ]; - } - return $sitemap; -} - -function zip_wp_files($target_path) { - // Zip wp-content and wp-includes - $zip = new ZipArchive(); - if ($zip->open($target_path, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) { - echo 'Failed to create zip file'; - exit(1); - } - - foreach(['wp-content', 'wp-includes'] as $dir) { - $files = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator(ABSPATH . '/' . $dir), - RecursiveIteratorIterator::LEAVES_ONLY - ); - - foreach ($files as $name => $file) { - if (!$file->isDir() && pathinfo($file->getRealPath(), PATHINFO_EXTENSION) !== 'php') { - $filePath = $file->getRealPath(); - $relativePath = substr($filePath, strlen(ABSPATH)); - $zip->addFile($filePath, $relativePath); - } - } - } - - $zip->close(); -} function create_db_pages_from_html_files($dir, $parent_id = 0) { $indexFilePath = $dir . '/index.html';