Frontend Best Practices
Overview
- CSS
- Pre/Postprocessors
- Organization
- Naming Conventions
- Javascript Conventions
- Style guides
- Linters
- React Tips & Tricks
- Automated Testing
- Integration tests vs unit tests
- Testing React Components
- Testing Redux
CSS
Pre/Post-processors
- LESS/SASS
- write styles in languages that compiles to CSS
- PostCSS
- The Future™
- parses CSS into node tree, applies JS transformations, then outputs transformed styles
- should we use one? yes
- does it matter which one we use? not really
Pre/Post-processors cont'd
- Useful features
- variables
- nested selectors (&)
- functions
- unit conversions
- vendor prefixing
- We already have cssnext/PostCSS installed, just need to add plugins and configure Webpack properly
Organization
- Currently: one CSS file per React component, all inlined separately onto every page (not ideal)
- encourages duplication of styles
- unclear order of style precedence
- easy to find styles for components
- Better Option: Put CSS in separate directory, structured by components/pages/shared, and compile all CSS files into one file before serving
- allows for style re-use when appropriate
- clear order of style precedence
- slightly harder to find styles for components
Naming Conventions
- motivation: make CSS codebase easy to comprehend and maintain
- describe how classes relate to each other
- establish hierarchy without high-specifity selectors
- BEM, SMACSS
- can get pretty complicated; start with only the most useful parts
- Javascript namespaces (e.g. js- prefix)
- decouple JS/DOM interaction from styling
BEM
/*
* Block, Element, Modifier
* everything is a class; nothing is nested
*/
/* a block is the top-level abstraction */
.modal {}
/* an element is a child of a block */
.modal__content {}
/* a modifier changes the behavior of a block/element */
.modal--open {}
/*
* benefits:
* - low-specifity, shallow selectors
* - modularity
* - easy to understand what classes are for
*/
References
Javascript Conventions
Style Guides
- the exact code conventions aren't that important
- what matters is that everyone follows the same conventions
- more detailed conventions === less things to think about for the
- my personal favorite is the AirBnB style guide (they also have a React style guide) (and an .eslintrc!)
Linters
- the preferred linter in 2016 seems to be ESLint
- we already have ESLint installed and configured in the frontend
- configurations are managed in .eslintrc
- Atom, Sublime Text, Vim, etc. all have ESLint plugins that will highlight linter errors as you write code
- ideally, PRs should not be merged if they contain code that fails the linter
- can use eslint --fix to automatically fix linter errors
React Tips & Tricks
Writing Good Components
- keep components small; better to have more small components than a few large, complicated ones
- make use of stateless components
- separate data fetching and interaction logic (state) from UI details
- higher-level components know how to get data and what to do with it
- lower-level components know what things should look like
Props
- propTypes are your friend
- specifies the interface of a component, i.e. what data do you need to use this component?
- can specify both type and requiredness of props, as well as nested prop structures
- defaultProps are also your friend
Component Lifecycle
- don't interact with the DOM in constructor(); use componentDidMount() instead
- don't request data (via AJAX or websockets) in constructor(); use componentWillMount() instead
- don't assign to this.state directly; use this.setState()
- use componentDidUpdate() to trigger side-effects of state changes
References
Automated Testing
Unit vs. Integration
- unit tests ensure that components and modules behave correctly and conform to expected interface
- integration tests check end-to-end behavior of the frontend, starting from user interaction and ending with updates to the DOM
- writing tests is kind of a pain
- integration tests provide more value for time spent
Writing Integration Tests
- Visit the url of the page in question
- Mock responses for any backend API requests
- Perform user interaction (e.g. click a button) through testing tools
- Wait for asynchronous behavior (e.g. backend requests) to finish executing
- Assert expectations about the state of the DOM (e.g. the button is now red)
Testing Tools
- For unit tests, React docs suggest using Jest
- Other options include Enzyme, Mocha, Jasmine
- For integration testing, it'd be nice to use a headless browser testing library like CasperJS or Nightwatch.js
- Running integration tests would involve spinning up an instance of the app, running headless browser tests, then spinning down the app instance
- ideally a script could automate this
Testing Tool Considerations
- ease of writing/debugging tests
- can tests run in a browser?
- how fast do tests run?
- does the testing library place nicely with React/Redux?
- how to mock backend requests/signals?
- can tests be run in random order?
- can tests be run by a continuous integration system?
Frontend Best Practices
By Oren Shoham
Frontend Best Practices
- 332