Zac Fukuda
044

Basic configuration of Webpack, Rollup, and Parcel
How the three bundlers are different

There is always an emerging technology. The new tools come with it.

I am going to list the basic configuration of modern JavaScript bundlers of:

to bundle each of the following JavaScript codes:

Each type of source file has extension of .js, .ts, .jsx or .tsx.

Along with the config files, I will show you the yarn commands to install the necessary packages.

The source code can be found at GitHub repo. Please follow the instruction written in the README.md to perform bundling on your machine.

Presumption

The configurations shown below are just to perform simple bundling. They do not adapt to:

  • Watching changes
  • Hot module replacement
  • Code splitting

Common config files

Whatever bundler you use, the configurations of TypeScript and Babel are shared. Please keep in mind that the configurations of the following two files are bare minimum, not to meet the need of various development.

Tyescript

tsconfig.json
{
  "compilerOptions": {
    "outDir": "./dist/",
    "noImplicitAny": true,
    "module": "es6",
    "target": "es5",
    "jsx": "react",
    "allowJs": true,
    "moduleResolution": "node"
  },
}

Babel

babel.config.js
{
  "presets": ["@babel/preset-react"]
}

Babel has an amazing page on how to install and setup itself based on the build system. See Using Babel.

Webpack

Webpack Logo

Please add build command to package.json:

package.json
{
	…
	"scripts": {
		"build": "webpack"
	},
	…
}

The default Webpack config file is webpack.config.js.

ES Module

const path = require('path');

module.exports = {
	mode: 'production',
	entry: './src/index.js',
	output: {
		filename: 'index.js',
		path: path.resolve(__dirname, 'dist'),
	},
};
yarn add -D webpack webpack-cli

TypeScript

const path = require('path');

module.exports = {
	mode: 'production',
	entry: './src/index.ts',
	output: {
		filename: 'index.js',
		path: path.resolve(__dirname, 'dist'),
	},
	module: {
		rules: [
			{
				test: /\.tsx?$/,
				use: 'ts-loader',
				exclude: /node_modules/,
			},
		],
	},
	resolve: {
		extensions: ['.tsx', '.ts', '.js'],
	},
};
yarn add -D ts-loader typescript webpack webpack-cli

React

const path = require('path');

module.exports = {
	mode: 'production',
	entry: './src/index.jsx',
	output: {
		filename: 'index.js',
		path: path.resolve(__dirname, 'dist'),
	},
	module: {
		rules: [
			{
				test: /\.jsx?$/,
				exclude: /node_modules/,
				use: {
					loader: "babel-loader",
					options: {
						presets: ['@babel/preset-react']
					}
				}
			}
		]
	},
};
yarn add react react-dom
yarn add -D @babel/core @babel/preset-react babel-loader webpack webpack-cli

React+TypeScript

const path = require('path');

module.exports = {
	mode: 'production',
	entry: './src/index.tsx',
	output: {
		filename: 'index.js',
		path: path.resolve(__dirname, 'dist'),
	},
	module: {
		rules: [
			{
				test: /\.tsx?$/,
				use: 'ts-loader',
				exclude: /node_modules/,
			},
		],
	},
	resolve: {
		extensions: ['.tsx', '.ts', '.js'],
	},
};
yarn add react react-dom
yarn add -D @babel/core @babel/preset-react @types/react @types/react-dom ts-loader typescript webpack webpack-cli

Rollup

Rollup Logo

Please add build command to package.json:

package.json
{
	…
	"scripts": {
		"build": "rollup --bundleConfigAsCjs"
	},
	…
}

The --bundleConfigAsCjs option allows you to use import/export in rollup.config.js without setting "type": "module" in package.json.

The default Rollup config file is rollup.config.js.

ES Module

export default {
	input: 'src/index.js',
	output: {
		file: 'dist/index.js',
		format: 'iife'
	},
};
yarn add -D rollup

TypeScript

import typescript from '@rollup/plugin-typescript';

export default {
	input: 'src/index.ts',
	output: {
		file: 'dist/index.js',
		format: 'iife'
	},
	plugins: [typescript()]
};
yarn add -D @rollup/plugin-typescript rollup tslib typescript

React

import replace from '@rollup/plugin-replace';
import babel from '@rollup/plugin-babel';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';

export default {
	input: 'src/index.jsx',
	output: {
		file: 'dist/index.js',
		format: 'iife',
	},
	plugins: [
		replace({
			'process.env.NODE_ENV': JSON.stringify('production'),
			preventAssignment: true,
		}),
		babel({babelHelpers: 'bundled'}),
		resolve(),
		commonjs(),
	],
};
yarn add react react-dom
yarn add -D @babel/core @babel/preset-react @rollup/plugin-babel @rollup/plugin-commonjs @rollup/plugin-node-resolve @rollup/plugin-replace rollup

React+TypeScript

import replace from '@rollup/plugin-replace';
import typescript from '@rollup/plugin-typescript';
import babel from '@rollup/plugin-babel';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';

export default {
	input: 'src/index.tsx',
	output: {
		file: 'dist/index.js',
		format: 'iife',
	},
	plugins: [
		replace({
			'process.env.NODE_ENV': JSON.stringify('production'),
			preventAssignment: true,
		}),
		typescript(),
		babel({babelHelpers: 'bundled'}),
		resolve(),
		commonjs(),
	],
};
yarn add react react-dom
yarn add -D @babel/core @babel/preset-react @rollup/plugin-babel @rollup/plugin-commonjs @rollup/plugin-node-resolve @rollup/plugin-replace @rollup/plugin-typescript @types/react @types/react-dom rollup tslib typescript

Parcel

Webpack Logo

Please add build command to package.json:

package.json
{
	…
	"scripts": {
		"build": "parcel build"
	},
	…
}

Parcel doesn’t have dedicated config file. You add config properties to package.json.

ES Modules

{
	…
	"source": "src/index.js",
	"main": "dist/index.js",
	…
}
yarn add -D parcel

TypeScript

{
	…
	"source": "src/index.ts",
	"main": "dist/index.js",
	…
}
yarn add -D parcel typescript

React

{
	…
	"source": "src/index.jsx",
	"main": "dist/index.js",
	…
}
yarn add react react-dom
yarn add -D parcel

React+TypeScript

{
	…
	"source": "src/index.tsx",
	"main": "dist/index.js",
	…
}
yarn add react react-dom
yarn add -D @types/react @types/react-dom parcel typescript

What’s best

Here is my opinion.

Webpack still has the advantage of its longevity, despite its hustling configuration. Very extendable, rich documents, plenty of resources are available on the Internet.

Rollup is the alternative to Webpack. When you run yarn add -D rollup, the file size of node_modules was 2.7MB, while that of Webpack is 19.2MB. The project was suspended but when I developed CI build system for serverless app on Amazon Web Service, I chose to use Rollup. The simple compilation was enough. Webpack was a overkill.

Rollup is great for package development, not so for application development.

Parcel is not an option. Its non-configuration philosophy makes the project rigid, leaving programmers skeptical to use them in the nature and dynamism of software development.

Resources