Skip to content

Frontend asset builds

Three self-hosted, committed JavaScript bundles plus one committed CSS file are built from source via npm. Node and npm are not a runtime dependency of the deployed app and aren’t used in the Docker image at all. They’re only a dev-time tool for whoever next touches the editor JS, date-picker JS, or Tailwind classes. There is no engines field in this repo’s package.json, so no specific Node version is enforced by the build itself, any reasonably current Node install should work.

editor-src/main.js, the rich-text editor used for finding content, report text blocks, and observations and testing phases, is bundled by esbuild into static/vendor/redscribe-editor.bundle.js. The exact invocation, from package.json’s build:editor script, is:

Terminal window
esbuild editor-src/main.js --bundle --format=iife --outfile=static/vendor/redscribe-editor.bundle.js --minify

--format=iife wraps the whole bundle in an immediately invoked function expression, so it can be loaded with a plain <script> tag and never pollutes the global scope beyond whatever it explicitly attaches. It depends on @tiptap/core, @tiptap/starter-kit, @tiptap/pm, and a set of individual extension packages (extension-paragraph, extension-image, extension-code-block, extension-highlight, extension-underline, extension-link, and the four table extensions), all pinned to the same 2.27.3 minor line in package.json’s devDependencies.

  1. Terminal window
    npm install
  2. Terminal window
    npm run build:editor
  3. Commit the updated static/vendor/redscribe-editor.bundle.js.

datepicker-src/main.js, wrapping flatpickr, is bundled the same way into static/vendor/redscribe-datepicker.bundle.js:

Terminal window
npm run build:datepicker

This one is easy to forget since it doesn’t come up as often as the editor or Tailwind bundles. If date fields across the app start looking like plain unstyled <input type="date"> elements after a dependency bump, this is the bundle to rebuild.

strength-src/main.js, using zxcvbn-ts (@zxcvbn-ts/core plus the language-common and language-en dictionary packages), is bundled into static/vendor/redscribe-password-strength.bundle.js. It attaches to every input[type="password"] on the page whose id ends in password1, which is Django’s own naming convention for the first of a two-field password-confirmation pair, so it only ever shows up next to a password-creation field, never a login field. It’s client side, advisory-only feedback. The actual policy is enforced server side by AUTH_PASSWORD_VALIDATORS (config/settings/base.py), independent of whatever this widget displays, so a browser with JavaScript disabled or a direct API call is never able to bypass the real policy just because the meter didn’t run.

Terminal window
npm run build:strength

tailwind-src/input.css, the theme tokens and component classes documented in COLOR_SCHEME.md at the repo root, is compiled by the Tailwind CLI (@tailwindcss/cli) into static/css/tailwind.css, scanning every template in the repo for utility class usage automatically, with --minify applied:

Terminal window
npm run build:css
Terminal window
npm install
npm run build

This runs build:editor, build:strength, build:datepicker, and build:css in sequence, then you commit the updated files in static/vendor/ and static/css/.

  • Missing packages or a version mismatch error from esbuild or the Tailwind CLI: run npm install again. node_modules/ is gitignored, so a fresh clone or a package.json change both need it before any build:* script will find its dependencies.
  • esbuild: command not found: the same fix, npm install puts esbuild in node_modules/.bin/, and npm run picks it up from there automatically. Don’t try to invoke esbuild as a global command unless you’ve installed it globally yourself, the scripts don’t assume that.
  • Tailwind classes you added to a template don’t show up after build:css: Tailwind only picks up class names it can find as literal strings while scanning template files, so a dynamically constructed class name (built by concatenating strings in a template tag, for instance) won’t be detected. Write the full class name literally somewhere Tailwind can scan it.