/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 overide, 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
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.