mirror of
https://github.com/lichess-org/lila.git
synced 2026-05-26 13:51:00 +00:00
support server only manifest entries for hashed assets
This commit is contained in:
+15
-13
@@ -10,27 +10,29 @@ import { isEquivalent } from './algo.ts';
|
||||
export async function hash(): Promise<void> {
|
||||
if (!env.begin('hash')) return;
|
||||
const hashed: Manifest = {};
|
||||
const pathOnly: { glob: string[] } = { glob: [] };
|
||||
const hashRuns: { glob: string | string[]; update?: string; pkg?: Package }[] = [];
|
||||
const withClient: { globs: string[] } = { globs: [] };
|
||||
const serverOnly: { globs: string[] } = { globs: [] };
|
||||
const hashRuns: { globs: string[]; omit: boolean; catalog?: string; pkg?: Package }[] = [];
|
||||
|
||||
for (const [pkg, { glob, update, ...rest }] of env.tasks('hash')) {
|
||||
update ? hashRuns.push({ glob, update, pkg, ...rest }) : pathOnly.glob.push(glob);
|
||||
hashLog(glob, '', pkg?.name);
|
||||
for (const [pkg, { path, catalog, omit }] of env.tasks('hash')) {
|
||||
if (catalog) hashRuns.push({ globs: [path], catalog, pkg, omit: omit ?? true });
|
||||
else if (omit) serverOnly.globs.push(path);
|
||||
else withClient.globs.push(path);
|
||||
hashLog(path, '', pkg?.name);
|
||||
}
|
||||
if (pathOnly.glob.length) hashRuns.push(pathOnly);
|
||||
if (withClient.globs.length) hashRuns.push({ globs: withClient.globs, omit: false });
|
||||
if (serverOnly.globs.length) hashRuns.push({ globs: serverOnly.globs, omit: true });
|
||||
|
||||
await fs.promises.mkdir(env.hashOutDir).catch(() => {});
|
||||
const symlinkHashes = await symlinkTargetHashes();
|
||||
await Promise.all(
|
||||
hashRuns.map(({ glob, update, pkg }) =>
|
||||
hashRuns.map(({ globs, catalog, omit, pkg }) =>
|
||||
makeTask({
|
||||
pkg,
|
||||
ctx: 'hash',
|
||||
debounce: 300,
|
||||
root: env.rootDir,
|
||||
includes: Array<string>()
|
||||
.concat(glob)
|
||||
.map(path => ({ cwd: env.rootDir, path })),
|
||||
includes: globs.map(path => ({ cwd: env.rootDir, path })),
|
||||
execute: async (files, fullList) => {
|
||||
const shouldLog = !isEquivalent(files, fullList);
|
||||
await Promise.all(
|
||||
@@ -40,16 +42,16 @@ export async function hash(): Promise<void> {
|
||||
symlinkHashes[name] && !(await isLinkStale(hashedBasename(name, symlinkHashes[name])))
|
||||
? symlinkHashes[name]
|
||||
: await hashAndLink(name);
|
||||
hashed[name] = { hash };
|
||||
hashed[name] = omit ? { hash, omit } : { hash };
|
||||
if (shouldLog) hashLog(src, hashedBasename(name, hash), pkg?.name);
|
||||
}),
|
||||
);
|
||||
if (update && pkg?.root) {
|
||||
if (catalog && pkg?.root) {
|
||||
const replacements: Record<string, string> = {};
|
||||
for (const src of fullList.map(f => relative(env.outDir, f))) {
|
||||
replacements[src] = `hashed/${hashedBasename(src, hashed[src].hash!)}`;
|
||||
}
|
||||
const { name, hash } = await replaceAllWithHashUrls(update, replacements);
|
||||
const { name, hash } = await replaceAllWithHashUrls(catalog, replacements);
|
||||
hashed[name] = { hash };
|
||||
if (shouldLog) hashLog(name, hashedBasename(name, hash), pkg.name);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ const manifest = {
|
||||
};
|
||||
let writeTimer: NodeJS.Timeout;
|
||||
|
||||
type SplitAsset = { hash?: string; path?: string; imports?: string[]; inline?: string };
|
||||
type SplitAsset = { hash?: string; path?: string; imports?: string[]; inline?: string; omit?: boolean };
|
||||
|
||||
export type Manifest = { [key: string]: SplitAsset };
|
||||
export type ManifestUpdate = Partial<Omit<typeof manifest, 'dirty'>>;
|
||||
@@ -75,8 +75,10 @@ async function writeManifest() {
|
||||
.map(pairLine)
|
||||
.join(',');
|
||||
const cssLines = Object.entries(manifest.css).map(pairLine).join(',');
|
||||
const hashedLines = Object.entries(manifest.hashed).map(pairLine).join(',');
|
||||
|
||||
const hashedLines = Object.entries(manifest.hashed)
|
||||
.filter(([, { omit }]) => !omit)
|
||||
.map(([name, { hash }]) => pairLine([name, { hash }]))
|
||||
.join(',');
|
||||
clientJs.push(`s.manifest={\ncss:{${cssLines}},\njs:{${jsLines}},\nhashed:{${hashedLines}}\n};`);
|
||||
|
||||
const hashable = clientJs.join('\n');
|
||||
|
||||
@@ -18,8 +18,9 @@ interface Bundle {
|
||||
}
|
||||
|
||||
interface Hash {
|
||||
glob: string; // glob for assets
|
||||
update?: string; // file to update with hashed filenames
|
||||
path: string; // glob for assets
|
||||
catalog?: string; // file to update with hashed filenames
|
||||
omit?: boolean; // omit from client manifest, default false
|
||||
}
|
||||
|
||||
interface Sync {
|
||||
@@ -123,7 +124,7 @@ async function parsePackage(root: string): Promise<Package> {
|
||||
if ('hash' in build)
|
||||
pkgInfo.hash = []
|
||||
.concat(build.hash)
|
||||
.map(g => (typeof g === 'string' ? { glob: normalize(g) } : normalizeObject(g))) as Hash[];
|
||||
.map(g => (typeof g === 'string' ? { path: normalize(g) } : normalizeObject(g))) as Hash[];
|
||||
|
||||
if ('sync' in build)
|
||||
pkgInfo.sync = Object.entries<string>(build.sync).map(x => ({
|
||||
|
||||
+7
-4
@@ -167,11 +167,14 @@ Hash entries identify files for which a symlink named with their content hash wi
|
||||
```
|
||||
Entries may also take object form:
|
||||
```json
|
||||
"hash": { "glob": "<pattern>", "update": "<package-relative-path>" }
|
||||
"hash": { "path": "<pattern>", "omit": true, "catalog": "<path-to-catalog>" }
|
||||
```
|
||||
When the object form is processed, symlinks for globbed files are created in /public/hashed same as before. Then the "update" file is processed and all occurrence of those globbed filenames are replaced with their hashed symlink URLs. The modified "update" file contents are also content-hashed and written to /public/hashed. This is useful when an asset references other files by name and those references must be updated to reflect the hashed URLs. Any asset mapping within a static json or text file can be kept current in this way.
|
||||
When the object form is processed, symlinks for files globbed by the "path" pattern are created in /public/hashed same as before.
|
||||
|
||||
* "hash" sources must begin with `/public` to resolve correctly on production deployments.
|
||||
* "update" files may not begin with `/` and are always package relative.
|
||||
Setting the optional "omit" field to true will omit all "path" globbed items from the client manifest. They will stil appear in the server manifest.
|
||||
|
||||
The optional "catalog" field may identifies a mapping file to be transformed. All occurrences of filenames globbed by the "path" pattern within the catalog file are replaced with their hashed symlink URLs. The modified catalog file contents are also content-hashed and written to /public/hashed. This is useful when an asset references other files by name and those references must be updated to reflect the hashed URLs. Any asset mapping within a static json or text file can be kept current in this way.
|
||||
|
||||
* hash paths must begin with `/public` to resolve correctly on production deployments.
|
||||
|
||||
The node sources for ui/build are in the [/ui/.build](./.build) folder.
|
||||
|
||||
Reference in New Issue
Block a user