Search
⌘K
    to navigateEnterto select Escto close

    Linting and Formatting Code

    Wheel from BigBinary

    BigBinary's wheel project is the source of truth for all these configs and toolchains.

    Every internal product or Rails project in BigBinary uses wheel as the base for bootstrapping that new project.

    Thus if you are asked to create a new Rails project while working in BigBinary, then you should strictly add the below mentioned hooks and relevant configs into your project.

    Rubocop

    Rubocop is a linter as well as a code formatter specifically for Ruby.

    BigBinary has strong and opinionated coding style guidelines that are enforced using this tool.

    Add the gems

    First, let's add the relevant gems to our Gemfile:

    1# previous gems as it was
    2
    3group :development, :test do
    4  # previous gems under this group as it was
    5
    6  # For code formatting and linting
    7  gem "rubocop"
    8  gem "rubocop-rails"
    9end
    10# other gems if any

    Now install the gems by running the following from the terminal:

    1bundle install

    Add the config

    Add BigBinary's Rubocop config to the root of your project by running the following command from the terminal:

    1curl -o ".rubocop.yml" "https://raw.githubusercontent.com/bigbinary/wheel/master/.rubocop.yml"

    Running Rubocop on all Ruby files

    The following needn't be run in your project at the moment, given that we haven't added any non-linted files to our git index.

    But there are valid cases, like say adding a new Rubocop rule, and wanting to apply that and format all the Ruby files within the project.

    In such cases run the following from the root of the project in your terminal:

    1bundle exec rubocop

    The above command would output the offenses it finds. Some offenses are auto-correctable by Rubocop. But some are not.

    We auto-correct the correctable ones by running:

    1bundle exec rubocop -a

    That should fix all the safely correctable errors. The non-corrected ones should be manually corrected.

    Moving forward, we won't be running these commands. Rather we will use git hooks to run these commands for us on modified files.

    Setup pre-commit Git hook

    A pre-commit Git hook can re-format the files that are marked as "staged" by git add command before you commit.

    In BigBinary, no PR should be made without running the pre-commit hook. Or more subtly saying, please don't bypass the Git hooks.

    Let's set up husky to run the hooks and install lint-staged to lint the files.

    Run the following commands from the terminal:

    1npx husky-init && yarn # press y to proceed
    2yarn add -D lint-staged

    Now add the following highlighted lines to the start of your package.json file.

    Note that you need to retain all other keys which were already part of the file as it was.

    1{
    2  "lint-staged": {
    3    "app/javascript/src/**/*.{js,jsx,json}": [
    4      "prettier --write",
    5      "eslint --fix",
    6      "git add"
    7    ],
    8    "{package.json,.eslintrc.js,.prettierrc.js}": [
    9      "prettier --write",
    10      "eslint --fix",
    11      "git add"
    12    ],
    13    "./**/*.rb": [
    14      "bundle exec rubocop -a"
    15    ],
    16    "{Gemfile,Rakefile,config.ru}": [
    17      "bundle exec rubocop -a"
    18    ]
    19  },
    20  ...
    21  <rest of the keys as it was>
    22}

    Husky, by default, will read the Git hooks from the .husky directory within the root of the project.

    When we installed husky, it should've automatically created the .husky folder along with some default configs.

    Now copy-paste the whole code block into your terminal and execute it, in order to setup the hooks:

    1cat << 'EOF' > .husky/pre-commit
    2#!/bin/sh
    3. "$(dirname "$0")/_/husky.sh"
    4. "$(dirname "$0")/helpers/lint_staged.sh"
    5
    6lint_staged_files
    7EOF
    8chmod a+x .husky/pre-commit
    9curl --create-dirs -o ".husky/helpers/lint_staged.sh" "https://raw.githubusercontent.com/bigbinary/wheel/master/.husky/helpers/lint_staged.sh"

    In the following sections, we will set up the tools which our hooks depend upon.

    ESLint

    ESLint is a static code analysis tool to quickly find problems with the JavaScript codebase.

    Most of the problems ESLint finds can be automatically fixed.

    Add the modules

    Run the following command from the terminal:

    1yarn add -D eslint \
    2babel-eslint \
    3eslint-plugin-react-hooks \
    4eslint-plugin-import \
    5eslint-config-prettier \
    6eslint-plugin-prettier \
    7eslint-plugin-json \
    8eslint-plugin-react \
    9eslint-plugin-promise \
    10eslint-plugin-jam3
    

    The above command installs prettier along with some other goodies.

    Prettier is a code formatter that can be integrated with linters. To integrate prettier with ESLint, we added eslint-config-prettier as well as eslint-plugin-prettier modules.

    Add the config

    Now let's add the ESLint config from wheel into our project.

    Run the following command from the terminal:

    1curl -o ".eslintrc.js" "https://raw.githubusercontent.com/bigbinary/wheel/master/.eslintrc.js"

    Prettier

    An unformatted JavaScript file is really hard to read. Prettier helps us in keeping the code sane and consistent.

    Add the module

    Run the following from the terminal:

    1yarn add -D prettier

    Add the config

    Run the following from the terminal to fetch the Prettier config from wheel:

    1curl -o ".prettierrc.js" "https://raw.githubusercontent.com/bigbinary/wheel/master/.prettierrc.js"

    Formatting all JavaScript files

    The following needn't be run in your project at the moment, given that we haven't added any non-linted files nor do have required folders in our git index.

    Similar to what we had mentioned in the Rubocop section, there are valid cases, like say adding a new ESLint/Prettier rule, and wanting to apply that and format all the JavaScript files within the project.

    In the Rails codebase we can run the following command from terminal, in order to format all such files:

    1npx prettier --write "./app/javascript/src/**/*.{js,jsx,json}"
    2npx eslint --fix "./app/javascript/src/**/*.{js,jsx,json}"

    If you run the above commands in the current state of your application, that is if you had typed only till current chapter, then it will lead to an error since the src folder hasn't been created yet. That folder will only be created in the chapter that sets up the React environment.

    You can safely ignore the warnings about react package not yet installed. We will be installing react and other related packages in the upcoming chapters.

    Configuring VSCode settings

    Now that we have added the configs for the relevant tools, let's add the necessary VSCode settings to ensure these tools are run on the fly while we code.

    At BigBinary we use the following plugins along with some custom settings in VSCode, to ensure coding style is maintained from grassroots level.

    Now, copy-paste the following commands into your terminal and run them:

    1curl --create-dirs -o ".vscode/extensions.json" "https://raw.githubusercontent.com/bigbinary/wheel/master/.vscode/extensions.json"
    2curl -o ".vscode/settings.json" "https://raw.githubusercontent.com/bigbinary/wheel/master/.vscode/settings.json"

    Running above commands should've created the relevant configs.

    Now, open the granite project in VSCode, by running the following from the root of the project:

    1code .

    If you had the project already opened in VSCode, then restart VSCode for the settings to take effect.

    At the bottom right side, you should will get a popup for installing the recommended extensions. Go ahead and click the install button:

    VSCode extensions recommendation.

    After installation, all the extensions should be working out of the box with the required settings.

    You can visit a Ruby file and see Rubocop provide you live linting. Likewise, you can visit a JavaScript file and format it via VSCode to see Prettier in action.

    Adding .editorconfig

    We can specify consistent IDE configurations for our project in the .editorconfig file located in the root of the project. This ensures the code style remains uniform across the project when multiple users are working on the same project.

    We can use the same config from wheel.

    Run the following command from the terminal:

    1curl -o ".editorconfig" "https://raw.githubusercontent.com/bigbinary/wheel/master/.editorconfig"

    VSCode will automatically detect this configuration, and will strictly adhere to the rules mentioned in it.

    Running Git hooks

    You don't need to manually run the Git hooks. These hooks are run automatically based on the kind of hook we have added.

    Currently, we have added a pre-commit hook. Thus before each time, you try to commit new code to the project, the hook will verify the coding style follows our guidelines.

    The Git hook will only be run on files that are currently modified. Meaning, the hook will ignore all files which were already committed using Git.

    That is why we mentioned a previous section on how to run the formatting on all files, which is inclusive of the committed files, if need be.

    If the Git hook fails, then it means that you need to fix a particular section within your codebase manually.

    Once again, never bypass the Git hooks. Always run the Git hooks, resolve the errors and then only push to GitHub.

    Git hooks in action

    Let's commit our code to see the Git hooks in action.

    Run the following from the terminal:

    1git add -A
    2git commit -m "Added git hooks, eslint, prettier and rubocop"

    Ideally, the above command should run without any issues.

    But let's take the case where we missed out on adding the string literal comment as the first comment in the file in our Gemfile.

    In such a case we might get the following output in the terminal: Rubocop string literal error.

    Rubocop shows an offense when it can't automatically fix the offense.

    The first thing we have to note is which task failed in the hook.

    Currently, it's the task for {Gemfile,Rakefile,config.ru} that has failed.

    The next thing to look into is the offenses and check which offense has the keyword [Correctable].

    In the above case, the offense is in the Gemfile since we are missing the string literal comment in it.

    For above mentioned scenario we can run the following command from the terminal:

    1bundle exec rubocop -A Gemfile

    Note that we have run the unsafe auto-correction mode from Rubocop in the last command.

    It's not recommended to be used often. That's the exact reason why we haven't added this command as part of our hook. The offenses shown by Rubocop are best fixed manually.

    If you had encountered the above error, then now you should be able to commit, by running the following commands from the terminal:

    1git add -A
    2git commit -m "Added git hooks, eslint, prettier and rubocop"

    References

    Previous
    Next