/benefit-finder
|-.husky
|-git-hooks
|-.storybook
|-cypress
|-nginx
|-src
|-App
|-Routes
|-shared
|-api
|-components
|-ComponentName
|-__tests__
|-__snapshots__
index.spec.js
indexComponentName.spec.cy.js
_index.scss
index.jsx
index.stories.jsx
|-hooks
|-locales
|-style-docs
|-styles
|-utils
|-index.jsx
|-setupTest.js
|-vite-config
|-README.md
- "Modules", like
App
should follow the structure of routes. - Files from one module can only import from ancestor folders within the same module or from
src/components/shared
.
File or folder | Description |
---|---|
src/index.jsx |
Entry file. |
index.html |
All scripts and styles injected here |
src/App |
Main application routes, global / ancestor of all modules. |
src/Routes |
Route components |
src/shared/api |
dev utils for interacting with data |
src/shared/components |
Components, constants, machines, hooks, styles, utils etc; |
src/shared/hooks |
Custom Hooks |
src/shared/style-docs |
mdx files for !stories documentation |
src/shared/styles |
scss partials |
src/shared/utils |
custom Javascript utilities |
vite-config.mjs |
vite bundler config, imports from vite-config dir |
Any module is allowed to import from shared. |
file type | Description |
---|---|
.jsx |
React functional components |
.js |
ES |
.stories.jsx |
Component Story Format files for storybook stories |
.mdx |
Markdown files that accept ES imports for storybook docs |
.md |
Markdown files for project docs |
.mjs |
ES Module File |
.spec.js |
Testing specification |
.spec.cy.js |
Cypress testing specification |
.spec.js.snap |
Testing snapshots |
.hbs |
Handlebars (used in plop generated components) |
.scss |
Syntactically awesome style sheets |
.json |
JavaScript Object Notation |
*rc |
Resource files |
*sh |
Bash files |
This project was bootstrapped with Create React App.
npm install
- Copy environment example file
cp .env.local.example .env.local
- Replace env variable as needed
There are three local build environments, one for our component workshop (Storybook), another for our Application (Vite), and finally a test e2e test env (Cypress).
Run development workshop
npm run dev:storybook
Run development server from vite.config.mjs
npm run dev
Run e2e development config
npm cy:dev:storybook
We use husky to manage git hooks.
husky is automatically installed after the packages are installed.
-
The
pre-commit
git hook leverageslint-staged
to run a series of scripts on any staged files when a commit is made. -
The
pre-push
git hook runs a series of scripts on the directory before pushing to the origin.
We use a combination of linting and best practices to guide code consistency.
We include a few scripts in package.json
that can be executed to interact with our standards.
Run eslint on .js
and .jsx
files
npm run lint:js
Auto-fix lint errors
npm run lint:js:fix
Format .js
and .jsx
files with prettier.
npm run format
Run stylelint on .scss
files
npm run lint:scss
Auto-fix lint errors
npm run lint:scss:fix
We also carry the following working agreements that may fall outside of the linting.
If you have this...
<Foo onClick={function () { alert("1337") }} />
We prefer this
<Foo onClick={handleAlert} />
If you have this...
<Foo style={{ width: 100% }} />
We prefer this
<Foo class="full-width" />
Typecheck with PropTypes
We take a utility first approach. We do not have full control over our styles since a custom version of USWDS already exist in the usa.gov project.
- we establish uswds components with
usa-<class>
classes. - this inherits global
uswds
css
andjs
- IF we need to override, we clone the uswds class
usa-
and prependbf-
.
.bf-usa-<class> .usa-<class>
- custom classes do not include
usa-
but still includebf-
.bf-<class>
We use Sass and Sass Modules
Generally, it is recommend that you don’t reuse the same CSS classes across different components. For example, instead of using a .usa-button
CSS class in <AcceptButton>
and <RejectButton>
components, it is recommended to create a <Button>
component with its own .usa-button
styles, that both <AcceptButton>
and <RejectButton>
can render (but not inherit).
We use composition, but leverage the https://designsystem.digital.gov/. We will attempt to use pre-processor methods when it makes sense to do so.
We use inline documentation for functions, hooks, and functional components.
Example with function
/**
* a boolean function that returns a component when true.
* @function
* @param {boolean} value - the inherited value, can be true || false
* @return {component} returns a component if true
*/
const handleTruth = value => value === true && <Truth />
Example with hook
/**
* a boolean that manages the state of truth.
* @function
* @param {boolean} value - the inherited value, can be true || false
* @return {state} returns an updated state for value
*/
const [value, setValue] = useState(true)
Example with functional component
/**
* a functional component that wraps form elements in a form element
* @component
* @param {node} children - inherited children
* @return {html} returns a semantic html div element, with all its children
*/
function Value = ({ children }) => (<div className="wrapper">{children}</div>)
We use Vitest for Unit/DOM testing
npm run test
npm run cy:run:e2e
Description: Runs the end-to-end (E2E) tests in the test environment using the Chrome browser.
npm run cy:run:prod:links:e2e
Description: Runs the E2E tests using the production configuration for testing links, with the Chrome browser.
For more information, refer to the Cypress Documentation.
We build each of our components with spec
, scss
, stories
and jsx
files
|-ComponentName
|-__tests__
|-__snapshots__
index.spec.js
_index.scss
index.jsx
index.stories.jsx
To generate a component with these files based on a name space, you can use plop
cd
to the root of the application
npm run generate:component <component-name>
It's important to export components from the root of the shared index file. This is where you will import and destructure across other documents.