Managing Dependencies ===================== Front-end dependencies are managed using ``yarn`` and are defined in ``package.json`` at the root of the ``commcare-hq`` repository. Most JavaScript on HQ is included on a page via a JavaScript bundle. These bundles are created by Webpack. Webpack is given a list of "entry points" (or pages) and builds a dependency graph of modules to determine what code is needed for a page, combining related code into bundles. These bundles are split along ``vendor`` (npm modules), ``common`` (all of hq), and application (like ``hqwebapp`` or ``domain``). By bundling code, we can make fewer round-trip requests to fetch all of a page's JavaScript. Additionally, the bundler minifies each bundle to reduce its overall size. You can learn more about bundlers in `the Static Files Overview `__ How do I create a new page with JavaScript? ------------------------------------------- New code should be written using the ES Module (ESM) format and bundled using Webpack. This approach is oriented around a single "entry point" per page (with some pages sharing the same entry point). This entry point contains the page-level logic needed for that page and imports other modules for shared logic. A typical new module structure will look something like: :: import "commcarehq"; // REQUIRED at the top of every "entry point" // This loads site-wide dependencies needed to run global navigation, modals, notifications, etc. // Common third-party dependencies import $ from "jquery"; // Ideally, new pages should move away from jQuery and use native // javascript. But this is here as an example. import ko from "knockout"; import "hqwebapp/js/knockout_bindings.ko"; // This one doesn't need a named parameter because it only adds // knockout bindings and is not referenced in this file import _ from "underscore"; // A commonly used internal module for passing server-side data to the front end import initialPageData from "hqwebapp/js/initial_page_data"; /* page-level entry point logic begins here */ To register your module as a Webpack entry point, add the ``js_entry`` template tag to your HTML template, near the top and outside of any other block: :: {% js_entry 'prototype/js/example' %} Some pages don't have any unique logic but do rely on other modules. These are usually pages that use some common widgets but don't have custom UI interactions. If your page only relies on a single JavaScript module, you can use that as that page's entry point: :: {% js_entry 'locations/js/widgets' %} If your page relies on multiple modules, it still needs one entry point. You can handle this by making a module that only imports other modules. For instance an entry point located at ``prototype/js/combined_example.js`` might look like: :: import "commcarehq"; // always at the top import "hqwebapp/js/crud_paginated_list_init"; import "hqwebapp/js/bootstrap5/widgets"; // No page-specific logic, just need to collect the dependencies above Then in your HTML page: :: {% js_entry 'prototype/js/combined_example' %} The exception to the above is if your page inherits from a legacy page that doesn't use a JavaScript bundler, like in app manager. This is rare, but one example would be adding a new page to app manager that inherits from ``apps_base.html``. How do I add a new internal module or external dependency to an existing page? ------------------------------------------------------------------------------ ESM modules provide an extensive and flexible way of managing and naming imports from dependencies. :: import myDependency from "hqwebapp/js/my_new_dependency"; myDependency.myFunction(); // using only portions of an dependency import { Modal } from "bootstrap5"; const myModal = new Modal(document.getElementById('#myModal')); // this also works import bootstrap from "bootstrap5"; const myOtherModal = new bootstrap.Modal(document.getElementById('#myOtherModal')); // you can also alias imports import * as myAliasedDep from "hqwebapp/js/my_other_dependency"; My python tests are failing because of javascript ------------------------------------------------- Failures after "Building Webpack" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The JavaScript tests run in Github Actions ``yarn build`` to check that ``webpack`` is building without errors. You can run ``yarn build`` locally to simulate any errors encountered by these tests. Since you are likely developing using ``yarn dev``, you should have already encountered the build errors during development. However, if the development build of Webpack is running without failures, please check the ``webpack/webpack.prod.js`` configuration for possible issues if the error messages don't yield anything useful. My deploy is failing because of javascript ------------------------------------------ Webpack Failures ~~~~~~~~~~~~~~~~ Webpack failures during deploy should be rare if you were able to run ``yarn dev`` successfully locally during development. However, if these failures do occur, it is likely due to issues with supporting deployment infrastructure. Is the version of ``npm`` and ``yarn`` up-to-date on the deploy machines? Are the supporting scripts outlined in the staticfiles_collect tasks for `Webpack `__ configured properly?