Skip to content

DIY repository setup

Martin Corevski edited this page Apr 19, 2018 · 13 revisions

Step by step guide

  • This wiki page is for those that want to create the repository from scratch in order to learn more about React setup.

Install node

Project folder and initialization

  • UNIX commands
mkdir "directory-name" 
cd "directory-name"
npm init

Installed packages

npm i -S react react-dom react-router-dom react-transition-group
  • i -S stands for install and save, installs packages locally in the project under dependencies
npm i -D babel-cli babel-preset-react babel-plugin-transform-class-properties babel-plugin-transform-object-rest-spread babel-plugin-syntax-dynamic-import babel-plugin-transform-regenerator
  • i -D stands for install-save-dev, installs packages locally in the project under dev-dependencies

  • Testing with Jest (identity-obj-proxy) and Enzyme

npm i -D jest jest-cli babel-jest identity-obj-proxy enzyme enzyme-adapter-react-16 react-test-renderer
npm i -D babel-eslint standard
npm i -D eslint
  • After creating your .eslintrc file you will need to install prettier-eslint in order to use Prettier and ESLint fix on your files.
npm i -D prettier-eslint
  • There are two main options to choose from when working with CSS and React:
  1. CSS modules with scoped classes css-modules and a Webpack demo. With this option all the classes are local scoped by default, if we want to make them globally scoped we need to add :global in front of the class name. In order to enable this option please see the webpack.config.js update for css-loader.
  2. Inline styles but since React's inline styling doesn't support some basic effects like :hover you need to install a library:
  • PropTypes is now a separate package, see link
npm i -S prop-types

PS: Local installation is recommended! If you want to install the packages globally you can use i -g

Package json file

  • Then update package.json or create/update .babelrc (THIS IS HIGHLY RECOMMENDED) file in the root directory, for the webpack setup and package.json updates please refer to this wiki
"babel": {
    "presets": ["react", "env", "stage-0"]
}
  • If you installed the linter packages you need to add standard parser and you can add it just after scripts or wherever you please inside package.json
"scripts" : {
  …
},
"standard": {
  "parser": "babel-eslint",
  "globals": ["shallow", "render", "mount", "describe", "it", "expect"]
}

Testing setup files

  • Jest config file in root directory
module.exports = {
  setupFiles: [
    '<rootDir>/config/tests-setup.js'
  ],
  transform: {
    '^.+\\.(jsx|js)?$': '<rootDir>/node_modules/babel-jest'
  },
  moduleNameMapper: {
    '^.+\\.(css|scss)$': 'identity-obj-proxy'
  }
}
  • Jest setup file for Enzyme init, this file is in a separate config folder
import Enzyme, { shallow, render, mount } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'

Enzyme.configure({ adapter: new Adapter() })

// Make Enzyme functions available in all test files without importing
global.shallow = shallow
global.render = render
global.mount = mount

Eslintrc file

  • Parser added, space before function, jsx single quotes because of the standard js rules, generator functions spacing.
{
  "env": {
    "browser": true,
    "es6": true
  },
  "extends": "eslint:recommended",
  "parser": "babel-eslint",
  "parserOptions": {
    "ecmaFeatures": {
      "experimentalObjectRestSpread": true,
      "jsx": true
    },
    "sourceType": "module"
  },
  "plugins": ["react"],
  "rules": {
    "indent": ["error", 2, { "SwitchCase": 1 }],
    "linebreak-style": ["error", "unix"],
    "quotes": ["error", "single"],
    "semi": ["error", "never"],
    "space-before-function-paren": ["error", "always"],
    "jsx-quotes": ["error", "prefer-single"],
    "generator-star-spacing": ["error", {"before": true, "after": true}]
  }
}

Webpack config file

  • In order to use ES6-7 JS syntax (features) the transform-class-properties plugin needs to be installed and added to the babel configuration. For the ability to use the spread operator for objects (example: let itSpread = {…someObject}) the transform-object-rest-spread plugin needs to be installed.
  • For generator functions (function * funcName ()) to work, transform-regenerator plugin needs to be installed and also babel-polyfill to be added npm i -S babel-polyfill. After adding babel polyfill you need to update the entry option in webpack.config.js entry: ['babel-polyfill', './index.js']
  • The import() method is made available by the syntax-dynamic-import plugin. Enables async load of components, bonus package react-loadable. Currently an error might appear Uncaught (in promise) TypeError: Cannot read property 'call' of undefined for css files inside async components when using chunks, see issue and issue in create-react-app also, since it's Webpack problem. Workaround until the issue is solved, inside the HOC yourComponent.js add at the beginning:
require('style-loader/lib/addStyles')
require('css-loader/lib/css-base')
  • This is how the babel loader part of the webpack.config.js file should look like:
{
 test: /\.js$/,
 include: /src/,
 exclude: /node_modules/,
 use: {
  loader: 'babel-loader',
  options: {
    presets: ['react', 'env', 'stage-0'],
    plugins: ['transform-class-properties', 'transform-object-rest-spread', 'syntax-dynamic-import', 'transform-regenerator']
  }
}
{
  test: /\.(css|scss|sass)$/,
  use: extractTextPlugin.extract({
    use: [
      {
         loader: 'css-loader',
         options: {
          modules: true,
          importLoaders: 2, // postcss and sass
          localIdentName: '[name]___[local]___[hash:base64:5]'
         }
      },
      'postcss-loader',
      'sass-loader'
    ],
    fallback: 'style-loader'
  })
}

Js files

  • Everything is documented inside the files.
  • Additional docs on:
  1. Babel installation, preset-env and preset-react
  2. React hash-router and router-quick-start

Folder structure

  • The folder structure can be updated and then all the paths in webpack.config.js need to be updated accordingly.
  • Here are some articles on React project folder structure:
  1. From reactjs-org
  2. Blog atomic-web-design
  3. How to structure react-project
  4. How to organize large-react-project
  5. But is there a 100% correct way to structure react-app?