PreactJS is a fast 3kB alternative to React with the same ES6 API

First, some background…

PreactJS is developed by Jason Miller — one of my programming heroes. The framework was developed with a goal of providing high performance, memory efficiency and close compatibility with React API with an aim to keep the footprint as small as possible i.e 3kb. Preact is increasingly getting adopted in the community with a bunch of high load websites already using it successfully in production.

Last week Jason Miller released Preact-CLI — A command line based tool similar to Create React App which makes it incredibly easy to get started. In this guide, we’ll be using that to ramp up ourselves to the framework.

Local Setup 🛠

Assuming you already have Node & NPM installed on your dev machine, We’ll install Preact’s command line utility

npm i -g preact-cli@latest

Once installation is successfully complete, we’ll create our first app

preact create my-first-preact-app

running above mentioned command should create a new directory with all the required files and configuration.

⭐️ The up side of using Preact’s command line utility is — it provides a preconfigured setup with all the industry standards tools out of the box. For instance, CSS modules, LESS / SASS, Hot Module Reload (HMR), Progressive Web App (PWA), Service Worker for offline caching, Preact Router and many more. Trust me; this will save you a ton of time. You can read complete list of features in the project’s README.

Now, let’s get the project running

cd my-first-preact-app
# start a live-reload/HMR dev server:
npm start
# Or 
preact watch

When preact-cli is done building files, we can point our favorite browser to http://0.0.0.0:8080. And, We should see a ready Preact app waiting to serve its creator! 😈

via GIPHY

(Slight) API Differences 👩‍🔬

There are very small (and negligible) API difference between React and Preact when writing UI. Having said that, If you like to stay attached to React’s API — Preact has a package called “preact-compat” which works as a compatibility layer and maps the API between both the frameworks (Amazing right? I know, I know).

Let’s see some Preact code to understand this.

import { h, render, Component } from 'preact'

h — this function that turns your JSX into Virtual DOM elements. You just need to import it similar to how we import React in each file.

render — function creates DOM tree from that Virtual DOM.

render((     
<div id="foo">         
   <span>Hello, world!</span>         
   <button onClick={ e => alert("hi!") }>Click Me</button>     </div> 
), document.body);

Component — Extendable class to build encapsulated, self-updating pieces of a User Interface with lifecycle methods support; much like React.Component.

class Clock extends Component {
    constructor() {
        super();
        // set initial time:
        this.state.time = Date.now();
    }
    componentDidMount() {
        // update time every second
        this.timer = setInterval(() => {
            this.setState({ time: Date.now() });
        }, 1000);
    }
    componentWillUnmount() {
        // stop when not renderable
        clearInterval(this.timer);
    }
    render(props, state) {
        let time = new Date(state.time).toLocaleTimeString();
        return <span>{ time }</span>;
    }
}
// render an instance of Clock into <body>:
render(<Clock />, document.body)

🚨 Notice how render receives two extra parameters props and state when used inside Component unlike React. Know more here.

That’s it! Seriously, that’s it. From top level these are difference in terms of API, there are some low level under the hood differences as well — You can find them in Preact guide.

Let’s Look At Code 👨🏼‍💻

Until this point we have a working Preact app where we can make changes, grasp on API differences & a sense of ease.

Open index.js in your favorite code editor — it should look something like

import './style';
import { h } from 'preact';
import { Router } from 'preact-router';
import Header from './components/header';
import Home from './routes/home';
import Profile from './routes/profile';
export default () => (
 <div id="app">
  <Header />
  <Router>
   <Home path="/" />
   <Profile path="/profile/" user="me" />
   <Profile path="/profile/:user" />
  </Router>
 </div>
);

If you’re coming from React world — this should feel like home. Nothing fancy going on here, importing components and setting up routes.

Now, let’s open Profile component inside ./routes/profile and change line 34

// From 
<h1>Profile: {user}</h1>
// To
<h1>Hola {user}!</h1>

Save. And, visit http://0.0.0.0:8080/profile/john to see your change. (No need to refresh, HMR takes care of that.)

Cool! Let’s now add a new Component in our app to get a better understanding about the framework.

Create a folder called github inside routes ; then create a file index.jsinside github folder. We are going to write a component which will fetch followers of a given user from Github’s API.

import { h, Component } from 'preact';
import style from './style'
export default class Github extends Component {
  state = {
      username: '',
      followers: null,
    };
  fetchUser = () => {
      fetch(`https://api.github.com/users/${this.state.username}`)
      .then(response => response.json())
      .then(user => this.setState({followers: user.followers }));
  }
  setUsername = e => {
      this.setState({ username: e.target.value });
  }
  render({}, { username, followers }) {
      return (
        <div class={style.container}>
          <h1>Enter a Github username</h1>
          <input 
            type="text" 
            value={username} 
            onChange={this.setUsername} 
           />
          <button 
            onClick={this.fetchUser}>
           Submit
          </button>
          {
          followers && 
          <h3>{username} has {followers} followers on Github.</h3>
           }
        </div>
      );
   }
}

Let’s add some basic style as well; Inside the same folder create styles.css

.container {
  padding: 56px 20px;
  min-height: 100%;
  width: 100%;
  background: #EEE;
}

Great! We’ve the component ready now. Let’s hook it up with routes and add a link in header to be able to navigate. Open index.js which we can find in the root of the project and import the Github component which we just created.

import './style';
import { h } from 'preact';
import { Router } from 'preact-router';
import Header from './components/header';
import Home from './routes/home';
import Profile from './routes/profile';
import Github from './routes/github'; // <--- Add this line
export default () => (
 <div id="app">
  <Header />
  <Router>
   <Home path="/" />
   <Profile path="/profile/" user="me" />
   <Profile path="/profile/:user" />
   <Github path="/github" /> // <-- Attach the component with path
  </Router>
 </div>
);

Then — open ./components/header/index.js and add new Link tag.

<Link activeClassName="active" href="/github">Github</Link>

Bingo! Now, let’s visit our newly created component http://0.0.0.0:8080/github. Your page should look something like this.

Go ahead; Type a username from Github (Hint: Mine is BilalBudhani). After entering a correct username — Our freshly minted component should show the number of followers of the specified username.

Boom! We’ve got ourselves a functional component written in Preact. Easy Peasy! right? But we’re not done yet — There’s a final step which we need to go through in order to form a full circle.

Ship it! 🚀

Time for showdown! Let’s tap into deployment part and see how we can bundle everything together. Before we do that, I would urge you to open Browser’s developer tools, navigate to network tab, find bundle.js and notice the size of the asset. Here’s what mine looks like.

bundle.js in development is around ~279Kb — Keep this in mind we’ll compare it with bundle.jsgenerated after build process.

Now goto the root of your project and runpreact build in command line. You will see an output similar to this

via GIPHY

above command will generate files which can be found inside build folder — these files are production ready and can be deployed directly on your favorite server.

We will now see how the app will function in a production like environment. Preact-CLI ships with a command called preact serve — this will essentially serve files from build folder. After running this command and let us point our browser to https://localhost:8080/. If all went fine — we should see our application functional — as it was in development mode. Go ahead and play around with the application, also don’t forget to try out our Github component. Everything should work like a charm!

But… Wait ✋! Remember the bundle.js size we noted earlier in the article? It’s now time look what’s inside 🕵️

Damn! Straight down to ~26kb — that’s a reduction of ~71%. The wait was worth it. Imagine, how many metrics it can impact in your production application — which might be used by hundreds if not thousands of users.

Edit 1: Jason Miller has reported that it should be even lesser, apparently there’s a bug in Chrome DevTools Http2 which is why the size is not accurate. I’ll update the copy as soon as I get any evidence.

Edit 2: Jason Miller got back to me with an update and provided with a screenshot which shows that bundle size goes to around 7.2 kb.

Final note 🤝

Firstly, Congratulations 🙌🏼! We just wrote our first Preact app.

Preact is an incredibly powerful tool with an amazing community (growing), plugin ecosystem, evolving production use cases and a bliss to work with. Also, Contributors are highly receptive (proof: I discovered a bug & Jason fixed it while I was writing this post. 😄). Checkout examples https://preactjs.com/about/demos-examples. I hope this post lured you enough to consider the Preact framework. You can find code which is mentioned in this post at github.

What’s next? You can follow the video course “Up and Running with Preact” at egghead.io