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
// 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 ✨
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.
You can check bundler's behavior with rollup relp:
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());
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()
!!
First, global install Treeche.
npm install treeche -g
treeche "**/*.ts" --excludes "node_modules" "**/*.test.ts"
kind | name | description | example |
---|---|---|---|
argument | inputs | input files to check tree-shakable. you can use Node glob pattern | treeche "src/**/*.ts" |
option | excludes | excludes files to filter from inputs. you can use Node glob pattern | treeche "src/**/*.ts" --e "node_modules" |
option | entry point | the 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_modules | treeche --entry-point ./src/main.ts |
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.
This is experimental project, so your feedback is welcome!!