This document explains how the application code flows and is structured, ie. "what code goes where" and teaches you application specific terminology.
The application is a Single Page Application bundled by webpack.
Webpack outputs an index.html with the script tags required to bootstrap the application already embedded. All required assets and scripts will be output to the dist folder. To serve the application simply serve the dist folder.
In development we use
webpack-dev-server
to automate this process, so this is something that you only need to care about if working with the build or deployment infrastructure.
In production we also render the application server side to improve SEO (see server.tsx).
Our application uses one common webpack.config.ts that is configured via --env.<optionName> <optionValue>
. See BuildOptions for options. Make sure you have webpack
and webpack-dev-server
installed globally for an optimal work flow.
npm install -g webpack webpack-dev-server
- Run
webpack-dev-server --env.<optionName> <optionValue>
to run the dev server with fine tuned options. - Run
webpack --env.<optionName> <optionValue>
to create a build with fine tuned options (this is what CI does)
A recommended preconfigured webpack-dev-server
can be used by simply running:
npm run dev-server
However, you are encouraged to fine tune the dev-server to your daily and situational needs (ie. when polishing UI you often don't need source maps, so disabling them will decrease built times and thus improve your work flow).
index.pug -> client.tsx -> App.tsx
The above sequence illustrates in which order key code files act to bootstrap the application. Down below follows an in depth explanation of each step.
The entry point of the browser.
This is a PUG template that generates index.html. We prefer a template over a plain index.html primarily for convenience together with
HtmlWebpackPlugin
.
The entry point of the application.
- Initializes application state
- Sets up global behaviors
- Sets up HMR in development.
- Renders App.tsx.
The root react component.
Sets up application behaviors and context providers.
The codebase is separated into specific folders, each with a singular purpose.
This documentation.
Development code. Tools that aid your dev workflow. Not part of the deployed application.
May not use
application code
(don't import from<rootDir>/src
).
Application code. Everything that makes up the deployed application.
May not use
development code
(don't import from<rootDir>/dev
).
This is a webpack module folder: This means <rootDir>/src
behaves like node_modules
.
This enables convenient import expressions like
require('assets/logo.svg')
.
Webpack entries.
Some entries act as plug ins for the application (ie. raven.ts, while others are completely independent variants of the application (ie. sitemap.ts.
You can find more documentation about each entry in their respective file.
All assets that the application uses.
Example asset usage:
const style = {
backgroundImage: `url(${require('assets/images/foo.jpg')})`
}
Note that assets load differently depending on their type. See webpack.config.tsx for a detailed list of asset loaders to get an insight in how each asset loads.
The fonts defined here are automatically loaded in main.tsx
.
Example font usage:
import {fonts} from 'assets/fonts';
const style = {
fontFamily: fonts.Default
};
Never specify fonts inline. Always reference the
fonts
variable.
Configuration files like routes and buildOptions.
This is the bulk code of the application, where everything comes together and creates the application.
If content exceeds a single file in complexity, create a folder and name the files
<contentName>/<contentName><something>.tsx
.
Example:
<rootDir>/src/content/browse/Browse.tsx
<rootDir>/src/content/browse/BrowseCard.tsx
<rootDir>/src/content/browse/BrowseFoo.tsx
State code. See state.md for more information.
We create forms using a factory pattern.
- Each form requires its own factory function named
create<Name>Form
, exported from a file of the same name. - The function is passed a reference to the I18nStore so that labels can be internationalized.
Example:
// src/forms/createTestForm.ts
export function createTestForm (i18n: I18nStore) {
return new Form({
email: {
label: i18n.format('common.field.label.email'),
rules: 'required'
}
});
}
Common reusable UI code, primarily react components.
If a component exceeds one file in complexity, create a folder and name the files <moduleName>/<moduleName><something>.tsx
.
Example:
<rootDir>/src/ui/chatbox/Chatbox.tsx
<rootDir>/src/ui/chatbox/ChatboxMessage.tsx
<rootDir>/src/ui/chatbox/ChatboxUsername.tsx
If a component is part of a series (ie. many buttons), create a folder and name the files <seriesName>/<variationName><seriesSubject>.tsx
.
Example:
<rootDir>/src/ui/buttons/CommonButton.tsx
<rootDir>/src/ui/buttons/WideButton.tsx
<rootDir>/src/ui/buttons/SmallButton.tsx
If a component is part of a category (ie. components with animations), create a folder and name the files <categoryName>/<moduleName>.tsx
.
The category convention should only be used when your ui code fits neither of the above conventions but still justifies its own structure.
Example:
<rootDir>/src/ui/animations/Morph.tsx
<rootDir>/src/ui/animations/Collapse.tsx
<rootDir>/src/ui/animations/Sequencer.tsx
If a component falls under none of the above conventions it should be generic enough to be regarded as a core component and should reside directly under <rootDir>/src/ui
A list of ui component demos.
Thanks to the modular nature of react components it is easy to demonstrate and unit test each component independently.
When to set up demos for UI components has no clear guideline, but it's recommended to develop new ui components using the demo interface. That way you will get demos and tests essentially for free.
Read more about the benefits of and how to create component demos in demos/index.tsx)
Standalone libraries being incubated in this project.
This folder exists purely for convenience so we don't have to maintain separate npm projects for each library.
Must be truly standalone (May only depend on npm modules and other code in
lib
)