Skip to content

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 nameEntry pointLoaded by
adminstatic/js/pack_admin.mjsAll admin portal pages
userstatic/js/pack_user.mjsClient portal pages (IPs, EDs, GCs, SDs)
gurgleclientstatic/js/pack_gurgleclient.mjsIn-app messaging pages
journey_pagestatic/js/pack_journey.mjsCase journey page
form_intakestatic/js/pack_intake.mjsForm submission / intake pages
profilestatic/js/pack_profile.mjsProfile editing pages

Build outputs

Build typeJS outputCSS output
Developmentstatic/js/[name].bundle.jsstatic/css/[name].bundle.css
Productionstatic/js/[name].bundle.min.jsstatic/css/[name].bundle.min.css

Build commands

Terminal window
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 prod

Static 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:

  1. Which portal does this feature live in? Admin → admin bundle. Client portal → user bundle. Messaging → gurgleclient. Journey page → journey_page. Forms → form_intake. Profile editing → profile.

  2. Open the entry point file (pack_admin.mjs, etc.) to see what it imports.

  3. Add your module to the right entry point or create a new module file and import it.

Example: adding JS to the admin bundle

static/js/my_admin_feature.mjs
export function initMyFeature() {
document.querySelectorAll('.my-button').forEach(btn => {
btn.addEventListener('click', () => {
// ...
});
});
}
static/js/pack_admin.mjs
import { initMyFeature } from './my_admin_feature.mjs';
// Initialize when DOM is ready
document.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-loaderpostcss-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.

  1. Create the entry point file: static/js/pack_myfeature.mjs
  2. Add it to webpack.config.js:
entry: {
// existing entries...
myfeature: './static/js/pack_myfeature.mjs',
}
  1. Load the built bundle in the relevant Jinja2 template(s)
  2. Update this page to document the new bundle