When importing dependencies we loosely follow some general rules and strictly follow others.
The canonical ordering list lives in /AGENTS.md; this is the worked example.
// 3rd party dependencies generally in order or "lowest-level" dependency
import { extend } from 'underscore';
import hbs from 'handlebars-inline-precompile'; // not really a dependency, but indirectly used by Marionette
import { View } from 'marionette';
// General css goes next before any local imports
import 'scss/modules/global.scss';
// Utilities
import funFormatter from 'js/utils/fun-formatter';
import intl from 'js/i18n';
// Base classes
import App from 'js/base/app';
// Entities and service modules
import { Model as PatientModel } from 'js/entities-service/entities/patients';
// Apps (typically alphabetically)
import ChildApp from 'js/apps/foo/child/child_app';
import LocalDepApp from './local_app';
// Other Mn classes in no particular order (there's usually not many)
import FooBehavior from 'js/behaviors/foo';
import FooRegion from 'js/regions/foo';
import FooComponent from 'js/components/foo';
// Views (typically alphabetically)
import { FooView, BarCollectionView } from 'js/apps/foo/child/child_views';
import { LocalDepView } from './local_views';
// Structural templates; leaf templates are typically inlined with hbs``
import FooTemplate from './foo.hbs';
// App-shared and cross-app domain css come after dependencies that may import styles
import 'js/apps/foo/shared/foo.scss';
import 'scss/domain/foo.scss';
// Local css
import './for-this-view.scss';Keep a template inline when it is a leaf fragment that makes the view easier to understand beside its behavior. Typical examples include button contents, icons, labels, status values, empty messages, and small picklist items with shallow conditional rendering.
Use a colocated .hbs file when the template defines structure that is meaningful independently of the view behavior. Page and application layouts, list rows, result items, loading skeletons, multi-region views, editor bodies, and members of an existing template family generally belong in files.
Template length is only a signal. Long attributes and translation keys do not make a cohesive leaf fragment structural, while a short template that defines a page's region topology may still deserve a file. Do not introduce a shared or configurable template merely because two views currently have similar markup; extracting a template file is separation, not abstraction.
Rather than needing to import files relatively, by resource asset directories are aliased with vite. The aliases can be found here: https://github.com/RoundingWell/app-frontend/blob/develop/vite.config.js
These aliases allow for any js file, no matter its location within the js directory to import like so:
import { FooView } from 'js/apps/foo/foo_views';See AGENTS.md for this app's
installed contract, integrations, ownership entrypoint, and packaged documentation
helper. Use the marionette skill supplied by Marionette's upstream plugin to
select the matching framework API guide for the task.
This repo requires template element selectors in the View's ui hash and access
through getUI, keeping selector queries out of View methods. The packaged
docs/dom.interactions.md explains the native DOM values and event APIs.
All trigger and event names should be wrapped in ''.
Incorrect way:
trigger:something:happened: this.onSomethingHappenedCorrect way:
'trigger:something:happened': this.onSomethingHappenedEvents should alway indicate something that happened and not an action to take.
Ideally named verb:name like click:fooButton or sometimes context:verb:name like state:change:foo.
Ideally handlers also indicate handling the event rather than a specific action.
Particularly if an event handler does more than one thing.
Should not be wrapped in ''. For example:
Incorrect way:
const x = {
'foo':'bar',
'bar':'foo'
};Correct way:
const y = {
foo: 'bar',
bar: 'foo'
};Note: Our linter currently cannot lint this.
-
Prefer
consttolet. Novar! -
Only use destructuring when it clarifies the code.
-
Use => functions for setting context when possible. Note that arrow functions do not have an
argumentsvariable.