Hello World with Preact, JSX & Typescript

Update: Jan 10th 2017: If you’re using Typescript 2.1 or above, you can can swap any mention of typescript@next with typescript — the option required (`jsxFactory’) is now in the stable release :)

In this tutorial we’re going to setup the bare minimum needed to use Preact with Typescript. No Hot-Module-Reloading or complicated Webpack configurations (we will use Webpack, but in its simplest form), just the actual bits you need to learn how to use both of these amazing tools in your projects today.

Now, Typescript already works extremely well with React (a >40kb Preact alternative) — static typing across both props & state objects makes authoring JSX an absolute pleasure. Having the compiler or your editor warn you about typos or mis-matched types as you work is something you just get used to and will be reluctant to give up when switching between libraries.

This is the problem I faced recently — I want my 3KB view renderer (Preact), but I also want my static types and awesome developer experience.

The goal — let Typescript guide us through development

The good news is that it can be done, it just requires a bleeding edge Typescript version and the correct configuration. Here, let me walk you through it.

Step 1 — Install dependencies

yarn add typescript@next preact webpack ts-loader
# or, for npm users
npm i typescript@next preact webpack ts-loader

Note: We need to use typescript@next as this allows us to use the upcoming compiler option jsxFactory which we’ll see shortly.

Step 2 — Create a tsconfig.json file

This will configure the Typescript compiler with the options needed for Preact.

{
"compilerOptions": {
"sourceMap": true,
"module": "commonjs",
"jsx": "react",
"jsxFactory": "h",
"target": "es5"
},
"include": [
"src/*.ts",
"src/*.tsx"
]
}

Notes:

  • We set "jsx": "react" to instruct Typescript to transpile JSX like <Hello /> into regular JS… But, this alone would result in something like React.createElement(...) calls which isn’t going to work for us, as Preact uses h instead.
  • This is why we set "jsxFactory": "h" so that when Typescript encounters some JSX like <HelloWorld /> it will instead compile that into h(HelloWorld) which is what Preact can then use.

Step 3 — Create a webpack.config.js file

This is the minimum code needed to get this setup working. You can go crazy and do some awesome thing with Webpack, but I would suggest you start here and build up piece by piece as you need it — you’ll learn more this way as opposed to copy/pasting a 200 line config that someone else set up.

module.exports = {
devtool: 'source-map',
entry: ['./src/app'],
output: {
path: 'dist',
filename: 'app.js'
},
resolve: {
extensions: ['', '.ts', '.tsx']
},
module: {
loaders: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
loaders: ['ts-loader']
}
]
}
};

Notes:

  • We set the extensions array on the resolve property so that we can ‘import’ or ‘require’ both .ts.tsx files.
  • The single item in the loaders array will instruct Webpack to process any .ts or .tsx files with the ts-loader plugin that we installed before. The cool thing about ts-loader is that it will use your locally installed version of Typescript by default, so there’s nothing extra we have to configure. :)

Step 4 — Create the entry file src/app.tsx

import { h, render } from 'preact';
import HelloWorld from './HelloWorld';

render(<HelloWorld name="World" />, document.querySelector('#app'));

Notes:

  • on line 1 we import the render function from preact, but also the h function. We don’t need to manually call this function, but remember that Typescript will convert any JSX into h() calls, so we need it to be available in any file that contains JSX, otherwise we’ll see an error when trying to compile.
  • on line 3 we’re mounting the HelloWorld component into the DOM, and passing a single prop called name . We’re doing this as a simple example of where Typescript can help — by validating your props!

Step 4 — Create the HelloWorld Componentsrc/HelloWorld.tsx

import {h, Component} from 'preact';

export interface HelloWorldProps {
name: string
}

export default class HelloWorld extends Component<HelloWorldProps, any> {
render (props) {
return <p>Hello {props.name}!</p>
}
}

Notes:

  • I’ve declared the interface HelloWorldProps with a single name property here just to show how you can utilise generics when creating Components in Preact — just think of it as better propTypes. This is not a Typescript tutorial however, so we’ll leave the TS details there — just know that by providing Component<HelloWorldProps... we’re associating the interface HelloWorldProps with this HelloWorld class and this is what allows Typescript to provide type checking both inside this component and at any point in which this component is used elsewhere.
  • Notice that in the render function here we get access to the component's props (as well as state) — this is an area in which Preact improves upon React :). Again though, this is not a how-to-use Preact tutorial either, so we’ll keep this bit brief.

Recap

If you’re following along, your directory should now look like the following, (although if you used NPM to install your dependencies, you won’t have a yarn.lock file)

The minimum files needed for this setup

Step 5 — run Webpack to create the bundle

Because we installed Webpack locally, we can run it in the following way.

./node_modules/.bin/webpack

Webpack will use the config file that we created earlier to load the ‘entry’ point for the app. It will then create a bundle that includes each file we’ve referenced. So in our case the entry was ./src/app — so that will be included along with the Preact Library and our HelloWorld component.

If it all worked correctly, you should see something along the following lines:

Notes:

  • The file sizes in that screenshot are un-minified & un-gzipped as I didn’t want to include any extra config in this tutorial — but you can rest assured that when in production Preact really is just over 3.5kb :)

Step 6 — use the bundle in a web page index.html

Time to load it up in your browser of choice and marvel at the amazing HelloWorld component!

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="dist/app.js"></script>
</body>
</html>

Conclusion

Sometimes you have to do a little bit of extra work to get your favourite tools to play nicely together, but in my eyes it’s almost always worth it — especially if it boosts your productivity!. In this performance obsessed front-end world we live in I just cannot ignore a library like Preact that clocks in at only 3.5kb — but at the same time I was not willing to give up the developer experience I’ve become accustomed to with Typescript. This post shows that you can indeed have your cake, and eat it.

Like this? Perhaps you’d enjoy some of my lessons on https://egghead.io/instructors/shane-osbourne— many are free and I cover Vanilla JS, Typescript, RxJS and more.