Skip to content

Instantly share code, notes, and snippets.

@kasper573
Created April 25, 2018 19:13
Show Gist options
  • Save kasper573/4c0b93a5adacbfa2bd44c6a57691429f to your computer and use it in GitHub Desktop.
Save kasper573/4c0b93a5adacbfa2bd44c6a57691429f to your computer and use it in GitHub Desktop.

Frontend guidelines

This document explains what practices to follow while working in the frontend codebase.

Coding

Keep it simple

Solve the problems at hand. Avoid premature optimization and architecture. Refactoring is and should be simple.

Use Typescript

Javascript is only used where absolutely necessary, ie. code shared between app/jest, and jest configuration files (jest runs on vanilla js).

Avoid globals

Avoid using global/window unless absolutely necessary. Wrap integrations in a reusable modules (Example: buildOptions.ts)

Warning: We have little to no linting support to control this.

Excessive use of globals can make unit testing very difficult.

No side effects

Module imports that have side effects is strictly forbidden. This makes our code more flexible and the flow of code easier to follow.

Warning: We have little to no linting support to control this.

A common problem with module side effects is when a module has both side effects and exports. A programmer could then easily make a mistake by importing without anticipating the side effects.

No default exports

Default exports is strictly forbidden. This makes our code easier to refactor and the flow of code easier to follow.

Heads up: Code style rule enabled!

Default exports force you do give imports a local name, which may differ from place to place.

Code style

We use tslint to enforce a code style. The rules come from tslint-config-airbnb, with a few exceptions.

Heads up: Linting is done automatically pre-commit.

See tslint.json for full list of rules.

Continuous Integration

Unit tests and linting runs automatically on your machine as pre-commit hooks, but also per commit in our CI. Failing either tests or lints will report errors in the CI. Builds won't pass unless tests and linting pass. You are responsible.

i18n

We use react-intl and WebTranslateIt for internationalization.

i18n state originates from I18nStore.ts and is passed on on to react-intl. Thus can you also use I18nStore for formatting when that is more convenient than react-intl.

Reference file

<rootDir>/src/assets/i18n/reference.json

This is the reference i18n file. Make i18n changes here.

Your day-to-day involvement in i18n ends here. The rest of this section exist for transparency only.

Generated files

i18n files are automatically downloaded and generated when you run the development server (See sync.ts for more information). i18n files are generated to <rootDir>/src/assets/i18n/generated.

Do not modify these files. Any changes will be overwritten.

Good to know

  • Changes will be automatically uploaded to WebTranslateIt by our CI.
  • You can manually run sync.ts upload to upload changes (this is what the CI does), but this is not the intended workflow.

State management

See state.md.

Forms

We manage forms using a custom library Form.ts and FormTransport.ts. We leverage validatorjs for validation.

All forms code should be located in src/forms (see application structure guidelines)

Routing

We have a custom route configuration API.

Justification: We rely on static route configuration to align sitemap, unit test and menu generation for common routes. We tried to leverage router5 or react-router, but due to the lack of support for static route configuration or custom configuration options or route traversal in the end that created more complexity than creating a custom solution.

All routes are defined in routes.tsx.

For configuration options see RouteConfig.ts.

We use route-parser to parse route paths and allow its full syntax.

HTTP requests

  • Plain http requests are made with axios.

UI

Atomic design, React.JS and Material-UI

All UI is designed and programmed following the atomic design method using React and Material-UI.

App specific UI components

While Material-UI provides us with almost all atoms, molecules and organisms we need, there are still common components across many features that require specific components.

It is expected of you to collaborate with the team and together to the best of your ability identify common patterns and re-use or create re-usable components across features.

See application structure documentation for how to structure ui components

CSS reset

We use CssBaseline to reset css.

CSS in Typescript

All CSS is to be to written inline according to Material-UI standards

We have one exception: We have a custom withStyles.ts:

Why?

Material-UI 1 is still in beta and the typescript definitions for working with styles has a limiting workflow (Material-UI admits so themselves, albeit this is due to current typescript limitations). We redefine the types of withStyles.ts without changing the behavior to improve this workflow.

We have made the following type changes:

  • withStyles() (the function) can (and should) be used as decorator
  • WithStyles (the type) can be used without generics (ie. React.Component<WithStyles>).

Example:

// Import from 'ui' instead of 'material-ui'
import {WithStyles, withStyles} from 'ui/withStyles';

const styles = (theme: Theme) => ({
  thing: {
    padding: theme.spacing.unit,
    background: theme.palette.background,
    color: theme.palette.primary,
  },
});

@withStyles(styles)
export class MyComponent extends React.Component<WithStyles> { 
  render () {
    return <div className={this.props.classes.thing}/>;
  }
}

Our hope is that material-ui will improve the typescript support as the beta finalizes, in which case we'll be able to easily refactor from using our override to the one from material-ui.

In depth: "CSS-in-JS" has many benefits

Images

All images should be rendered using the SmartImage component. It automates loading state, transitions and gives us a centralized control over all images.

Testing

We use jest for testing.

  • Tests should follow the naming convention <filename>.test.ts.
  • Everything in /src/state and ``/src/lib` should be covered, anything else is optional.
  • We configure jest to collect coverage automatically.

Running npm run test (or just jest) will run all tests and collect and present coverage status.

Heads up: Testing is done automatically pre-commit and by the CI.

It is your responsibility to fix tests you break and to submit tests for code that needs coverage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment