inline-functions
v0.0.1
Published
This library allows you to inline functions in your JS/TS code. This is useful for performance reasons, as it allows you to avoid function calls and instead inline the function body directly. It provides plugins for Vite, Rollup and esbuild.
Downloads
6
Maintainers
Readme
inline-functions
This library allows you to inline functions in your JS/TS code. This is useful for performance reasons, as it allows you to avoid function calls and instead inline the function body directly.
It comes as a collection of plugins for different build systems. It is designed to be used with vite
, rollup
, and esbuild
.
Inspired by the clever trick used in robust-predicates
by @mourner.
Installation
npm install inline-functions [vite] [rollup] [esbuild]
How it works
This plugin works by replacing function calls with the function body. This is done by using a macro system. The macro system is a simple object that maps function names to their bodies. For example:
import { Vec2, fn2 } from "./utils";
// this is the "real" implementation of the function
// it guarantees that the code will work even if the inlining step is skipped
const add = (a: Vec2, b: Vec2): Vec2 => {
a[0] += b[0];
a[1] += b[1];
};
const foo: Vec2 = [4, 5];
const bar: Vec2 = [5, fn2(6, 12)];
const ZERO = (): Vec2 => [0, 0];
const baz: Vec2 = [33, 22];
// note that you can use the function in the macro,
// if your replacement function can handle it
add(baz, ZERO());
// so that dead code removal doesn't remove the function altogether
console.log(foo, baz);
// this will work, but will be removed as dead code
add(ZERO(), bar);
Then the macros to inline the add()
function calls, would look like this:
// counter is used to generate unique variable names
let counter = 0;
const macros = {
add: (a, b) => {
const _a = `_a${counter++}`;
const _b = `_b${counter++}`;
// this will reference the arguments passed to the function
return `
const ${_a} = ${a};
const ${_b} = ${b};
${_a}[0] = ${_a}[0] + ${_b}[0];
${_a}[1] = ${_a}[1] + ${_b}[1];
`;
},
};
And the result of this replacement is:
var foo = [4, 5];
var ZERO = function () {
return [0, 0];
};
var baz = [33, 22];
// note that you can use the function in the macro,
// if your replacement function can handle it
const _a0 = baz;
const _b1 = ZERO();
_a0[0] = _a0[0] + _b1[0];
_a0[1] = _a0[1] + _b1[1];
// so that dead code removal doesn't remove the function altogether
console.log(foo, baz);
Usage
Vite
npm install inline-functions vite
Then, in your vite.config.ts
:
import { defineConfig } from "vite";
import inlineFunction from "inline-functions/vite";
import { resolve } from "path";
import { macros } from "./macros";
export default defineConfig({
..., // your config
plugins: [inlineFunction({ macros })],
});
Esbuild
npm install inline-functions esbuild
Then, in your esbuild.config.js
:
import inlineFunction from "inline-functions/esbuild";
import { macros } from "./macros";
esbuild
.build({
entryPoints: ...,
bundle: true,
outfile: ...,
plugins: [inlineFunction({ macros })],
})
.catch(() => process.exit(1));
Rollup
npm install inline-functions rollup
Then, in your rollup.config.js
:
import inlineFunction from "inlin-function/rollup";
import { macros } from "./macros";
export default {
input: ...,
output: {
...
},
plugins: [inlineFunction({ macros })],
};
Examples
See test
for examples and benchmarks.
Some benchmarks
Running "Vite" suite...
Progress: 100%
Inlined:
1 464 435 ops/s, ±4.63% | fastest
Not inlined:
1 187 396 ops/s, ±5.75% | slowest, 18.92% slower
Running "Rollup" suite...
Inlined:
1 560 921 ops/s, ±1.27% | fastest
Not inlined:
1 302 231 ops/s, ±0.11% | slowest, 16.57% slower
Running "esbuild" suite...
Inlined:
1 564 889 ops/s, ±0.80% | fastest
Not inlined:
1 281 501 ops/s, ±1.02% | slowest, 18.11% slower