Table of ContentsWhat is Treeche?ExampleWhat is side-effect in the context of module bundling?Why does side-effect cause an increase of bundle-size?How to use?OptionsHow to work?Feedback

Treeche, Tree-Shakable Checker for JavaScript/TypeScript Application to reduce bundle size

2022/08/27
Programming
JavaScript
DX
Frontend

What is Treeche?

Treeche stands for Tree -Shakable Che cker. You can check whether or not your JavaScript/TypeScript Application is tree-shakable with Treeche, and this diagnose will allow you to reduce bundle size and optimize UserExperience!!

https://github.com/Shinyaigeek/treeche

Example

// this is not tree-shakable because have side-effect

const currentYear = new Date().getFullYear();

export function getCurrentYear() {
    return `Year ${currentYear}`
}

The above code is not tree-shakable, because the above typescript module has side-effect.

Treeche show the diagnose like below for the above code:

🚨 ~/application/side_effect.ts is not tree-shakable due to the following code:


const currentYear = new Date().getFullYear();
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If you fix the module with side-effect to the module which does not have side-effect like below.

export function getCurrentYear(currentDate: Date) {
    return `Year ${currentDate.getFullYear()}`
}

and Treeche will show the diagnose like below:

Congratulation 🎉 All files are tree-shakeable ✨

What is side-effect in the context of module bundling?

A side-effect in ECMAScript module context is a code that effects outside the module. For example, it is side-effect to set a variable to window object in module top-level like below:

window.m = 1;
export mod() {
    return 1;
}

Of course, if this were to happend in init module, this will not be invoked on import so this will no longer be a side effect.

Why does side-effect cause an increase of bundle-size?

You can check bundler's behavior with rollup relp:

URL: https://rollupjs.org/repl/?version=2.78.1&shareable=JTdCJTIybW9kdWxlcyUyMiUzQSU1QiU3QiUyMm5hbWUlMjIlM0ElMjJtYWluLmpzJTIyJTJDJTIyY29kZSUyMiUzQSUyMmltcG9ydCUyMCU3QiUyMGhvZ2UlMjAlN0QlMjBmcm9tJTIwJTVDJTIyLiUyRm1vZCU1QyUyMiUzQiU1Q24lNUNuY29uc29sZS5sb2coaG9nZSgpKSUyMiUyQyUyMmlzRW50cnklMjIlM0F0cnVlJTdEJTJDJTdCJTIybmFtZSUyMiUzQSUyMm1vZC5qcyUyMiUyQyUyMmNvZGUlMjIlM0ElMjJleHBvcnQlMjBmdW5jdGlvbiUyMGhvZ2UoKSUyMCU3QiU1Q24lNUN0cmV0dXJuJTIwMSUzQiU1Q24lN0QlNUNuJTVDbmV4cG9ydCUyMGZ1bmN0aW9uJTIwZnVnYSgpJTIwJTdCJTVDbiU1Q3RyZXR1cm4lMjBuZXclMjBEYXRlKCkuZ2V0RnVsbFllYXIoKSUzQiU1Q24lN0QlMjIlN0QlNUQlMkMlMjJvcHRpb25zJTIyJTNBJTdCJTIyZm9ybWF0JTIyJTNBJTIyZXMlMjIlMkMlMjJuYW1lJTIyJTNBJTIybXlCdW5kbGUlMjIlMkMlMjJhbWQlMjIlM0ElN0IlMjJpZCUyMiUzQSUyMiUyMiU3RCUyQyUyMmdsb2JhbHMlMjIlM0ElN0IlN0QlN0QlMkMlMjJleGFtcGxlJTIyJTNBbnVsbCU3RA==

main.js

import { hoge } from "./mod";

console.log(hoge())

mod.js

export function hoge() {
	return 1;
}

export function fuga() {
	return new Date().getFullYear();
}

and bundled result by rollup is like above:

function hoge() {
	return 1;
}

console.log(hoge());

You know fuga module in mod.js is tree-shaken because the bundler know fuga module is not imported( and of course not used) and the bundler does not need to include fuga module to its bundle output, and this lead a decrease of bundle-size.

However, if your edit mod.js like below:

export function hoge() {
	return 1;
}

const _fuga = new Date().getFullYear();

export function fuga() {
	return _fuga;
}

the bundled output will be like above:

function hoge() {
	return 1;
}

new Date().getFullYear();

console.log(hoge());

https://rollupjs.org/repl/?version=2.78.1&shareable=JTdCJTIybW9kdWxlcyUyMiUzQSU1QiU3QiUyMm5hbWUlMjIlM0ElMjJtYWluLmpzJTIyJTJDJTIyY29kZSUyMiUzQSUyMmltcG9ydCUyMCU3QiUyMGhvZ2UlMjAlN0QlMjBmcm9tJTIwJTVDJTIyLiUyRm1vZCU1QyUyMiUzQiU1Q24lNUNuY29uc29sZS5sb2coaG9nZSgpKSUyMiUyQyUyMmlzRW50cnklMjIlM0F0cnVlJTdEJTJDJTdCJTIybmFtZSUyMiUzQSUyMm1vZC5qcyUyMiUyQyUyMmNvZGUlMjIlM0ElMjJleHBvcnQlMjBmdW5jdGlvbiUyMGhvZ2UoKSUyMCU3QiU1Q24lNUN0cmV0dXJuJTIwMSUzQiU1Q24lN0QlNUNuJTVDbmNvbnN0JTIwX2Z1Z2ElMjAlM0QlMjBuZXclMjBEYXRlKCkuZ2V0RnVsbFllYXIoKSUzQiU1Q24lNUNuZXhwb3J0JTIwZnVuY3Rpb24lMjBmdWdhKCklMjAlN0IlNUNuJTVDdHJldHVybiUyMF9mdWdhJTNCJTVDbiU3RCUyMiU3RCU1RCUyQyUyMm9wdGlvbnMlMjIlM0ElN0IlMjJmb3JtYXQlMjIlM0ElMjJlcyUyMiUyQyUyMm5hbWUlMjIlM0ElMjJteUJ1bmRsZSUyMiUyQyUyMmFtZCUyMiUzQSU3QiUyMmlkJTIyJTNBJTIyJTIyJTdEJTJDJTIyZ2xvYmFscyUyMiUzQSU3QiU3RCU3RCUyQyUyMmV4YW1wbGUlMjIlM0FudWxsJTdE

Why is an unnecessary new Date().getFullYear() in the bundled output? Because new Date().getFullYear() has side-effect. In JavaScript, imported module is executed once on import, so a bundler cannot remove a line which have side-effect like new Date().getFullYear(). If you import fuga module, it is expected that new Date().getFullYear() will be inserted in a bundled output, but if you don't import fuga module, it is not expected that new Date().getFullYear() will be inserted in a bundled output because the other module, hoge, does not need const _fuga = new Date().getFullYear() !!

How to use?

First, global install Treeche.

npm install treeche -g
treeche "**/*.ts" --excludes "node_modules" "**/*.test.ts"

Options

kindnamedescriptionexample
argumentinputsinput files to check tree-shakable. you can use Node glob patterntreeche "src/**/*.ts"
optionexcludesexcludes files to filter from inputs. you can use Node glob patterntreeche "src/**/*.ts" --e "node_modules"
optionentry pointthe unique entry point to check tree-shakable. if you specify input with this, treeche will bundle so you can check tree-shakable also in node_modulestreeche --entry-point ./src/main.ts

How to work?

The principle is really simple. Treeche runs rollup, which is JavaScript module bundler, internally to bundle the virtual entrypoint code which imports the input module like below.


import "./your-module"

If there is a side-effect in "./your-module", the output will include the code other than import.

Feedback

This is experimental project, so your feedback is welcome!!

monkey-icon
earth
Hi 👋 I'm Shinobu Hayashi a.k.a Shinyaigeek(しにゃい).
Web Developer 🕸 / Reliable Web Enthusiast 🔥
Faster, Lighter, More accessible, More secure, More productive Web for anyone, anytime , anywhere.
twitter
github
linkedin
Copyright. 2022 Shinyaigeek