ES module is a .js
file with at least one export or folder containing index.js
with at least one export.
The guiding module structure design principle is: you should imagine that any module might be extracted to its own package some day.
First, file paths in MacOS and Windows are case-insesitive. Developer on MacOS could misspell a component module named SignUpForm
as components/SignupForm/
then import {SignUpForm} from '@app/components'
and not to get an error. After changes are pushed to the CI, it will crash with an error if being run on GNU/Linux, where file paths are case-sensitive.
Second, see the guiding principle. Package name cannot contain uppercase letters.
Therefore, camelCase should never be used. This leaves snake_case and kebab-case.
kebab-case is by far the most common convention today. The only use of underscores is for internal node packages, and this is simply a convention from the early days.
components/ — exports presentational components; has no default export
containers/ — exports container components; has no default export
store/ — exports the store object by default
actions/ — exports Redux async action creators; has no default export
reducers/ — exports Redux reducers; exports the root reducer by default
sagas/ — (if redux-saga is used) exports Redux sagas; exports the root saga by default
epics/ — (if redux-observable or redux-most is used) exports Redux epics; exports the root epic by default
api/ — exports the api object by default
utils/ — export utility functions; has no default export
style/ — exports fonts, colors, dimensions objects; has no default export
fonts — exports fonts object by default
colors — exports colors object by default
dimensions — exports dimensions object by default
i18n/ — exports an object with translated messages by locale by default
main — exports a reference to the mounted app by default
The main field is a module ID that is the primary entry point to the program. That is, if a package is named foo, and a user installs it, and then does require("foo"), then the main module’s exports object will be returned.
We define it in order to facilitate publishing of the app in private NPM repo for embedding in another app.
This way we import modules of the app as if we had them published in a scoped NPM package. Later we could publish that package in a private NPM repo. This supports the guiding principle and facilitates the code reuse across apps being deleloped by an organisation.
There are no nested component modules.
The motivation for this is a mixture of keeping the project root clean and keeping static configuration all in one place. This approach becomes more common in the JS community with time.2
They should be configured in package.json
:
"devDependencies": {
"husky": "^1.2.0"
},
"husky": {
"hooks": {
"pre-commit": "eslint . && jest --passWithNoTests --lastCommit",
"pre-push": "yarn build"
}
}
.env
.env.local
.editorconfig
.nvmrc
.gitignore