From c714326bd07ef39cd14a00bb5fe2a5758f384b02 Mon Sep 17 00:00:00 2001 From: Ethan Gardner Date: Wed, 23 Oct 2024 19:03:22 -0400 Subject: [PATCH] chore: performance improvements - update build asset handling. delete the asset paths manifest since that is an artifact of the build. - Remove `--use` flag from postcss command. Set env for federalist command. The `--use` flag in the postcss command was causing issues with inline source maps. By updating the command, we ensure better compatibility and cleaner builds. - Set ELEVENTY_ENV to production for federalist script prevent blank space in rendered HTML file output and delete preload - Write uswds fonts to manifest file so they can be preloaded Added logic to include .woff2 font files in asset path generation. The new code filters and maps font files, preserving consistent naming and paths, then integrates them into the existing assets object. This ensures all necessary assets, including fonts, are correctly referenced in the output JSON. - Preload fonts needed for the critical rendering path - add build step to packages to avoid an unstyled page on the first run of `dev` - add uswds-init.js to a file that is in the build pipeline so it can be hashed and cached. - split getFonts out to its own function. - remove comment - update production build name --- .eleventy.js | 3 --- .gitignore | 1 + _data/assetPaths.json | 9 ------- _includes/layouts/base.html | 3 +-- _includes/meta.html | 17 +++++++++--- config/buildAssets.js | 53 +++++++++++++++++++++++++++++-------- js/uswds-init.js | 1 + package.json | 6 ++--- postcss.config.js | 8 ++++-- 9 files changed, 68 insertions(+), 33 deletions(-) delete mode 100644 _data/assetPaths.json create mode 100644 js/uswds-init.js diff --git a/.eleventy.js b/.eleventy.js index 3265982..ebda343 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -15,9 +15,6 @@ module.exports = function (config) { // Copy the `admin` folders to the output config.addPassthroughCopy('admin'); - // Copy USWDS init JS so we can load it in HEAD to prevent banner flashing - config.addPassthroughCopy({'./node_modules/@uswds/uswds/dist/js/uswds-init.js': 'assets/js/uswds-init.js'}); - // Add plugins config.addPlugin(pluginRss); config.addPlugin(pluginNavigation); diff --git a/.gitignore b/.gitignore index 939ce5c..5e58acd 100644 --- a/.gitignore +++ b/.gitignore @@ -120,3 +120,4 @@ web_modules/ _site public node_modules +_data/assetPaths.json \ No newline at end of file diff --git a/_data/assetPaths.json b/_data/assetPaths.json deleted file mode 100644 index 1daa272..0000000 --- a/_data/assetPaths.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "admin.js": "/assets/js/admin-OYJBR6FH.js", - "admin.map": "/assets/js/admin-OYJBR6FH.js.map", - "app.js": "/assets/js/app-ZQYILJ3O.js", - "app.map": "/assets/js/app-ZQYILJ3O.js.map", - "uswds.js": "/assets/js/uswds-init.js", - "styles.css": "/assets/styles/styles-BBYPEDQ2.css", - "styles.map": "/assets/styles/styles-BBYPEDQ2.css.map" -} \ No newline at end of file diff --git a/_includes/layouts/base.html b/_includes/layouts/base.html index bb67b0a..dc201fc 100644 --- a/_includes/layouts/base.html +++ b/_includes/layouts/base.html @@ -1,10 +1,9 @@ + {% comment %} This is used for just about every page. It provides the border around the content. The home page uses wide.html layout, since it extends full width of page {% endcomment %} - - {% include "meta.html" %} diff --git a/_includes/meta.html b/_includes/meta.html index 491e2cf..758ddeb 100644 --- a/_includes/meta.html +++ b/_includes/meta.html @@ -29,9 +29,20 @@ - + + - - + + + {% comment %} + Preload only the files that are needed for the content in the initial viewport. This + will likely include the fonts needed for the navigation, page heading, and the font needed for the + first paragraph of body copy. The `crossorigin` attribute may be required based on the type + of asset you wish to preload in order for the preload to work properly. + {% endcomment %} + + + + diff --git a/config/buildAssets.js b/config/buildAssets.js index d029014..06b4a65 100644 --- a/config/buildAssets.js +++ b/config/buildAssets.js @@ -3,19 +3,47 @@ const path = require('path'); const esbuild = require('esbuild'); const { sassPlugin } = require('esbuild-sass-plugin'); +async function getFontFiles(assetPath, pathPrefix) { + const assetDirs = await fs.readdir(assetPath, {withFileTypes: true}); + const fonts = await Promise.all( + assetDirs.map(async (item) => { + const itemPath = path.join(assetPath, item.name); + const stats = await fs.lstat(itemPath); + if (stats.isFile() && path.extname(item.name) === '.woff2') { + return item.name; + } + return null; + }) + ); + return fonts.filter(item => item !== null) + .map((file) => { + const {name, ext} = path.parse(file); + const hashedAt = name.lastIndexOf('-'); + const originalName = name.slice(0, hashedAt); + const key = `${originalName}${ext}`; + return {[key]: `${pathPrefix}/assets/${file}`}; + }); +} + async function createAssetPaths() { - let pathPrefix = '' + let pathPrefix = ''; if (process.env.BASEURL) { - pathPrefix = process.env.BASEURL + pathPrefix = process.env.BASEURL; } const assetPath = path.join(__dirname, '../_site/assets'); - const assetDirs = await fs.readdir(assetPath); + let assetDirs = await fs.readdir(assetPath, { withFileTypes: true }); + const fontFiles = await getFontFiles(assetPath, pathPrefix); + + assetDirs = assetDirs + .filter((item) => item.isDirectory()) + .map((item) => item.name); + const assetsFiles = await Promise.all( assetDirs.map(async (dir) => { const files = await fs.readdir( - path.join(__dirname, '../_site/assets', dir) + path.join(__dirname, '../_site/assets', dir), ); return files.map((file) => { const { name, ext } = path.parse(file); @@ -28,7 +56,7 @@ async function createAssetPaths() { }); }) ); - const assets = Object.assign({}, ...assetsFiles.flat()); + const assets = Object.assign({}, ...assetsFiles.flat(), ...fontFiles.flat()); const outputData = path.join(__dirname, '../_data/assetPaths.json'); return await fs.writeFile(outputData, JSON.stringify(assets, null, 2)); @@ -36,16 +64,19 @@ async function createAssetPaths() { esbuild .build({ - entryPoints: ['styles/styles.scss', 'js/app.js', 'js/admin.js'], + entryPoints: ['styles/styles.scss', 'js/app.js', 'js/admin.js', 'js/uswds-init.js'], entryNames: '[dir]/[name]-[hash]', outdir: '_site/assets', format: 'iife', loader: { - '.png': 'dataurl', - '.svg': 'dataurl', - '.ttf': 'dataurl', - '.woff': 'dataurl', - '.woff2': 'dataurl', + '.jpg': 'file', + '.gif': 'file', + '.png': 'file', + '.webp': 'file', + '.svg': 'file', + '.ttf': 'file', + '.woff': 'file', + '.woff2': 'file', }, minify: process.env.ELEVENTY_ENV === 'production', sourcemap: process.env.ELEVENTY_ENV !== 'production', diff --git a/js/uswds-init.js b/js/uswds-init.js new file mode 100644 index 0000000..16d3a0a --- /dev/null +++ b/js/uswds-init.js @@ -0,0 +1 @@ +require('../node_modules/@uswds/uswds/dist/js/uswds-init'); diff --git a/package.json b/package.json index acbb879..b995558 100644 --- a/package.json +++ b/package.json @@ -5,19 +5,19 @@ "main": "index.js", "scripts": { "build": "npm run assets:build && npx @11ty/eleventy", - "assets:autoprefix": "postcss _site/assets/styles/*.css -r --use autoprefixer", + "assets:autoprefix": "postcss _site/assets/styles/*.css -r", "assets:build": "node ./config/buildAssets && npm run assets:autoprefix", "assets:clean": "rimraf _site/assets", "assets:refresh": "npm run assets:clean && npm run assets:build", "assets:watch": "chokidar 'js/**' 'styles/**' -c 'npm run assets:refresh' --polling", "clean": "rimraf _site", - "dev": "npm run clean && npm-run-all -p dev:assets dev:serve", + "dev": "npm run clean && npm run assets:build && npm-run-all -p dev:assets dev:serve", "dev:clean": "npm run clean && npm run dev", "dev:assets": "npm run assets:refresh && npm run assets:watch", "dev:debug": "DEBUG=* npx @11ty/eleventy --serve --watch", "dev:serve": "npx @11ty/eleventy --serve --watch", "dev:cms": "npx decap-server", - "federalist": "npm run build", + "pages": "ELEVENTY_ENV=production npm run build", "serve": "npx @11ty/eleventy --serve", "start": "npx @11ty/eleventy --serve", "test": "echo \"Error: no test specified\" && exit 1" diff --git a/postcss.config.js b/postcss.config.js index a0fa32b..aa19e0e 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,3 +1,7 @@ module.exports = { - plugins: [require('autoprefixer')], -}; + plugins: [ + require('autoprefixer')({ + map: process.env.ELEVENTY_ENV !== 'production' + }), + ], +}; \ No newline at end of file