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 other frameworks like Angular.
So far, it has been a good experience in terms of performance and tools integration.
What is Rollup?
In words of the official documentation:
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.
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.
- 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:
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.
npm init -y
The previous command will create the package.json
with some defaults. You can edit that file later according to your needs:
{
"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:
|- typescript-rollup
|- src/
|- math/
|- math.ts
|- index.ts
|- string/
|- string.ts
|- index.ts
|- app.ts
Add the Math operations in math/math.ts
file:
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:
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.
In order to import related functions regardless of the filenames, we can create the index.ts
files in both directories:
// src/math/index.ts
export { add, substract } from './math';
// src/string/index.ts
export { toLowerCase, toUpperCase } from './string';
Pay attention to the src/app.ts
file:
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:
npm install --save-dev rollup typescript
Additional tools are needed:
- @open-wc/building-rollup, as a rollup plugin for integration between Rollup.js and TypeScript,
- rimraf, which is the UNIX command
rm -rf
for Node.js - deepmerge, a tool to merge enumerable properties or more objects deeply.
Use a single command to have all of them as new dependencies:
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.
tsc --init
message TS6071: Successfully created a tsconfig.json file.
Let's apply some changes to that file:
{
"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 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:
// 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. Also, find an example of the TypeScript support 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:
{
...
"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 intsconfig.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 adist
folder. Those configurations are defined in therollup.config.js
file.
Generate the Build and Run the App
Run the build
script using:
npm run build
You'll have the following output:
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:
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:
|- 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 for seamless integration between Rollup and TypeScript.
// 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:
// 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:
// 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 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. Do not forget to give it a star ⭐️ and play around with the code.
You can follow me on Twitter and GitHub to see more about my work.