Frontend Bundles
Overview
Orchid’s frontend is not a single-page app. It is server-rendered HTML (via Jinja2) with JavaScript layered on top. Webpack bundles JavaScript and SASS into feature-specific bundles that are loaded by specific pages.
The six bundles
| Bundle name | Entry point | Loaded by |
|---|---|---|
admin | static/js/pack_admin.mjs | All admin portal pages |
user | static/js/pack_user.mjs | Client portal pages (IPs, EDs, GCs, SDs) |
gurgleclient | static/js/pack_gurgleclient.mjs | In-app messaging pages |
journey_page | static/js/pack_journey.mjs | Case journey page |
form_intake | static/js/pack_intake.mjs | Form submission / intake pages |
profile | static/js/pack_profile.mjs | Profile editing pages |
Build outputs
| Build type | JS output | CSS output |
|---|---|---|
| Development | static/js/[name].bundle.js | static/css/[name].bundle.css |
| Production | static/js/[name].bundle.min.js | static/css/[name].bundle.min.css |
Build commands
npm run build-dev # Development build (fast, no minification)npm run build-prod # Production build (slow, minified + tree-shaken)npm run build # Both dev and prodStatic file structure
Directorystatic/
Directoryjs/
- pack_admin.mjs — admin bundle entry point
- pack_user.mjs — user bundle entry point
- pack_gurgleclient.mjs — gurgle bundle entry point
- pack_journey.mjs — journey bundle entry point
- pack_intake.mjs — intake bundle entry point
- pack_profile.mjs — profile bundle entry point
- admin.bundle.js — built output (dev)
- admin.bundle.min.js — built output (prod)
- (other built bundles…)
Directoryvendor/ — third-party libraries (NOT bundled by Webpack)
- …
Directorycss/
- admin.bundle.css — built CSS (dev)
- admin.bundle.min.css — built CSS (prod)
- (other built CSS…)
- bundle_version.json — timestamp written after each build
Which bundle to edit
Finding where to add JavaScript for a new feature:
-
Which portal does this feature live in? Admin →
adminbundle. Client portal →userbundle. Messaging →gurgleclient. Journey page →journey_page. Forms →form_intake. Profile editing →profile. -
Open the entry point file (
pack_admin.mjs, etc.) to see what it imports. -
Add your module to the right entry point or create a new module file and import it.
Example: adding JS to the admin bundle
export function initMyFeature() { document.querySelectorAll('.my-button').forEach(btn => { btn.addEventListener('click', () => { // ... }); });}import { initMyFeature } from './my_admin_feature.mjs';
// Initialize when DOM is readydocument.addEventListener('DOMContentLoaded', () => { initMyFeature();});SASS / CSS
SASS files are imported in the entry point .mjs files:
// In pack_admin.mjs or a module it imports:import '../css/my_feature.scss';SASS files live in static/css/. They are compiled by the Webpack sass-loader → postcss-loader (autoprefixer) → MiniCssExtractPlugin pipeline into the bundle’s CSS output file.
Key frontend libraries
These libraries are available in all bundles:
- jQuery (
$) — DOM manipulation, AJAX - DayJS — date handling (replaces Moment.js)
- Chart.js — charts and graphs in reports/dashboard
- Quill — rich text editor (used for notes and email compose)
- Socket.IO client — real-time messaging (Gurgle)
- DOMPurify — HTML sanitization client-side
Third-party libraries in static/js/vendor/ are loaded separately in templates, not through Webpack.
bundle_version.json
After each build, Webpack writes a timestamp to static/bundle_version.json. This is referenced in templates to add a cache-busting query parameter to bundle URLs:
{# In templates — the bundle_version prevents stale JS after deploys #}<script src="{{ url_for('static', filename='js/admin.bundle.min.js') }}?v={{ bundle_version }}"></script>Adding a new entry point (rare)
Only add a new bundle if a new, genuinely distinct page context requires its own isolated JavaScript. The bar is high — most new features should extend an existing bundle.
- Create the entry point file:
static/js/pack_myfeature.mjs - Add it to
webpack.config.js:
entry: { // existing entries... myfeature: './static/js/pack_myfeature.mjs',}- Load the built bundle in the relevant Jinja2 template(s)
- Update this page to document the new bundle