2.4 KiB
Bootstrap Subset Build Proposal
KarlDNS currently serves the local Bootstrap 5.3.8 asset at /bootstrap-5.3.8.min.css. The local full file is 226.7 KiB raw and 30.1 KiB gzip.
Current Bootstrap Surface
Static templates and asset JavaScript use a small Bootstrap surface:
- Layout:
container,row,col-*,d-flex,d-grid,gap-*, responsive flex alignment, spacing utilities,w-100,h-100. - Components:
alert,badge,btn,card,form-control,form-select,form-check,input-group,nav,navbar,pagination,table. - Helpers/utilities:
border*,rounded*,text-*,text-bg-*,text-truncate,visually-hidden,opacity-75,small. - JavaScript-created classes in
router_dyndns/routers/assets.py:page-item,disabled,active,page-link,empty-row,empty.
The app CSS in router_dyndns/web/styles.py already owns the custom KarlDNS look. Bootstrap is mainly supplying reset, grid, forms, buttons, tables, navigation, pagination, and common utilities.
Proposed Build
Use scripts/build-bootstrap-subset.py to compile a Bootstrap Sass subset from transient npm packages:
python3 scripts/build-bootstrap-subset.py
python3 scripts/build-bootstrap-subset.py --write
The script imports Bootstrap 5.3.8 Sass modules for the components above and filters $utilities before utilities/api so unused utility families are not emitted. It does not require a committed package.json, lockfile, or node_modules.
Dry-run result on this worktree:
- Subset: 113.8 KiB raw, 16.8 KiB gzip.
- Full local asset: 226.7 KiB raw, 30.1 KiB gzip.
- Reduction: 49.8% raw, 44.2% gzip.
Rollout Recommendation
Keep the current app references unchanged until the subset is visually tested. The safe implementation sequence is:
- Run
python3 scripts/build-bootstrap-subset.py --writeto createrouter_dyndns/assets/bootstrap-karldns.min.css. - Add an isolated asset route for
/bootstrap-karldns.min.css. - Switch
_page()from/bootstrap-5.3.8.min.css?v=2to/bootstrap-karldns.min.css?v=1. - Run UI tests and browser-check public, dashboard, locked dashboard, admin tables, pagination, dark mode, and copy fields.
Do not use a selector-purge pass against rendered HTML yet. The Python templates include dynamic branches and JavaScript-created pagination classes, so Sass module selection plus a curated utility allowlist is simpler and less likely to break rare pages.