Why Rollup Beats Webpack for Building a Simple JS Library
This article compares Webpack and Rollup, explains why Rollup’s tree‑shaking and ES6 module support make it better for a lightweight JavaScript utility library, and provides a step‑by‑step guide to set up the project with TypeScript, ESLint, Prettier, Husky, Commitlint and Jest testing.
Preface
Recently I was writing a frontend utility library. I started with Webpack, but then discovered Rollup, which better fits my needs. This article introduces building a simple JavaScript utility library with Rollup.
Requirements
Code level 1. Write code using ES6 syntax (including async) with specific parameter requirements. 2. Follow coding standards when committing. 3. Unit testing. 4. Generate documentation comments. Function level 1. Support mainstream browsers (e.g., Chrome, Firefox). 2. Provide common JS methods. 3. May depend on other libraries.
Webpack VS Rollup
Entry files Both Webpack and Rollup require a configuration file to specify entry, output, plugins, etc.
Relative path support: Webpack does not support it (requires
path.resolve); Rollup supports it.
This is just one simple difference; there are several more.
Tree‑shaking (dead code elimination)
Tree‑shaking reduces the bundle size by removing unused code, which shortens page load time. It works by statically analyzing ES6 modules.
Comparing the same code bundled by Webpack and Rollup:
Execution time: Webpack 71 ms, Rollup 17 ms.
File size: Webpack 389 KB, Rollup 262 KB.
The main reason is that Rollup uses tree‑shaking, leveraging ES6 module features for static analysis and removing dead code during the uglify phase.
ES6 Module Rules
Only top‑level statements (import/export) are allowed.
Import module specifiers must be string literals.
Imported modules cannot be reassigned.
<code>// Case 1
let str = '只能作为模块顶层的语句出现';
import { sum } from 'util';
// Case 2
import { 's' + 'um' } from 'util';
// Case 3
import { sum } from 'util'
sum = 1; // Syntax Error: 'sum' is read‑only
</code>Real‑time Reloading
Webpack uses
webpack-dev-server. Rollup uses
rollup-plugin-serve+
rollup-plugin-livereload. Webpack offers more customizable middleware options.
Summary
Webpack - Rich ecosystem, complete documentation, many plugins. - Code splitting and on‑demand loading with tree‑shaking (Webpack 2+). - Generates additional code, larger bundles, slower execution, lower readability. - Suitable for projects involving CSS/HTML, complex code splitting, or full applications.
Rollup - Smaller plugin ecosystem. - Bundles everything together, uses tree‑shaking to reduce size. - Usually produces no extra code, faster execution, better readability. - Ideal for building libraries.
Project Setup
Initialize project 1. Create folder
rollup-demo. 2. Run
npm init -y. 3. Install Rollup and a plugin to clear the
distdirectory:
npm i rollup rollup-plugin-clear -D. 4. Create entry file
src/main.js.
<code>function fun1(){
function fun2(){
return 'no'
}
return 'yes'
}
fun1()
console.log(fun1())
function Useless(){
console.log(1111)
}
</code>Create
rollup.config.jsin the project root:
<code>'use strict';
import clear from 'rollup-plugin-clear';
export default {
input: 'src/main.ts',
output: {
file: 'dist/bundle.js',
format: 'umd' // bundle format
},
plugins: [
clear({ targets: ['dist'] }) // clean dist folder
]
};
</code>Add a build script to
package.json:
<code>"build": "rollup -c rollup.config.js"
</code>Run
npm run buildto complete a simple Rollup build.
Using TypeScript
TypeScript provides static typing, better IDE support, and compile‑time checks, making code easier to read and refactor. Install the necessary packages:
<code>npm i rollup-plugin-typescript2 typescript -D
</code>Update
rollup.config.jsto use the TypeScript plugin:
<code>import ts from "rollup-plugin-typescript2";
export default {
input: "./src/main.ts",
plugins: [
ts({ useTsconfigDeclarationDir: true })
]
};
</code>Example
tsconfig.json:
<code>{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"lib": ["es2015", "es2016", "es2017"],
"strict": true,
"sourceMap": true,
"strictNullChecks": true,
"declaration": true,
"declarationDir": "dist/types",
"noUnusedLocals": true,
"outDir": "./dist",
"typeRoots": ["node_modules/@types"]
}
}
</code>ESLint & Prettier
ESLint enforces code quality rules; Prettier formats code. Install the following:
<code>npm i eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin prettier eslint-config-prettier eslint-plugin-prettier -D
</code>Create
.eslintrc.js:
<code>module.exports = {
root: true,
parser: '@typescript-eslint/parser',
parserOptions: { ecmaVersion: 2019, sourceType: 'module' },
extends: [
'plugin:@typescript-eslint/recommended',
'prettier/@typescript-eslint',
'plugin:prettier/recommended'
],
env: { es6: true, node: true },
rules: {
'no-undef': 'error',
'eqeqeq': 'error',
'no-console': 'error'
}
};
</code>Create
.prettierrc.js:
<code>module.exports = {
arrowParens: 'avoid',
bracketSpacing: false,
endOfLine: 'lf',
jsxBracketSameLine: false,
jsxSingleQuote: false,
printWidth: 100,
proseWrap: 'preserve',
semi: true,
singleQuote: true,
useTabs: false,
trailingComma: 'es5'
};
</code>Commit Code Standards (Husky, lint‑staged, Commitlint)
Install:
<code>npm i husky lint-staged -D
npm i @commitlint/cli @commitlint/config-conventional -D
</code>Create
huskyrc.js:
<code>module.exports = {
hooks: {
'commit-msg': 'commitlint -e $HUSKY_GIT_PARAMS',
'pre-commit': 'lint-staged'
}
};
</code>Create
lint-staged.config.js:
<code>module.exports = {
'{src,test}/**/*.ts': ['npm run lint', 'git add']
};
</code>Create
commitlint.config.js:
<code>module.exports = {
extends: ["@commitlint/config-conventional"],
rules: {
'subject-case': [2, 'always', ['upper-case']]
}
};
</code>Jest Testing
Jest provides fast parallel test execution, powerful mocking, built‑in coverage, DOM testing via JSDOM, and works with TypeScript via
ts-jest. Install:
<code>npm i jest @types/jest ts-jest -D
</code>Create
jest.config.js:
<code>module.exports = {
roots: ['<rootDir>/test'],
transform: { '.(ts|tsx)': 'ts-jest' },
testEnvironment: 'node',
testRegex: '(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$',
collectCoverage: true,
coveragePathIgnorePatterns: ['/node_modules/', '/test/'],
coverageThreshold: {
global: { branches: 90, functions: 95, lines: 95, statements: 95 }
}
};
</code>Create a sample test
test/main.test.ts:
<code>import Sum from '../src/main';
test('sum is right', () => {
expect(Sum(1, 2)).toBe(10);
});
</code>Add a test script to
package.json:
<code>"test": "jest"
</code>Conclusion
This article explained the differences between Webpack and Rollup, demonstrated how to build a simple JavaScript library with Rollup, and incorporated TypeScript, ESLint, Prettier, Husky, Commitlint, and Jest to ensure code quality. The complete project is available on GitHub: https://github.com/turning1998/baselib .
37 Mobile Game Tech Team
37 Mobile Game Tech Team
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.