From 65121832c05276bab61438f47ad64d3d0d23df90 Mon Sep 17 00:00:00 2001 From: "Charles Graham, SWT" Date: Wed, 15 Jul 2026 12:54:25 -0500 Subject: [PATCH 1/3] Improve library module tree output --- package-lock.json | 35 ++------------------------------- package.json | 44 ++++++++++++++++++++++++++++++++++++++---- vite.config.js | 49 ++++++++++++++++++++++++++++++++++------------- 3 files changed, 78 insertions(+), 50 deletions(-) diff --git a/package-lock.json b/package-lock.json index b3e1249..5baafce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,8 @@ "react-icons": "^5.0.1", "redux-bundler": "^28.1.0", "redux-bundler-hook": "^1.0.3", - "redux-bundler-react": "^1.2.0" + "redux-bundler-react": "^1.2.0", + "tailwind-merge": "^2.5.2" }, "devDependencies": { "@lhci/cli": "^0.15.1", @@ -32,7 +33,6 @@ "lint-staged": "^16.1.4", "postcss": "^8.4.33", "prettier": "^3.6.2", - "tailwind-merge": "^2.5.2", "tailwindcss": "^3.4.1", "typescript": "^6.0.3", "vite": "^8.1.3", @@ -894,9 +894,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -914,9 +911,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -934,9 +928,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -954,9 +945,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -974,9 +962,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -994,9 +979,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5499,9 +5481,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5523,9 +5502,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5547,9 +5523,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5571,9 +5544,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -8146,7 +8116,6 @@ }, "node_modules/tailwind-merge": { "version": "2.6.0", - "dev": true, "license": "MIT", "funding": { "type": "github", diff --git a/package.json b/package.json index dccf85e..250b4be 100644 --- a/package.json +++ b/package.json @@ -9,15 +9,51 @@ "url": "git+https://github.com/USACE/groundwork.git" }, "main": "./dist/groundwork.umd.cjs", - "module": "./dist/groundwork.es.js", + "module": "./dist/es/index.js", "files": [ "dist" ], "exports": { ".": { - "import": "./dist/groundwork.es.js", + "import": "./dist/es/index.js", "require": "./dist/groundwork.umd.cjs" }, + "./components/*": { + "import": "./dist/es/components/*.js" + }, + "./components/buttons/*": { + "import": "./dist/es/components/buttons/*.js" + }, + "./components/display/*": { + "import": "./dist/es/components/display/*.js" + }, + "./components/form/*": { + "import": "./dist/es/components/form/*.js" + }, + "./components/layout/*": { + "import": "./dist/es/components/layout/*.js" + }, + "./components/navigation/*": { + "import": "./dist/es/components/navigation/*.js" + }, + "./composite/*": { + "import": "./dist/es/composite/*.js" + }, + "./composite/footer/*": { + "import": "./dist/es/composite/footer/*.js" + }, + "./composite/header/*": { + "import": "./dist/es/composite/header/*.js" + }, + "./composite/site-wrapper/*": { + "import": "./dist/es/composite/site-wrapper/*.js" + }, + "./hooks/*": { + "import": "./dist/es/hooks/*.js" + }, + "./utils/*": { + "import": "./dist/es/utils/*.js" + }, "./groundwork.css": { "import": "./dist/groundwork.css", "require": "./dist/groundwork.css" @@ -60,7 +96,8 @@ "react-icons": "^5.0.1", "redux-bundler": "^28.1.0", "redux-bundler-hook": "^1.0.3", - "redux-bundler-react": "^1.2.0" + "redux-bundler-react": "^1.2.0", + "tailwind-merge": "^2.5.2" }, "peerDependencies": { "react": "^18.2.0 || ^19.0.0", @@ -80,7 +117,6 @@ "lint-staged": "^16.1.4", "postcss": "^8.4.33", "prettier": "^3.6.2", - "tailwind-merge": "^2.5.2", "tailwindcss": "^3.4.1", "typescript": "^6.0.3", "vite": "^8.1.3", diff --git a/vite.config.js b/vite.config.js index 14a275d..b454898 100644 --- a/vite.config.js +++ b/vite.config.js @@ -7,6 +7,18 @@ import path from "path"; import fs from "fs"; const LHCI_PREFIX = process.env.LHCI_PREFIX || "http://localhost:5173/"; +const externalPackages = [ + ...Object.keys(pkg.dependencies ?? {}), + ...Object.keys(pkg.peerDependencies ?? {}), +]; +const isExternalPackage = (id) => + externalPackages.some((name) => id === name || id.startsWith(`${name}/`)); +const libraryAssetFileNames = (assetInfo) => { + if (assetInfo.name?.endsWith(".css")) { + return "groundwork.css"; + } + return "assets/[name][extname]"; +}; function RoutesToLHCIPlugin() { return { @@ -41,24 +53,35 @@ export default defineConfig(({ mode }) => { build: { lib: { name: "Groundwork", - fileName: (format) => `groundwork.${format}.js`, + fileName: (format) => + format === "umd" ? "groundwork.umd.cjs" : "index.js", entry: "lib/index.jsx", + formats: ["es", "umd"], }, rollupOptions: { - external: ["react", "react-dom", "react/jsx-runtime"], - output: { - assetFileNames: (assetInfo) => { - if (assetInfo.name?.endsWith(".css")) { - return "groundwork.css"; - } - return "[name][extname]"; + external: isExternalPackage, + output: [ + { + format: "es", + dir: "dist", + preserveModules: true, + preserveModulesRoot: "lib", + entryFileNames: "es/[name].js", + chunkFileNames: "es/chunks/[name]-[hash].js", + assetFileNames: libraryAssetFileNames, }, - globals: { - react: "React", - "react-dom": "ReactDOM", - "react/jsx-runtime": "ReactJsxRuntime", + { + format: "umd", + name: "Groundwork", + entryFileNames: "groundwork.umd.cjs", + assetFileNames: libraryAssetFileNames, + globals: { + react: "React", + "react-dom": "ReactDOM", + "react/jsx-runtime": "ReactJsxRuntime", + }, }, - }, + ], }, }, }; From 6329fcde3c2299d7f04eb9549e6816dde5e8994a Mon Sep 17 00:00:00 2001 From: "Charles Graham, SWT" Date: Wed, 15 Jul 2026 12:57:42 -0500 Subject: [PATCH 2/3] Separate library CSS from JS entry --- lib/index.jsx | 3 --- lib/style-entry.js | 1 + package.json | 5 ++++- vite.config.js | 31 +++++++++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 lib/style-entry.js diff --git a/lib/index.jsx b/lib/index.jsx index e667f54..93f58a3 100644 --- a/lib/index.jsx +++ b/lib/index.jsx @@ -1,6 +1,3 @@ -// bundle tailwind -import "./styles.css"; - // utilities export { gwMerge } from "./gw-merge"; diff --git a/lib/style-entry.js b/lib/style-entry.js new file mode 100644 index 0000000..fed29db --- /dev/null +++ b/lib/style-entry.js @@ -0,0 +1 @@ +import "./styles.css"; diff --git a/package.json b/package.json index 250b4be..89fca92 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,9 @@ "files": [ "dist" ], + "sideEffects": [ + "**/*.css" + ], "exports": { ".": { "import": "./dist/es/index.js", @@ -74,7 +77,7 @@ "scripts": { "dev": "vite", "build": "npm run build-lib && npm run build-docs", - "build-lib": "vite build -m lib", + "build-lib": "vite build -m lib && vite build -m css", "build-docs": "vite build", "lhci:prep": "node scripts/extract-routes.js", "lhci:run": "rmdir /s /q .lighthouseci 2>nul & npx @lhci/cli autorun --config=.lighthouserc.gen.json --verbose & node scripts/lhci-index.js", diff --git a/vite.config.js b/vite.config.js index b454898..9686656 100644 --- a/vite.config.js +++ b/vite.config.js @@ -19,6 +19,15 @@ const libraryAssetFileNames = (assetInfo) => { } return "assets/[name][extname]"; }; +const removeCssEntrypointPlugin = (fileName) => ({ + name: "remove-css-entrypoint", + closeBundle() { + const filePath = path.resolve("dist", fileName); + if (fs.existsSync(filePath)) { + fs.unlinkSync(filePath); + } + }, +}); function RoutesToLHCIPlugin() { return { @@ -87,6 +96,28 @@ export default defineConfig(({ mode }) => { }; } + if (mode === "css") { + console.log("Building library CSS"); + return { + plugins: [react(), tailwindcss(), removeCssEntrypointPlugin("style.js")], + publicDir: false, + build: { + emptyOutDir: false, + lib: { + entry: "lib/style-entry.js", + name: "GroundworkStyles", + fileName: () => "style.js", + formats: ["es"], + }, + rollupOptions: { + output: { + assetFileNames: libraryAssetFileNames, + }, + }, + }, + }; + } + console.log("Building preview app", mode); const base = mode === "production" From 44cd6d085070c9024b4580ad34af00197874fb23 Mon Sep 17 00:00:00 2001 From: "Charles Graham, SWT" Date: Wed, 15 Jul 2026 12:59:09 -0500 Subject: [PATCH 3/3] Lazy load heavy visual assets --- lib/composite/footer/essayons.jsx | 22 +++++++++- lib/composite/footer/logo-banner.jsx | 64 ++++++++++++++++++++-------- 2 files changed, 67 insertions(+), 19 deletions(-) diff --git a/lib/composite/footer/essayons.jsx b/lib/composite/footer/essayons.jsx index 9cb2f6a..72ed7b5 100644 --- a/lib/composite/footer/essayons.jsx +++ b/lib/composite/footer/essayons.jsx @@ -1,6 +1,26 @@ -import essayons from "../../img/essayonscrest.png"; +import { useEffect, useState } from "react"; function Essayons() { + const [essayons, setEssayons] = useState(null); + + useEffect(() => { + let cancelled = false; + + import("../../img/essayonscrest.png").then((module) => { + if (!cancelled) { + setEssayons(module.default); + } + }); + + return () => { + cancelled = true; + }; + }, []); + + if (!essayons) { + return null; + } + return ( import("../../img/armystar-logo-rb.svg"), + army250: () => import("../../img/Army-250-year-logo.png"), + usace: () => import("../../img/usace-logo-color.svg"), + usace250: () => import("../../img/USACE-250-year-logo.png"), + rsgis: () => import("../../img/rsgis-logo.png"), + cwbi: () => import("../../img/cwbi-logo.png"), +}; + +function LazyLogo({ loader, ...props }) { + const [src, setSrc] = useState(null); + + useEffect(() => { + let cancelled = false; + + loader().then((module) => { + if (!cancelled) { + setSrc(module.default); + } + }); + + return () => { + cancelled = true; + }; + }, [loader]); + + if (!src) { + return null; + } + + return ; +} function LogoBanner({ army, army250, usace, usace250, rsgis, cwbi }) { return (
{army && ( - U.S. Army - U.S. Army - U.S. Army Corps of Engineers - U.S. Army Corps of Engineers - Remote Sensing - GIS Center of Expertise -