Contributing Guidelines
Table of Contents
Project Structure
Contributing
Requirements
docker>=17.0.0
docker-compose>=1.17.0
node>=10.0.0
Set-up dev environment
#. If not yet done, clone project locally
#. If not yet done, install node dependencies
#. Start application
You can now access application in dev mode at http://localhost
Start developing
Create a new branch
Requirements
New branch MUST be started from development (which is our dev branch)
Feature branch MUST be named
feature/[a-zA-Z0-9\-]+
Bug fix branch MUST be named
fix/[a-zA-Z0-9\-]+
Branch referring to an open issue MUST be named
(fix|feature)/<issue-ID>
Develop on new branch being careful to write test for every change you proceed to
Push branch
Pushing will trigger a CI pipeline (see section CI/CD)
Create a pull request
Install new dependencies
Command above can sometime error with EACCES
code, this means that docker wrote some files (usually cache) in your local node_modules
folder. To solve it you can change right access of the folder by running command
Release a new version
Create a release branch
release/x.x.x
Bump to version
x.x.x
package.json
: change version tox.x.x
CHANGELOG.md
: ensure release sectionx.x.x
documentation is exhaustive and set release date
Commit with message
bump version to x.x.x
Tag version
Bump to version
increment(x.x.x)-dev
package.json
: change version toincrement(x.x.x)-dev
CHANGLOG.md
: create emptyincrement(x.x.x)-dev
section with unreleased status
Push branch and tags
Proceed to merge request
release/x.x.x
->master
Tests
Commands
Run test
Display more DOM lines when a test fails
Run coverage
Practices
Test framework
We use Jest test framework (directly packed into create-react-app
We use React testing library to test components
Requirements
Tests MUST be written in a
**/__tests__
folder located in the same directory as the element testedTests file for
<filename>.js
MUST be named<filename>.test.js
SHOULD use Jest snapshot testing
Folder structure
Testing guidelines
Here are some useful reading to help you write tests:
https://kentcdodds.com/blog/how-to-know-what-to-test
https://kentcdodds.com/blog/common-mistakes-with-react-testing-library
Anything displayed here: https://kentcdodds.com/testing/
Test example
Code linting
Framework
We use ESLint (packed in create-react-app)
This project use a combination of husky, lint-staged, prettier to format code automatically including .js,.jsx, .json and .css (c.f create-react-app documentation.
Some pre-commit hooks are set-up so whenever you make a commit, prettier will format the changed files automatically.
Requirements
Code MUST respect linting rules defined in
.eslintrc
Commit Linting
Framework
We use commitlint
The Conventional Commits specification is a lightweight convention on top of commit messages. It provides an easy set of rules for creating an explicit commit history; which makes it easier to write automated tools on top of. This convention dovetails with SemVer, by describing the features, fixes, and breaking changes made in commit messages.
The commit message should be structured as follows:
Types of commit:
feat: Add a new feature to the codebase (MINOR in semantic versioning).
fix: Fix a bug (equivalent to a PATCH in Semantic Versioning).
docs: Documentation changes.
style: Code style change (semicolon, indentation...).
refactor: Refactor code without changing public API.
perf: Update code performances.
test: Add test to an existing feature.
ci: Update continuous integration processes
chore: Update something without impacting the user (ex: bump a dependency in package.json).
Requirements
Commits MUST be prefixed with a type, which consists of a noun,
feat
,fix
, etc., followed by the OPTIONAL scope, OPTIONAL!
, and REQUIRED terminal colon and space.The type
feat
MUST be used when a commit adds a new feature to your application or library.The type
fix
MUST be used when a commit represents a bug fix for your application.A scope MAY be provided after a type. A scope MUST consist of a noun describing a section of the codebase surrounded by parenthesis, e.g.,
fix(parser):
A description MUST immediately follow the colon and space after the type/scope prefix. The description is a short summary of the code changes, e.g., fix: array parsing issue when multiple spaces were contained in string.
A longer commit body MAY be provided after the short description, providing additional contextual information about the code changes. The body MUST begin one blank line after the description.
A commit body is free-form and MAY consist of any number of newline separated paragraphs.
One or more footers MAY be provided one blank line after the body. Each footer MUST consist of a word token, followed by either a
:<space>
or<space>#
separator, followed by a string value (this is inspired by the git trailer convention).A footer’s token MUST use
-
in place of whitespace characters, e.g.,Acked-by
(this helps differentiate the footer section from a multi-paragraph body). An exception is made forBREAKING CHANGE
, which MAY also be used as a token.A footer’s value MAY contain spaces and newlines, and parsing MUST terminate when the next valid footer token/separator pair is observed.
Breaking changes MUST be indicated in the type/scope prefix of a commit, or as an entry in the footer.
If included as a footer, a breaking change MUST consist of the uppercase text BREAKING CHANGE, followed by a colon, space, and description, e.g., BREAKING CHANGE: environment variables now take precedence over config files.
If included in the type/scope prefix, breaking changes MUST be indicated by a
!
immediately before the:
. If!
is used,BREAKING CHANGE:
MAY be omitted from the footer section, and the commit description SHALL be used to describe the breaking change.Types other than
feat
andfix
MAY be used in your commit messages, e.g., docs: updated ref docs.The units of information that make up Conventional Commits MUST NOT be treated as case sensitive by implementors, with the exception of BREAKING CHANGE which MUST be uppercase.
BREAKING-CHANGE MUST be synonymous with BREAKING CHANGE, when used as a token in a footer
Files organization & file naming convention
Redux related files go into src/redux
We make active usage of redux, if not familiar with redux we recommend going through redux documentation before going through this section.
Requirements
Actions MUST go into a into src/redux/actions
Reducers MUST go into a into src/redux/reducers
Enhancers MUST go into a into src/redux/enhancers
Folder structure
Reducers
We highly recommend you reading more about structuring reducer
Requirements
State structure (or state shape) MUST be defined in terms of domain data & app status, it MUST NOT be defined after your UI component tree
Root reducer (feeded to createStore()) MUST combine together specialized reducers:
data reducers, handling the data application needs to show, use, or modify (typically information retrieved from some APIs)
status reducers, handling information related to application's behavior (such as "there is a request in progress")
ui reducer, handling how the UI is currently displayed (such as "Sidebar is open")
Global state shape MUST reflect src/redux/reducers/ folder structure. Keys in global state MUST be the same as file names src/redux/reducers/
Specialized reducer files MUST implement a reducer function exported as default
Folder structure
Corresponding state shape would be
Example
Actions
Actions are payloads of information that send data from your application to your store. They are the only source of information for the store. You send them to the store using store.dispatch().
Requirements
Actions MUST be grouped by piece of state they cover (e.g. UI actions are defined into src/redux/actions/ui.js)
Each action type MUST be declared as a constant
Each action SHOULD come with an action creator function
Action types & creator functions MUST be implemented in the same file
Actions MUST be serializable (if you think in passing a function into an action for handling by reducers, it means that you actually need a redux middleware)
Actions MUST follow Flux-Standard-Action(https://github.com/redux-utilities/flux-standard-action#actions) format
MUST be a plain JavaScript object
MUST have a
type
propertyMAY have an
error
propertyMAY have an
payload
propertyMAY have an
meta
propertyMUST NOT include property other than
type
,error
,payload
andmeta
There SHOULD NOT be a 1-to-1 link between actions and reducers. Typically an action could be reduced by multiple reducers
Folder structure
Example
Enhancers and middlewares
Store enhancers are higher-order function that composes a store creator to return a new, enhanced store creator. In our case, we mainly use enhancer to add redux middlewares allowing to hook custom behaviors when dispatching actions.
We highly recommend you reading more about middlewares in redux
Requirements
Middlewares MUST go into src/redux/enhancers/middlewares
Folder structure
Components go into src/components
Requirements
All components MUST go into src/components
Components MUST have a unique name
Module specific components go into src/components/
Requirements
Component files MUST go into a into a folder named after the component in src/components/
Component code MUST be split into as many atomic sub components as necessary
Component MUST follow naming pattern path-based-component-naming, which consists in naming the component accordingly to its relative path from src/components/
Examples of those components are
Skeleton elements such as AppBar, Sidebar
View panels such as Home
Layout elements such as Layout
Folder structure and file naming
Component naming
Main component
Sub component
Generic atomic reusable components go into src/components/UI
Requirements
Generic UI components MUST NOT held business logic specific to the application (they actually could be stored on some external npm library)
MUST follow naming pattern path-based-component-naming, which consists in naming the component accordingly to its relative path from src/components/UI
Examples of those components are: Button, Input, Checkbox, Select, Modal, etc…
Folder structure and file naming
Containers go into src/containers
Requirements
Container MUST go into src/containers
Container MUST follow same relative path from src/containers as the component it wraps from src/components
Container MUST have same name as the component it wraps
Folder structure
Custom hooks go into src/hooks
Requirements
Custom hook MUST go into src/hooks
Custom hook's name MUST start with use (for example: useTimer)
Folder structure
Component & Container separation pattern
We respect a separation between presentational components & containers.
Motivation for the pattern
Better separation of concerns makes app understandable and better UI writing components this way.
Better reusability. Same presentational component can be used with completely different state sources, and turn those into separate container components that can be further reused.
Presentational components are essentially app’s “palette”. It is possible to put them on a single page and let designers tweak all their variations without touching the app’s logic. It is possible to run screenshot regression tests on that page.
This forces to extract “layout components” such as Sidebar, AppBar, etc. and use this.props.children instead of duplicating the same markup and layout in several container components.
You can read more about it here
Components (or presentational components) are concerned with how things look
Requirements
SHOULD implement some DOM markup and styles of their own
MAY contain both presentational components and containers
SHOULD allow containment via this.props.children.
SHOULD NOT have their own state (when they do, it MUST be UI state and MUST NOT be data)
SHOULD be written as functional components unless they need state, lifecycle hooks, or performance optimizations
MUST receive data and callbacks exclusively via props.
MUST NOT have dependencies with the rest of the app, such as redux actions or stores
MUST NOT specify how the data is loaded or mutated (API calls MUST NOT be defined in a component)
MUST NOT define any route
Implement a component
Set imports
Requirements
MAY import components from UI libraries typically Material-UI
MAY import components and containers from the rest of the application
SHOULD NOT import any resources related to Redux, except compose() that is sometime convenient to connect multiple material-ui wrappers (withStyles(), withTheme()...)
SHOULD NOT have any dependencies in the rest of the application, except components or containers
MUST be organized in 3 ordered sections: 1. low-level React imports / 2. Material-UI imports / 3. intra-application imports
Example
Define styles
Requirements
MUST be a function taking theme as argument and returning an object
Example
Code component
Requirements
SHOULD be a function taking a props object as an argument (except lifecycle, UI state or some optimization are required)
MUST respect component naming convention (see below)
MUST be atomic
MUST be agnostic of the rest of the application, this MUST include every variable namings. Think it as it should be able to exist on its own
MUST be documented with PropTypes
Example
Connect styles and export
Requirements
MAY inject styles information using withStyle(), makeStyle(), _withTheme(), withWidth()
There MUST be one unique export
Example
Basic: only withStyle()
Advanced: using compose() from redux
Containers are concerned with how things work
Requirements
MAY contain both presentational components and containers
SHOULD NOT define DOM markup of their own (except for some wrapping divs)
MUST NOT have styles
MAY provide the data and behavior to presentational or other container components.
MAY organise components/containers using routes
MAY implement redux related elements mapStateToProp(), mapDispatchToProps(), mergeProps() and connect it to presentational component using connect()
MAY implement API calls or other side effects
MAY be stateful, as they tend to serve as data sources
Implement a container
Set imports
Requirements
MAY import elements from state management libraries elements (redux, react-redux)
MAY import elements from src/redux such as actions or selectors
MAY import elements from routing library
MAY import Material-UI utilities such as isWidthUp()
Example
Code container
Requirements
SHOULD NOT define DOM markup of their own (except for some wrapping divs)
MAY define route
MAY implement hooks on React lifecycle
MUST respect
Example
Lifecycle container
Routing container
Implement mapStateToProps(state, [ownProps]), mapDispatchToProps(dispatch, [ownProps]), mergeProps(stateProps, dispatchProps, ownProps)
Requirements
MAY implement mapStateToProps(state, [ownProps])
MAY implement mapDispatchToProps(dispatch, [ownProps]). If it is only required to map action creators it MUST be an object
MAY implement mergeProps(stateProps, dispatchProps, ownProps)
Aggregating props MUST NOT be performed within container, ownProps and mergeProps() allow to accomplish it properly out of the component (c.f. https://github.com/reduxjs/react-redux/blob/master/docs/api.md)
Example
Connect container & export
Requirements
MAY connect redux information to a comp
MUST be one unique export
Example
Others
Error handling: Refer to to this article for handling async errors using our built ErrorFallback.js file.
Material-UI
Theme
Material UI theme is declared in ./src/themes/theme.js
CSS classes
To apply styling on specific components and not in the full app, use Material-UI overrides
UI width
To make UI fully responsive, you can use Material-UI breakpoints
Audit application
Use Lighthouse of Google in order to audit your PWA and see what's missing (icons, https, ...)
Follow the guidelines here (Google opinionated way of building PWA)
Conventions
RFC keywords
MUST This word, or the terms "REQUIRED" or "SHALL", mean that the definition is an absolute requirement of the specification.
MUST NOT This phrase, or the phrase "SHALL NOT", mean that the definition is an absolute prohibition of the specification.
SHOULD This word, or the adjective "RECOMMENDED", mean that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course.
SHOULD NOT This phrase, or the phrase "NOT RECOMMENDED" mean that there may exist valid reasons in particular circumstances when the particular behavior is acceptable or even useful, but the full implications should be understood and the case carefully weighed before implementing any behaviour described with this label.
MAY This word, or the adjective "OPTIONAL", mean that an item is truly optional. One vendor may choose to include the item because a particular marketplace requires it or because the vendor feels that it enhances the product while another vendor may omit the same item. An implementation which does not include a particular option MUST be prepared to interoperate with another implementation which does include the option, though perhaps with reduced functionality. In the same vein an implementation which does include a particular option MUST be prepared to interoperate with another implementation which does not include the option (except, of course, for the feature the option provides.)
Last updated