How to Setup a TypeScript project using Rollup.js
Tags: typescript, rollup, webdev
Published: 2021-01-20 04:39:04

A couple of months ago, I started to work through web standards, Rollup.js, and TypeScript. It’s my first experience using Rollup although I’ve been working with TypeScript on different projects and using it along with other frameworks like Angular.

So far, it has been a good experience in terms of performance and tools integration.

![rollup-typescript](//images.ctfassets.net/zojzzdop0fzx/5b35MD6Vv5bbkc9qA7C5vN/a62d902c6604c8b99543cba55936da03/rollup-typescript.png)

## What is Rollup?
In words of the official [documentation](https://rollupjs.org/guide/en/):

> Rollup is a module bundler for JavaScript which compiles small pieces of code into something larger and more complex, such as a library or application...

What does that mean? Let’s start by saying that JavaScript improved drastically since ES6, and now it’s possible to define small portions of code that can be shared using two magical keywords: _import_ and _export_. This specification is supported by modern browsers and tools. Rollup allows writing a _future-proof code_ using the new module system without missing the compatibility with other module systems like CommonJS, AMD, and others.

Rollup also is considered as the "Next-generation ES module bundler", an alternative to the very known bundler [Webpack](https://webpack.js.org/).

## Project Setup
Let's start building a small application based in TypeScript. Our first goal would be to compile and build it using Rollup.

### Prerequisites
You need to install the following tools in your local environment:

* **Node.js**. Preferably the latest [LTS version](https://nodejs.org/en/about/releases/).
* **A package manager**. You can use either NPM or Yarn. This tutorial will use NPM.

### Initialize the Project
You'll need a new folder to get started, you can create it from a command-line interface or from your favorite IDE/Code Editor:

```bash
mkdir typescript-rollup
cd typescript-rollup
```

Let's start running the first command inside that folder to create the `package.json` file and have an initialized project. This will be useful to manage and install packages later.

```bash
npm init -y
```
The previous command will create the `package.json` with some defaults. You can edit that file later according to your needs:

```json
{
  "name": "typescript-rollup",
  "version": "1.0.0",
  "description": "A basic TypeScript project built using Rollup.js",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/luixaviles/typescript-rollup.git"
  },
  "keywords": [],
  "author": "Luis Aviles <@luixaviles>",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/luixaviles/typescript-rollup/issues"
  },
  "homepage": "https://github.com/luixaviles/typescript-rollup#readme"
}
```

Use `npm init` only if you want to set your preferences with the interactive mode of the command. 

### Source Code Files
Let's create a library to perform basic Math operations and perform strings processing. The project will contain the following source files:

```text
|- typescript-rollup
    |- src/
        |- math/
            |- math.ts
            |- index.ts
        |- string/
            |- string.ts
            |- index.ts
        |- app.ts
```

Add the Math operations in `math/math.ts` file:

```ts
export function add(x: number, y: number): number {
  return x + y;
}

export function substract(x: number, y: number): number {
  return x - y;
}
```

Then, the strings operations will be defined in `string/string.ts` file:

```ts
export const toLowerCase = (input: string): string => {
  return input.toLocaleLowerCase();
};

export const toUpperCase = (input: string): string => {
  return input.toUpperCase();
};
```

In the latest file, we're exporting a function using the ES6 [Arrow function expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions).

In order to import related functions regardless of the filenames, we can create the `index.ts` files in both directories:

```ts
// src/math/index.ts
export { add, substract } from './math';
```

```ts
// src/string/index.ts
export { toLowerCase, toUpperCase } from './string';
```

Pay attention to the `src/app.ts` file:

```ts
import { add, substract } from './math';

const x = 20;
const y = 10;

console.log(`${x} + ${y} = ${add(x, y)}`)
console.log(`${x} - ${y} = ${substract(x, y)}`);

```

The `app.ts` file is the starting point of our application. Also, take a look at the first import line. We don't need to import those functions from `./math/math.ts` file, since all of them have been exported in `/math/index.ts` file. Again, this is a convenient way to organize the library content using TypeScript.

### Installing Rollup and TypeScript

Let's continue installing Rollup and TypeScript as development dependencies:

```bash
npm install --save-dev rollup typescript
```

Additional tools are needed:
* [@open-wc/building-rollup](https://www.npmjs.com/package/@open-wc/building-rollup), as a rollup plugin for integration between Rollup.js and TypeScript, 
* [rimraf](https://www.npmjs.com/package/rimraf), which is the UNIX command `rm -rf` for Node.js
* [deepmerge](https://www.npmjs.com/package/deepmerge), a tool to merge enumerable properties or more objects deeply. 

Use a single command to have all of them as new dependencies:

```bash
npm install --save-dev @open-wc/building-rollup rimraf deepmerge
```

### TypeScript Configuration
For every TypeScript project, it's required to create the `tsconfig.json` file. It indicates that the directory is the root of a [TypeScript project](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html).

```bash
tsc --init
message TS6071: Successfully created a tsconfig.json file.
```

Let's apply some changes to that file:

```json
{
  "compilerOptions": {
    "target": "es2018",                          
    "module": "esnext",
    "moduleResolution": "node",                     
    "noEmitOnError": true,
    "lib": ["es2017"],                            
    "strict": true,  
    "esModuleInterop": false,                 
    "outDir": "out-tsc",
    "rootDir": "./"
  }
  ,
  "include": ["./src/**/*.ts"]
}
```

The most important thing here is the `outDir` option since the value says where the JavaScript files will be generated. Also, the `include` parameter will list a set of patterns of the files to be included in the compilation.

Learn more about the `compilerOptions` and the `tsconfig.json` file in [TsConfig Reference](https://www.typescriptlang.org/tsconfig) documentation.

### Rollup Configuration
It's time to configure the module bundler tool: Rollup. You can use Rollup from a command-line interface along with parameters. However, you can provide a configuration file to simplify the usage and provide advanced functionality. 

Let's create a `rollup.config.js` file with the next content:

```js
// rollup.config.js

import merge from 'deepmerge';
import { createBasicConfig } from '@open-wc/building-rollup';

const baseConfig = createBasicConfig();

export default merge(baseConfig, {
  input: './out-tsc/src/app.js',
  output: {
      dir: 'dist',
  }
});
```

Take a look at the documentation if you're curious about the different ways to use these [configuration files](https://rollupjs.org/guide/en/#configuration-files). Also, find an example of the [TypeScript support](https://www.npmjs.com/package/@open-wc/building-rollup#support-for-typescript) provided by `@open-wc/building-rollup` package.

### The Build script

In the `package.json` file, define a script to compile the input files and run the previous configurations:

```json
{
  ...
  "scripts": {
    "build": "rimraf dist && tsc && rollup -c rollup.config.js"
  },
  ...
}
```

Here's what is happening with the script:

* `rimraf dist`, will make sure to clean up the output directory for Rollup: `dist`
* `tsc`, will run the TypeScript compiler through the configurations defined in `tsconfig.json` file. The output content will be located in the `./out-tsc` directory, as defined in the TypeScript configuration file.
* `rollup -c rollup.config.json`, will run Rollup and take the `./out-tsc` directory as input and put the result in a `dist` folder. Those configurations are defined in the `rollup.config.js` file.

### Generate the Build and Run the App

Run the `build` script using:

```bash
npm run build
```

You'll have the following output:

```bash
npm run build

> typescript-rollup@1.0.0 build /Users/luixaviles/projects/github/typescript-rollup
> rimraf dist && tsc && rollup -c rollup.config.js

./out-tsc/src/app.js → dist...
created dist in 300ms
```

Finally, run the single file generated as a result of the build script:

```bash
node dist/7b857f5b.js 
20 + 10 = 30
20 - 10 = 10
```

You'll see the expected output.

## The Final Project Structure

You should have the following project structure, including the source code files and configurations:

```text
|- typescript-rollup
    |- src/
        |- math/
            |- math.ts
            |- index.ts
        |- string/
            |- string.ts
            |- index.ts
        |- app.ts
    |- package.json
    |- rollup.config.js
    |- tsconfig.json
```

## Alternatives to integrate Rollup and TypeScript
In case you're planning to build a SPA project(_Single Page Application_), you can use the `createSpaConfig` in Rollup configuration. Also, you can install the [@rollup/plugin-typescript](https://github.com/rollup/plugins/tree/master/packages/typescript) for seamless integration between Rollup and TypeScript.

```js
// rollup.config.js
import merge from 'deepmerge';
import { createSpaConfig } from '@open-wc/building-rollup';
import typescript from '@rollup/plugin-typescript';

const baseConfig = createSpaConfig();

export default merge(baseConfig, {
  input: './index.html',
  plugins: [typescript()],
});
```

The `@rollup/plugin-typescript` will load any `compilerOptions` from the `tsconfig.json` file by default. However, there's an option to override those configurations:

```js
// rollup.config.js

...
export default merge(baseConfig, {
  input: './index.html',
  plugins: [typescript({target: "es5"})],
});
```

In case you prefer a simple configuration, then you can set the `rollup.config.js` file using only this plugin:

```js
// rollup.config.js
import typescript from '@rollup/plugin-typescript';

export default {
  input: 'src/app.ts',
  output: {
    dir: 'output',
    format: 'cjs',
  },
  plugins: [typescript()],
};
```

Or even better, use the [open-wc project generator](https://open-wc.org/) for an automated setup through Rollup, TypeScript, and even Web Components.

## Source Code of the Project

Find the complete project in this GitHub repository: [typescript-rollup](https://github.com/luixaviles/typescript-rollup). Do not forget to give it a star ⭐️ and play around with the code.

You can follow me on [Twitter](https://twitter.com/luixaviles) and [GitHub](https://github.com/luixaviles) to see more about my work.

---
*This Dot Labs is a modern web consultancy focused on helping companies realize their digital transformation efforts. For expert architectural guidance, training, or consulting in React, Angular, Vue, Web Components, GraphQL, Node, Bazel, or Polymer, visit [thisdotlabs.com](https://www.thisdotlabs.com).*

*This Dot Media is focused on creating an inclusive and educational web for all.  We keep you up to date with advancements in the modern web through events, podcasts, and free content. To learn, visit [thisdot.co](https://www.thisdot.co).*