Skip to content

Commit

Permalink
Generate a list of assets to cache for offline support (#1573)
Browse files Browse the repository at this point in the history
## Motivation for the change, related issues

To make [Playground available offline
](#1535 will
need to precache all Playground assets.

This PR generates a list of all assets Playground needs to run offline. 
#1535 will use the
asset file.

## Implementation details

The PR implements a new Vite plugin (`websiteCachePathsPlugin`). The
plugin runs every time the website is built and scans through the
`website`, `remote`, and `client` dist folders for cache files.

We need to do this because Vite generates new file names on each build.
For example `index.js` will be `index-HASH.js`.

To detect all required files, the plugin has a list of regex expressions
that will match these files no matter what hash Vite generates.

## Testing Instructions (or ideally a Blueprint)

- Run `npm run build:website`
- Confirm that
`dist/packages/playground/wasm-wordpress-net/cache-files.json` exists
- The file should look similar to this

```
[
  "/assets/brain-1418d665.svg",
  "/assets/builder/builder.html-f350f1dc.js",
  "/assets/builder-0648a1dd.css",
  "/assets/client-102d8634.js",
  "/assets/config-2a6ab1ba.js",
  "/assets/download-d32bab19.svg",
  "/assets/edit-79dd2f3b.svg",
  "/assets/index-2a538d29.js",
  "/assets/index-d60708af.css",
  "/assets/main-7bf730a2.css",
  "/assets/main-88eaa39a.js",
  "/assets/modulepreload-polyfill-3cfb730f.js",
  "/assets/new-tab-button-f20e269a.svg",
  "/assets/open-11ad4fc6.svg",
  "/assets/peer-dbe7a0a3.js",
  "/assets/peer.html-34c24b0c.js",
  "/assets/php-blueprints-60a056f1.js",
  "/assets/php-blueprints.html-6ff813c0.js",
  "/assets/play-button-d16471c4.svg",
  "/assets/preload-helper-cf010ec4.js",
  "/assets/save-f248e35e.svg",
  "/assets/setup-playground-sync-f9eff12c.js",
  "/assets/sync.html-5a4cfeb8.js",
  "/assets/terminal-249bb152.css",
  "/assets/terminal-3554f247.js",
  "/assets/time-traveling-2c4678ce.js",
  "/assets/time-traveling.html-14ccf92b.js",
  "/assets/wp-cli.html-55f77252.js",
  "/assets/x-90ad5814.svg",
  "/assets/zoom-in-b8a0c399.svg",
  "/assets/zoom-out-7892b279.svg",
  "/builder/builder.html",
  "/favicon.ico",
  "/gutenberg.css",
  "/gutenberg.html",
  "/index.html",
  "/logo-192.png",
  "/logo-256.png",
  "/logo-384.png",
  "/logo-512.png",
  "/manifest.json",
  "/ogimage.png",
  "/previewer.css",
  "/wordpress-importer.zip",
  "/wordpress.html",
  "/wordpress.svg",
  "/assets/remote-b5d5f2da.css",
  "/assets/wordpress-e45f8a8e.js",
  "/remote.html",
  "/sw.js",
  "/worker-thread-aa53dc45.js",
  "/index.js"
]
```

---------

Co-authored-by: Adam Zieliński <[email protected]>
  • Loading branch information
bgrgicak and adamziel authored Jul 15, 2024
1 parent aafbbcd commit a740f6f
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 0 deletions.
8 changes: 8 additions & 0 deletions packages/playground/website/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { fileURLToPath } from 'node:url';
import { copyFileSync, existsSync } from 'node:fs';
import { join } from 'node:path';
import { buildVersionPlugin } from '../../vite-extensions/vite-build-version';
import { listAssetsRequiredForOfflineMode } from '../../vite-extensions/vite-list-assets-required-for-offline-mode';

const proxy = {
'^/plugin-proxy': {
Expand Down Expand Up @@ -134,6 +135,13 @@ export default defineConfig(({ command, mode }) => {
}
},
} as Plugin,
/**
* Generate a list of files needed for the website to function offline.
*/
listAssetsRequiredForOfflineMode({
outputFile: 'assets-required-for-offline-mode.json',
distDirectoriesToList: ['./', '../remote', '../client'],
}) as Plugin,
],

// Configuration for building your library.
Expand Down
121 changes: 121 additions & 0 deletions packages/vite-extensions/vite-list-assets-required-for-offline-mode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { readdirSync, statSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';

/**
* We want to cache all files from the website root directory, except for the files listed below.
*/
const patternsToNotCache = [
/**
* Static files that are not needed for the website to function offline.
*/
'/package.json',
'/README.md',
'/.DS_Store',
'/index.cjs',
'/index.d.ts',
/\/lib\/.*/, // Remote lib files
/\/test-fixtures\/.*/, // Test fixtures
/**
* WordPress assets removed from the minified builds, for example:
*
* /wp-6.2/wp-content/themes/twentytwentyone/style.css
*
* We don't need to cache them, because they're only used in a short time
* window after the Playground is initially loaded and before they're all backfilled
* from a dedicated ZIP file shipping all the static assets for a given minified
* build.
*
* See <Assets backfilling PR link>
*/
/^\/wp-[\w+((\.\d+)?)]+\/.*/,
/**
* Demos are not needed for the website to function offline.
*/
/^\/demos\/.*/,
/**
* Files needed only by the playground.wordpress.net server.
*/
'/.htaccess',
/**
* We can't download the PHP scripts – only get their execution result. This is fine,
* we don't need them for the offline mode anyway. This includes things like plugins-proxy.php.
*/
/\/.*\.php$/,
/**
* WordPress, PHP, and SQLite files that are loaded during boot.
* Eagerly loading all the PHP and WordPress releases offered by Playground would use an
* extra ~200MB of bandwidth every time you load Playground on a new device.
*
* However, most of the time time you only want to load a specific Playground configuration.
*
* Therefore, in here we're excluding the PHP and WP releases from being loaded
* eagerly and instead we're defaulting to caching the specific release that's
* loaded anyway when booting Playgroung.
*/
/^\/assets\/php_.*\.wasm$/, // PHP WASM files
/^\/assets\/php_.*\.js$/, // PHP JS files
/^\/assets\/wp-.*\.zip$/, // Minified WordPress builds and static assets bundles
/^\/assets\/sqlite-database-integration-[\w]+\.zip/, // SQLite plugin
];

function listFiles(dirPath: string, fileList: string[] = []) {
const files = readdirSync(dirPath);

files.forEach((file) => {
const filePath = join(dirPath, file);
const fileStat = statSync(filePath);

if (fileStat.isDirectory()) {
listFiles(filePath, fileList);
} else {
fileList.push(filePath);
}
});

return fileList;
}

/**
* This Vite plugin saves a list of those files as a JSON file served on
* `playground.wordpress.net`. Playground then consults the list to
* download and cache all those files at the end of the boot process.
* .
*/
export const listAssetsRequiredForOfflineMode = ({
outputFile,
distDirectoriesToList,
}: {
outputFile: string;
distDirectoriesToList: string[];
}) => {
return {
name: 'list-assets-required-for-offline-mode',
apply: 'build',
writeBundle({ dir: outputDir }: { dir: string }) {
const files = distDirectoriesToList.flatMap((dir) => {
const absoluteDirPath = join(outputDir, dir);
console.log(`Listing files in ${absoluteDirPath}`);
return listFiles(absoluteDirPath)
.map((file) => {
file = file.replace(absoluteDirPath, '');
if (file.startsWith('/')) {
return file;
}
return `/${file}`;
})
.filter((item) => {
return !patternsToNotCache.some((pattern) => {
if (pattern instanceof RegExp) {
return pattern.test(item);
}
return pattern === item;
});
});
});
writeFileSync(
join(outputDir, outputFile),
JSON.stringify(files, null, 2)
);
},
};
};

0 comments on commit a740f6f

Please sign in to comment.