What did I do in 2018?

Photo by chuttersnap

2018 is ending, I will do a quick review of the personal projects I worked on the last 12 months, in order to keep track of what I accomplished over the last year.

Projects

I worked on 3 main personal projects over this past year:

topheman/npm-registry-browser 🔗

There are lots of great resources on React (tutorials, blog posts, books, videos …), but most of them focus on a specific problem. Today, making an app is a lot about picking and putting building blocks together:

  • choosing and setting up external libraries (UI kits, state management, http clients, routers …)
  • enabling code quality good practices (linting, testing, git hooks, cis …)
  • automation / dev pipeline

The hard part is to put this all together. This is the goal of this project: provide a well-documented example of a front-end app with real-world features and constraints.

Related:

topheman/docker-experiments 🔗

The goal of this project is to let you discover docker/docker-compose with a simple use case in development, production (local kubernetes) and CI. I provide a highly documented README which I use myself as a reference.

The project itself ships:

  • a frontend made with create-react-app, running in a nodejs container for development
  • a very simple api made in go (the challenge was also not to have everything in JavaScript)
  • nginx setup as reverse proxy on the production image

Related:

topheman/react-fiber-experiments 🔗

At the time I’m writting this post, data fetching with Suspense is still not yet enabled in React (not even in alpha versions), Suspense is only available for code splitting (v16.8.0-alpha.1).

In march 2018, Dan Abramov presented for the very first time React Suspense. A month later, Andrew Clark made an other talk about Suspense, more oriented on placeholders.

In august 2018, Ryan Florence made a talk about route recalculating, where he presents how @reach/router can work with React Suspense.

In september 2018 (at this time, react was in v16.5.0), I decided to make a project based on the data fetching and code splitting features of Suspense to better understand the benefits of those features and expose them to other developers (since this will be a game changing for data fetching in React).

Related:

Talks

This year I made a few talks at local meetups:

Utils / Boilerplates

  • topheman/delay-proxy: A little development tool that lets you emulate slow network connections
  • topheman/my-react-app-starter: create-react-app is a great toolkit which removes a lot of boilerplate to manage. I added a few features that I was missing like: eslint/prettier/precommit hook, generate changelog, deploy task …
  • topheman/fullstack-setup: research repo about formatting automation

Overall

This year, I worked a lot on React (I like this library and I’ve been working with it for almost 4 years). I also got deeper into docker with topheman/docker-experiments (every year, I like to pick a technology outside of JavaScript and do a little more than just a Hello World 😉 ).

The main guideline I followed this year was to ship projects that take in account the constraints you would have developing in team (even if I was working alone):

  • formatting and linting enforced at precommit-hook: thanks to prettier and eslint, no more discussion about code style on PRs!
  • dev experience: accessible npm tasks install / start / build / test / deploy … more specific ones should be documented
  • unit tests
  • end to end tests: thanks to Cypress (read Cypress.io advanced setup)
  • CI: automatic deployment

This is the first time I’ve done a screencast. It was an interesting experience (doing it in english, not in french 😉 ).

Next

In 2019, I will try TypeScript – I already used it a little 3 years ago in topheman/angular2-sandbox to test angular@2 and ngrx, but now is definitely the time to check it out.

Cypress.io advanced setup

In my last projects, I’ve been using Cypress.io as an end to end testing solution (npm-registry-browser / react-fiber-experiments). It makes it easy to write, debug and record e2e tests.

If you want your team to write e2e tests, the dev experience must be straightforward:

  • You shouldn’t have to run more than one command line to launch your tests
  • You should have feedback
  • You should be able to debug your tests
  • You should be able to run your unit and e2e tests in parallel
  • You should be able to run your tests on a CI at some point

I will explain my setup. I won’t talk about how to write tests but how to run them against your code base / server (so there will be NO framework-specific code).

1) Cypress init

Install cypress then init your project. It will create a cypress directory containing default tests.

npm install --save-dev cypress
npx cypress open

Update the cypress.json file that was created and set the following:

{
  "baseUrl": "http://localhost:5000",
  "video": false
}
  • baseUrl: the url of the local server from where we will serve the production build
  • video: by default to true. You might not want to record video when running tests in local – otherwise, leave it to true (I will show on a future post how to setup Cypress on CI to record videos)

You will be ready to write your own tests and run them, but you will quickly feel that it misses some kind of automation …

2) Basics

You will need to install the following packages:

  • serve: use any other package that serves static sites
  • npm-run-all: a cli tool to run multiple npm-scripts in parallel or sequential
  • start-server-and-test: make sure to start testing only when server is ready
  • cross-env: set and use env vars across platforms

Install them:

npm install --save-dev serve npm-run-all start-server-and-test cross-env

3) Run your tests against a development server

You should be able to run your e2e tests while you are coding your project (a little like when you run your unit tests in watch mode). This will let you debug your tests.

We all have some kind of development toolchain, whether you rely on webpack, browserify or any other, I assume that:

  • npm start: starts your development server
  • your development server runs on http://localhost:3000

Here are the npm scripts we will use (change the start task to your own usage – I’m using a create-react-app based project as example):

scripts: {
  "start": "react-scripts start",
  "test:cypress:dev": "npm-run-all --parallel --race start 'cy:open -- --config baseUrl=http://localhost:3000'",
  "cy:open": "cypress open"
}

Running npm run test:cypress:dev will:

  • start your dev server (using npm start)
  • start the Cypress GUI (ready to test on your dev server at http://localhost:3000)

That way, you could choose to develop inside chrome or run your tests in the cypress GUI.

4) Run your tests against a production build

End to end tests should run in an environment that is the closest to production, to avoid the “it works on my machine” problem. So we will run them against a production build.

Here are the npm scripts we will use:

scripts: {
  "build": "react-scripts build",
  "test:cypress": "npm run build && npm run cy:start-server-and-test",
  "cy:start-server-and-test": "npx start-server-and-test serve :5000 cy:run",
  "serve": "npx serve --no-clipboard --single --listen 5000 build"
}

I will assume that you have some npm run build task that generates a production version of your project in the build folder (we all have that kind of task).

Running npm run test:cypress will:

  1. generate a production build (using npm run build)
  2. serve the build folder on http://localhost:5000
  3. finally, run the tests in headless mode

5) Run both your unit and e2e tests

Whatever the test framework you use, I will assume that you have setup your npm tasks to run your unit tests as:

  • test:unit: runs your unit tests in single run mode
  • test:unit:watch: runs your unit tests in watch mode

We will reuse a few tasks from the previous example, adding test, test:unit, test:unit:watch:

scripts: {
  "build": "react-scripts build",
  "test": "npm-run-all --parallel --silent test:unit test:cypress",
  "test:unit": "cross-env CI=true npm run test:unit:watch",
  "test:unit:watch": "react-scripts test --env=jsdom",
  "test:cypress": "npm run build && npm run cy:start-server-and-test",
  "cy:start-server-and-test": "npx start-server-and-test serve :5000 cy:run",
  "serve": "npx serve --no-clipboard --single --listen 5000 build"
}

Running npm test will launch in parallel test:unit and test:cypress, which means that while:

  • a production build is created and then served on http://localhost:5000 to be e2e tested
  • the unit tests will run

That way, you only have to run one command: npm test to run all your tests (unit AND e2e) – without even bothering about generating a production build / launching a test server – everything is included / run as soon as possible.

6) Conclusion

My testing workflow is based on the one I exposed in the following projects:

Check them out to learn more about react and testing.

If you followed all the steps, you should have the following tasks setup:

  • test: run both unit and e2e tests in parallel
  • test:unit: run your unit tests (if you had some)
  • test:cypress: run your e2e tests in headless mode
  • test:cypress:dev: launch your dev server + run your e2e tests in the Cypress GUI

 

Découvrir React Suspense – vidéo talk (fr)

Dans un post précédent, j’ai présenté React Suspense, une fonctionnalité en cours de développement chez React, qui changera la façon de faire du chargement asynchrone. Dans le but de vous faire découvrir cette fonctionnalité (et d’autres qui suivront), j’ai lancé topheman/react-fiber-experiments.

Il y a quelques jours, j’ai fait un talk à ce propos au meetup ReactJS chez Datadog. Le meetup était enregistré, je vous invite à le visionner :

Regarder le screencast [en] / Regarder le talk [fr]

Ressources :

Credits photo: @ReactjsParis

Discover React Suspense

Watch screencast [en] / Watch talk [fr]

With React v16, the Facebook team shipped a new version of the core called “Fiber”. Thanks to this full rewrite, we’ve already seen new features like Fragments, Portals and ErrorBoundaries. Some other features are still under development:

  • Suspense
  • Time Slicing

For the last few months, engineers from facebook have made a few demonstrations of the possibilities of these features. Few examples are available (at the time of the writing, those are still unstable/undocumented APIs).

After the talk of Ryan Florence at React Rally presenting Suspense and how @reach/router is ready for it, I decided to make a little project:

  • to dive into those new concepts
  • to share code examples
  • to expose a simple tool that could help explain the benefits of using suspense

TRY OUT

What problems does Suspense solves ?

  • It lets you start rendering before all data is ready (rendering can be paused when data starts loading and resumed when it finishes)
  • It lets you avoid a cascade of spinners, that may cause flashes due to unintentional reflows and repaints
  • Code splitting becomes a built-in feature, easy to use (you also can pause rendering while loading script)

What this means:

  • Move the fetching of data closer to where it will be rendered – data encapsulation
  • Get rid of loading states – cleaner state in components (maybe even stateless in some use cases – no more need of componentDidMount lifecycle hook to go fetch data)
  • Finer grain control over spinners (thanks to <Placeholder>)

How to test it today

Suspense is still under active development, be aware that the APIs might change and be unstable, though it’s advanced enough to hack a project with. You’ll need to make your own build of React.

Tophe

This was a short introduction to React Suspense, go further by watching the video and play online with topheman/react-fiber-experiments.

Resources:

CircleCI – How to use the latest version of docker-compose / docker-engine ?

On my latest project topheman/docker-experiments, I’ve been using CircleCI to build docker images of my app on the CI and run unit tests through them, using the same docker-compose file configuration as I’m using on my local machine. Though, at my first build I encountered the following error:

ERROR: Version in “./docker-compose.yml” is unsupported. You might be seeing this error because you’re using the wrong Compose file version. Either specify a supported version (“2.0”, “2.1”, “3.0”, “3.1”, “3.2”) and place your service definitions under the `services` key, or omit the `version` key and place your service definitions at the root of the file to use version 1.

For more on the Compose file format versions, see https://docs.docker.com/compose/compose-file/

This means that the docker-compose file format I’m using (v3.4) isn’t supported by the docker-engine version used on the default setup of CircleCIsee compose and docker matrix compatibility.

Fortunately, on CircleCI, in machine executor mode, you can change/customize the image your VM will be running (by default: circleci/classic:latest) – see the list of images available. All I had to do was switching the image name and I was able to use an other version of docker-compose / docker-engine on the CI:

version: 2
jobs:
  build:
-    machine: true
+    machine:
+      image: circleci/classic:201808-01

You can see the modifications in that commit.

More posts to come about docker, meanwhile, you can checkout topheman/docker-experiments.

Resources: