Esteban Herrera Family man, #Java and #Javascript developer. #Swift, and #VR/#AR hobbyist. Like #books, #movies and still trying many things. eherrera.net

What’s new in Create React App 2

6 min read 1721

Create React App 2.1, released at the end of October 2018, added official support for TypeScript. This, along with all of the improvements and features brought by the second version of Create React App, removes much of the complexity of creating and configuring a React app.

In this article, I’m going to cover the following features of Create React App 2:

  • TypeScript support
  • Service workers (unregistered by default)
  • Sass, CSS Modules, and PostCSS
  • React fragments short syntax
  • Babel macros
  • Custom proxy implementation
  • Yarn Plug’n’Play mode

For a complete list of all of the features (and some breaking changes), you can check out the official post about this version and the changelog of the project.

TypeScript support

For new applications, you only have to execute create-react-app with --typescript option:

npx create-react-app sample-typescript-app --typescript

If npx is not executing the latest version (2.1.1 at the time of this writing), specify the version of create-react-app:

npx create-react-app@2.1.1 sample-typescript-app --typescript

This will install the packages related to TypeScript and create a default tsconfig.json file. Here’s an extract of the command’s output:

Installing react, react-dom, and react-scripts...
+ react-dom@16.6.3
+ react@16.6.3
+ react-scripts@2.1.1
+ @types/react-dom@16.0.9
+ @types/react@16.7.3
+ @types/jest@23.3.9
+ @types/node@10.12.6
+ typescript@3.1.6
...
We detected TypeScript in your project (srcApp.test.tsx) and created a tsconfig.json file for you.
Your tsconfig.json has been populated with default values.

The file src/App.tsx will be identical to its JavaScript counterpart, however, if, for example, you add a functional component to the file like this:


//...
const Content = (props) => {
  return <div><h1>{props.title}</h1>{props.text}</div>;
 }

class App extends Component {
  // ...
}

An error concerning the props parameter type will be thrown:

Because now, you have to declare a type definition using React.SFC:

interface ContentProps {
  title: string,
  text: string,
 }

const Content: React.SFC<ContentProps> = (props) => {
  return <div><h1>{props.title}</h1>{props.text}</div>;
}

And if your IDE supports it (Visual Studio Code in the image below), it will show you the type of the component’s attribute and it will also catch type errors:

On the other hand, to add TypeScript to an existing Create React App app, first, manually install the TypeScript-related packages:

npm install --save typescript @types/node @types/react @types/react-dom @types/jest

Next, change the extension of the files from *.js to *.tsx and restart the application (if it’s running).

Service workers are unregistered by default

The structure of the project created by Create React App remains the same.

The only changes are related to service workers.

First, the file src/registerServiceWorker.js was renamed to src/serviceWorker.js and now, inside of this file, a config object is passed to the function registerValidSW to enable the callbacks onUpdate and onSuccess:

The second change is in src/index.js, the service worker is unregistered by default:

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();

You can learn more about service workers and progressive web apps here.

Sass, CSS Modules, and PostCSS

Create React App 2 gives you more options to style your application without the need for complex configurations, ejecting the application or using react-app-rewired.

The first option is Sass. To use it, first install node-sass:

npm install --save node-sass

Now you can create a Sass file (src/Message.scss). For example:

$theme-color: green;
```
.my-message {
  color: $theme-color;
}

And use it in a component (src/Message.js) this way:

import React from 'react'
import './Message.scss'
const Message = props => {
  return <li className={my-message}> {children} <li>
}
export default Message;

On the other hand, with CSS Modules, you don’t have to install more dependencies, you just have to follow the [name].module.css file naming convention.

For example, if you have a Message.js component (shown in the previous example), you can define its styles in the file Message.module.css (remember that with CSS Modules you can compose classes):

.my-theme {
  color: green;
}
.my-message {
  composes: my-theme;
  font-size: 20px;
}

And in the component, use the styles like this:

import styles from './Message.module.css'
// ...
<li className={styles.my-message}> {children} </li>

This way, at runtime, a CSS class with a semi-random name will be generated to locally scope those styles to the component:

<li class="Message_my-message_tp3lv"></li>

Also, postcss-flexbugs-fixes and postcss-preset-env (supporting only stage3+ features) are included in Create React App 2, which means vendor prefixes are added automatically and new CSS features for older browsers are polyfilled. You can learn more about it here.

React fragments short syntax

It’s been a while since React 16.2 added support for fragments to return multiple children from a component’s render method:

render() {
  return (
    <React.Fragment>
      <h1>My Messages</h2>
      <p>Message 1</p>
      <p>Message 2</p>
    </React.Fragment>
  );
}

However, as the JSX Fragment Syntax (or short syntax):

render() {
  return (
    <>
      <h1>My Messages</h2>
      <p>Message 1</p>
      <p>Message 2</p>
    </>
  );
}

It’s only supported by Babel 7, you can use it now that Create React App 2 uses this version of Babel.

However, remember that <></> is just syntax sugar for <React.Fragment> but without the option to use keys or other attributes.

Babel macros

In the context of Create React App 2, Babel macros allow you to use a special type of Babel plugins without any configuration.

Let me explain.

Babel plugins allow you to manipulate and transform code at build time. For example, there’s a plugin that transforms arrow functions:

const a = (b) => b;

To regular JavaScript functions:

const a = function (b) {
  return b;
};

However, one problem with Babel plugins is that you have to configure each one you want to use. Usually, this is done in .babel.rc, but when using Create React App, you don’t have access to this file unless you eject the application.

Luckily, there is babel-plugin-macros, a plugin that defines a standard interface for…macros (i.e. plugins that perform build-time transformations).

This way, you only have to add this plugin to your project (which is what Create React App does) to use any number of macros you want.

And since macros are processed at build-time and not required at runtime, they should be specified as devDependencies.

You can search npm for the keyword babel-plugin-macros to find macros.

Take, for example, the Babel plugin/macro tagged-translations, which translates text at build-time.

Just add this library to a Create React App project with:

npm install --save-dev tagged-translations

Add the file translations/default.json at the root of the project with a translation like the following:

{
  "Hello world": "Hola mundo"
}

And use it as a macro in your components (not as a plugin, there’s a difference):

import t from 'tagged-translations/macro'

class App extends Component {
  render() {
    return (
      <div className="App">
          {t`Hello world`}
      </div>
    );
  }
}

As you can see in the following image, the translation happens when the bundle is created at build-time:

Custom proxy implementation

In the first version of Create React App, when making an API request you either had the option of hard-coding the complete URL of the request like this:

fetch('http://localhost:3001/messages')
  .then(res => {
    // ...
})

Or add a proxy field to the package.json file:

'proxy': 'http://localhost:3001/'

To just use the path of the resource in the fetch call:

fetch('/messages')
  .then(res => {
    // ...
})

With Create React App 2, in addition to the methods shown above, you can configure a custom proxy by installing http-proxy-middleware:

npm install --save http-proxy-middleware

And creating the file src/setupProxy.js to configure the proxy:

const proxy = require('http-proxy-middleware');
module.exports = function(app) {
  // ...
};

This file will be imported automatically when the application starts, and it gives you access to an Express instance to do something like this:

const proxy = require('http-proxy-middleware');
module.exports = function(app) {
  app.use(proxy('/api', { target: 'http://localhost:3001/' }));
  app.use(proxy('/public', { target: 'http://localhost:3002/' }));
};

Yarn Plug’n’Play mode

Yarn Plug’n’Play mode allows your application to work without a node_modules directory.

This way, the app dependencies are loaded from Yarn’s cache, rather than requiring copying them into the node_modules directory during the installation step. This has the added benefit of faster app creations.

To use this feature, you’ll need Yarn 1.12+, Node.js 8.9+, and be sure to create your React application with the option --use-pnp:

npx create-react-app light-app --use-pnp

If the command executed successfully, in the file package.json, you will find an additional configuration option:

{
  ...
  "installConfig": {
    "pnp": true
  },
  ...
}

Also, you’ll get a .pnp directory with links to directories of Yarn’s cache and the file .pnp.js, which validates dependencies and provides the ability to search for them from the global cache instead of the node_modules directory.

This is an experimental feature(at the time of this writing) so it might not work in all situations (for example, I didn’t work on my Windows 10 machine) and with tools that work with the node_modules directory directly.

Conclusion

Create React App 2 adds more options to ease the creation and configuration of React applications. Personally, the three new features I find most helpful are TypeScript, Saas and Babel macros.

However, I have to say that for an existing application, if you don’t need these new features or if you have a working configuration using react-app-rewired or craco, it’s probably not worth upgrading.

Even the Create React App team advise this:

Don’t feel pressured to upgrade anything. If you’re satisfied with the current feature set, its performance, and reliability, you can keep using the version you’re currently at! It might also be a good idea to let the 2.0 release stabilize a little bit before switching to it in production.

But for new applications, you have many new features at your disposal.

Happy hacking!

Plug: LogRocket, a DVR for web apps

https://logrocket.com/signup/

 

Esteban Herrera Family man, #Java and #Javascript developer. #Swift, and #VR/#AR hobbyist. Like #books, #movies and still trying many things. eherrera.net

Leave a Reply