Let's Dev

How to develop properly2021-07-17

Many conventional tutorials cover the basics of getting started, explain concepts and details. In my experience, however, the most valuable things to learn are, where to avoid inefficiencies (and which things to leave inefficient), what speeds you up, as well as, a macroscopic overview on how to combine all tools at hand for those benefits.

This post aims to provide an overview of the aforementioned topics for developing React-style web applications at a fast pace.

It is not only meant for beginners, but, could also serve ideas and new concepts for experienced developers.

The first imperative of developing fast, is looking which tasks you often repeat and how much potential you can gain by optimizing them.

The key is to weigh the cost/benefit ratio of optimization. The variables to consider are: how much time it takes (and what improvements you can expect to gain) vs how frequently the latency occurs.

A few examples:

  • Your development environment takes 1:30m to load, you do it once per day when starting your work-day (1:30m once a day - 2 hours of optimization)
  • Installing an inline-styling library (recommendations below) that saves you about  .4 seconds, 500 times a day while creating or changing the layout of a component because then you can avoid switching files (.4 seconds, 500 times a day - 2 hours of setup)
  • Installing a formatting tool, that saves you from adding tabs, alignment and other things by automatically being formatting (estimated 20 minutes, across the span of a day, every day - 2 hours of setup)
  • Enabling auto formatting instead of running the formatter manually 5 times a day (20 seconds, five times a day - 2 minutes of setup)

You could calculate all of those cost/benefit ratios by hand or use a convenient matrix provided by XKCD:

Using the matrix, we can conclude, that you should:

  • not optimize the loading time of your IDE since the setup time is not worth it
  • switch to an inline-styling library
  • switch to a formatting tool
  • enable auto formatting in your IDE

With this principle in mind, here are a few recommendations that you should consider using to increase your development speed

Libraries

UI

It's always quicker to outsource the UI-component-primitives of your app to a ready-made library. They are well-tested, well-designed and familiar to your users.

We at Wasc use both mui.com and React-Bootstrap across many projects, and are very satisfied with their functionality.

Layout

As outlined above, I think speed is the most important virtue, when developing I am using TailwindCSS. It provides all necessary utility classes, optimizes what to include in your bundle and has a fast documentation (on the website hit CMD+K to search quickly)

I don't experience much duplication across my components, since I don't use Tailwind to style my UI-primitives, which are outsourced to the above-mentioned, but mostly for layouting and basic styling, which are individual to each component.

Architecture

If you need a routing library, I will recommend the React-Router v6-beta, unlike previous releases, it is Hook-based and allows for easy nesting of routing.

For example, a global router handling pages like Home, Login, Signup, Dashboard, and a subrouter configured in the Dashboard-component that handles all the /dashboard* routes. It allows for good separation of concerns and keeps the code clean.

Bonus

I have installed a small hook in the root component of each app, intercepting all clicks on anchors (links) and dispatching a route event to react-router. This has the only benefit of allowing me to use native <a /> tags which avoids me from importing <Link />, which saves time.

It uses pwa-helpers for the event handler.

import { installRouter } from "pwa-helpers";

// Render method
const navigate = useNavigate();
const element = useRoutes(routes);

useEffect(() => {
  installRouter((location) => {
    const href = location.pathname + location.search + location.hash;

    navigate(location, {
      replace: true,
    });
  });
}, [navigate]);

Tooling

To quickly find out, what effect a new library will have on your bundle size, check it with bundlephobia.com

Gitlab.com has a 400-minute CI/CD free tier for private repositories.

To cut down on latency between finding out about bugs and fixing them, it's important to have a robust toolchain in place.

I use ESLint, Prettier and Jest for linting, formatting and testing. I have bundled them in an open-source tool that you're free to use: wasc-tools

You should install these tools at three locations to cut down latencies as much as possible:

  • In your CI, create stages which run linting and testing
  • As pre-commit hooks, so you find your issues not just after the pipeline ran
  • In your IDE, format on saving, flag linting and test issue while developing (combine Husky [hooks], with lint-staged [only test what has changed])

You should keep them all, as they safeguard against malice (and more commonly, against stupid mistakes).

Moving fast will mean making mistakes. It's important to isolate changes into small bundles and separate them into distinct categories; this helps keeping a clean record and improves debugging with git bisect.

I recommend using the Conventional Commit Convention to enforce some rigour in the committing process. (A commit-message linting tool, like CommitLint is advised. Install it as a pre-commit hook)

Here is an excerpt of the commit history of one of my projects:


    * 34016e1 - (HEAD -> master, origin/master, origin/HEAD) chore: change ownership reference in help (4 weeks ago) <Nicolai Schmid>
    * 6eab9e1 - (tag: v5.14.0) feat(eslint): add eslint-plugin-fail-comment (2 months ago) <Nicolai Schmid>
    * b22623d - (tag: v5.13.0) feat(preact): remove compression, preact-cli has an option (3 months ago) <Nicolai Schmid>
    * 690d00a - fix(preact:markdown): remove old/unsupported configuration options (3 months ago) <Nicolai Schmid>
    * ca12412 - chore(husky): upgrade to v6 (3 months ago) <Nicolai Schmid>
    *   941375c - (tag: v5.12.6) Merge pull request #104 from wasc-io/renovate/execa-5.x (3 months ago) <Nicolai Schmid>
    |\\
    | * 12d6ae8 - fix(deps): update dependency execa to v5 (3 months ago) <Renovate Bot>
    |/
    *   35a4d98 - (tag: v5.12.5) Merge pull request #96 from wasc-io/renovate/eslint-config-prettier-6.x (3 months ago) <Nicolai Schmid>
    |\\
    | * d6e73ed - fix(deps): update dependency eslint-config-prettier to v6.15.0 (3 months ago) <Renovate Bot>
    * |   cd442a3 - Merge pull request #93 from wasc-io/renovate/eslint-plugin-jsx-a11y-6.x (3 months ago) <Nicolai Schmid>
    |\\ \\
    | * | a7aa964 - fix(deps): update dependency eslint-plugin-jsx-a11y to v6.4.1 (3 months ago) <Renovate Bot>
    | |/
    * |   cd5e4a3 - Merge pull request #97 from wasc-io/renovate/execa-4.x (3 months ago) <Nicolai Schmid>
    |\\ \\
    | * | b42f837 - fix(deps): update dependency execa to v4.1.0 (3 months ago) <Renovate Bot>
    | |/
    * |   080c7b4 - Merge pull request #92 from wasc-io/renovate/jest-monorepo (3 months ago) <Nicolai Schmid>
    |\\ \\
    | |/
    |/|
    | * 2eec5cc - fix(deps): update jest monorepo to v26.6.3 (3 months ago) <Renovate Bot>
    |/
    *   03e5467 - (tag: v5.12.4) Merge pull request #112 from wasc-io/renovate/node-loader-1.x (3 months ago) <Nicolai Schmid>

Cut versions frequently. Use standard-version to automatically choose the correct semantic version number and generate CHANGELOGs from the commit messages (can be used for reference when writing "What Changed" newsletters)

Use Renovate to keep your dependencies up-to-date automatically. Don't be afraid to auto-merge if you have plenty of test in your pipeline.

Should you use VSCode for development, I can recommend the following extensions which might speed you up:

  • Auto Close Tag (automatically adds the HTML/JSX close tag → less typing → more speed)
  • Auto Rename Tag (renames the corresponding closing HTML/JSX tag → less typing and scrolling → more speed)
  • Code Spell Check
  • ESLint (configure .eslintrc.js file from wasc-tools)
  • Formatting Toggle (sometimes Prettier screws up with unknown file format)
  • GitLens
  • Image preview (show what images you important inline, avoids switching files)
  • Import cost (not very precise, however it gives you a ballpark, similar to Bundlephobia, however, this time it's inline)
  • npm Intellisense (suggests completions for installed npm modules → less typing → more speed)
  • Path Intellisense (suggests completions for local paths → less typing → more speed)
  • Prettier (configure .prettierrc.js file from wasc-tools)
  • Subword navigation (jump to camel-cased segments of words → improves speed since it's one shortcut, instead of multiple arrow keys, or god-forbid, your mouse)
  • SVG viewer
  • tabOut
  • Tailwind CSS Intellisense (should you choose to use Tailwind)
  • Visual Studio Intellicode (advanced code auto-completion → less typing → more speed)
  • (you could also try Kite, it didn't improve my speed, so I removed it, although, since it's ML based, it could have improved a lot since I last used it)

Two settings I recommend changing to speed up development with VSCode:

  • Turn on "Format on Save", this will make VSCode run Prettier on saving to always have a properly formatted file on disk
  • Turn on "Save on Focus Lost", this trims down iterations while developing web applications, just switch focus to the browser window, VSCode loses focus, saves the file, Webpack (create-react-app or preact-cli) get triggered to hot-refresh, the browser reloads (instead of saving manually)

And I recommend you learn the CMD+P shortcut for changing the open file in VSCode, (CMD+P, enter parts of the filename/path, it uses fuzzy find, so it skips over typos → speed, select one and enter).

It improves changing file latency by at least two orders of magnitude. Considering, I switch files at least a few hundred times per day, it cuts down development time significantly.

Lastly, I will recommend you to use Preact, a drop-in replacement for React; it not only has a much smaller bundle size than React (good for your users) but also allows you to not have to import any Preact/React-dependencies (no import React from 'react' any more, one less line to type → more speed)

The preact-cli toolchain, in my opinion, also has some benefits over create-react-app, the most important is, you can configure it to include arbitrary Webpack rules and plugins without the notion of "ejecting," this means you don't have to keep migrating your Webpack configuration to later versions; a simple NPM update suffices.