files.js: make pure to fix font logic

Since 15469bb469 ("tools: Teach webpack-make.js to get node_modules by
itself") we want to support people invoking `./build.js` without having
run `tools/node-modules checkout`.  This commit added an invocation of
`tools/node-modules` to make sure that everything is checked out and up
to date.

Unfortunately, `file.js` gets imported before that happens, and since
7cab667c1b ("pkg: Change to variable font") this module import isn't
pure: it tries to read the font information from the `node_modules`
directory at import time, before we've run the update. That means that
we can either:

 - fail completely, if the `node_modules` aren't checked out yet

 - (maybe worse): read stale information if they're checked out, but to
   the incorrect version (and get updated in between the read and the
   build)

Move the top-level computation added in that commit to `getFiles()`
which gets called — once — at runtime, after we've done the update.  We
need to rename a local to avoid a shadow.  Move related constants, some
comments, and a few other "computationy" things (like path computations)
which are no longer needed at the toplevel into the function as well.

`all_subdirs` is left at the toplevel because it's entirely based on
internal data and it's an export (and used from build.js).

This module is now side-effect-free on import and the automatic
`node_modules` checkout functionality is working properly again.
This commit is contained in:
Allison Karlitskaya 2026-11-02 13:26:23 +01:00 committed by Allison Karlitskaya
parent 7a887d89b2
commit 5f3c0e9b8b

116
files.js
View file

@ -153,67 +153,67 @@ const info = {
] ]
}; };
const srcdir = import.meta.dirname;
const nodedir = path.join(srcdir, "node_modules");
export const all_subdirs = Array.from(new Set(info.entries.map(key => key.split('/')[0]))); export const all_subdirs = Array.from(new Set(info.entries.map(key => key.split('/')[0])));
// These are the fonts we used up until migrating to Patternfly v6
// It is kept here to make sure all dependencies of the fonts works like in
// third-party plugins etc.
// With the PF6 migration we now want to use Variable Fonts (VF) to ensure better
// Patternfly visuals, and we will use a new directory structure to avoid hardcoding
// @font-face.
//
// This copies all non-VF Red Hat fonts to our `static/fonts/` directory.
const redhat_fonts = [
"Text-Bold", "Text-BoldItalic", "Text-Italic", "Text-Medium", "Text-MediumItalic", "Text-Regular",
"Display-Black", "Display-BlackItalic", "Display-Bold", "Display-BoldItalic",
"Display-Italic", "Display-Medium", "Display-MediumItalic", "Display-Regular",
"Mono-Bold", "Mono-BoldItalic", "Mono-Italic", "Mono-Medium", "Mono-MediumItalic", "Mono-Regular",
].map(name => {
const subdir = 'RedHat' + name.split('-')[0];
const fontsdir = '@patternfly/patternfly/assets/fonts';
return {
from: path.resolve(nodedir, fontsdir, subdir, 'RedHat' + name + '.woff2'),
to: 'static/fonts/'
};
});
// Different directory structure than our redhat_fonts, which makes it easier
// to use the Patternfly default src and avoid hardcoding our own @font-face.
//
// This copies all variable fonts (VF in the name) to subdirectories:
// static/fonts/
// ├── RedHatDisplay
// │ └── RedHatDisplayVF.woff2
// ├── RedHatMono
// │ ├── RedHatMonoVF-Italic.woff2
// │ └── RedHatMonoVF.woff2
// ├── RedHatText
// │ ├── RedHatTextVF-Italic.woff2
// │ └── RedHatTextVF.woff2
const redhat_fonts_variable_font = [
"Text",
"Display",
"Mono",
].flatMap(name => {
const subdir = 'RedHat' + name;
const fontsdir = '@patternfly/patternfly/assets/fonts';
const fontsDirPath = path.resolve(nodedir, fontsdir, subdir);
return fs.readdirSync(fontsDirPath)
.filter(file => file.includes('VF') && file.endsWith('.woff2'))
.map(file => ({
from: path.resolve(fontsDirPath, file),
to: `static/fonts/${subdir}`
}));
});
const pkgfile = suffix => `${srcdir}/pkg/${suffix}`;
export const getFiles = subdir => { export const getFiles = subdir => {
const srcdir = import.meta.dirname;
const nodedir = path.join(srcdir, "node_modules");
const pkgfile = suffix => `${srcdir}/pkg/${suffix}`;
// These are the fonts we used up until migrating to Patternfly v6
// It is kept here to make sure all dependencies of the fonts works like in
// third-party plugins etc.
// With the PF6 migration we now want to use Variable Fonts (VF) to ensure better
// Patternfly visuals, and we will use a new directory structure to avoid hardcoding
// @font-face.
//
// This copies all non-VF Red Hat fonts to our `static/fonts/` directory.
const redhat_fonts = [
"Text-Bold", "Text-BoldItalic", "Text-Italic", "Text-Medium", "Text-MediumItalic", "Text-Regular",
"Display-Black", "Display-BlackItalic", "Display-Bold", "Display-BoldItalic",
"Display-Italic", "Display-Medium", "Display-MediumItalic", "Display-Regular",
"Mono-Bold", "Mono-BoldItalic", "Mono-Italic", "Mono-Medium", "Mono-MediumItalic", "Mono-Regular",
].map(name => {
const fontfamily = 'RedHat' + name.split('-')[0];
const fontsdir = '@patternfly/patternfly/assets/fonts';
return {
from: path.resolve(nodedir, fontsdir, fontfamily, 'RedHat' + name + '.woff2'),
to: 'static/fonts/'
};
});
// Different directory structure than our redhat_fonts, which makes it easier
// to use the Patternfly default src and avoid hardcoding our own @font-face.
//
// This copies all variable fonts (VF in the name) to subdirectories:
// static/fonts/
// ├── RedHatDisplay
// │ └── RedHatDisplayVF.woff2
// ├── RedHatMono
// │ ├── RedHatMonoVF-Italic.woff2
// │ └── RedHatMonoVF.woff2
// ├── RedHatText
// │ ├── RedHatTextVF-Italic.woff2
// │ └── RedHatTextVF.woff2
const redhat_fonts_variable_font = [
"Text",
"Display",
"Mono",
].flatMap(name => {
const fontfamily = 'RedHat' + name;
const fontsdir = '@patternfly/patternfly/assets/fonts';
const fontsDirPath = path.resolve(nodedir, fontsdir, fontfamily);
return fs.readdirSync(fontsDirPath)
.filter(file => file.includes('VF') && file.endsWith('.woff2'))
.map(file => ({
from: path.resolve(fontsDirPath, file),
to: `static/fonts/${fontfamily}`
}));
});
/* Qualify all the paths in entries */ /* Qualify all the paths in entries */
const entryPoints = []; const entryPoints = [];
info.entries.forEach(key => { info.entries.forEach(key => {