npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

optimize-js-code-cache

v1.1.0

Published

Optimize JavaScript execution/parsing by wrapping functions

Downloads

13

Readme

optimize-js-code-cache JavaScript Style Guide

Optimize a JavaScript file for faster execution, by wrapping almost all function expressions in parentheses. This allows V8 to compile code in background thread and use the code cache. Forked from https://github.com/nolanlawson/optimize-js.

A blog post from the V8 team with some details.

Install

npm install -g optimize-js-code-cache

Usage

optimize-js-code-cache input.js > output.js

Example input:

!function (){}();
function runIt(fun){ fun() }
runIt(function (){});
var x=function(){}();
var do1=function(){},do2=()=>{},dont1=function dont1(){};
[].concat([function(a){},b=>{},(function(c){}),(d=>{})]);
chunk.push([{1:function(a){},2:b=>{},x:function(a){},y:b=>{}}]);

Example output:

!(function (){})();
function runIt(fun){ fun() }
runIt((function (){}));
var x=(function(){})();
var do1=(function(){}),do2=(()=>{}),dont1=function dont1(){};
[].concat([(function(a){}),(b=>{}),(function(c){}),(d=>{})]);
chunk.push([{1:(function(a){}),2:(b=>{}),x:(function(a){}),y:(b=>{})}]);

Benchmark overview

Bundle execution before:

  • ≈74 ms code compilation
  • ≈100 ms overall

before

Bundle execution after:

  • ≈11 ms code compilation
  • ≈27 ms overall

after

CLI

Usage: optimize-js-code-cache [ options ]

Options:
      --version                             Show version number        [boolean]
      --source-map, --sourceMap             Include source map         [boolean]
      --ecma-version, --ecmaVersion         The ECMAScript version to parse.
                                            Must be either 3, 5, 6 (or 2015), 7
                                            (2016), 8 (2017), 9 (2018), 10
                                            (2019), 11 (2020), 12 (2021), 13
                                            (2022), 14 (2023), or "latest" (the
                                            latest version the library
                                            supports). This influences support
                                            for strict mode, the set of reserved
                                            words, and support for new syntax
                                            features.
     [choices: 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 2015, 2016, 2017, 2018,
                                   2019, 2020, 2021, 2022, 2023, 2024, "latest"]
      --handle-function-declarations,       Specify how to handle
      --handleFunctionDeclarations          FunctionDeclaration nodes: "none"
                                            skips them completely; "unsafe"
                                            wraps all declarations; "safe" wraps
                                            only declarations that are not used
                                            before declaration and thus
                                            preserves hoisting (that otherwise
                                            can result in broken code, when the
                                            function is called before being
                                            assigned to variable).
                                             [choices: "none", "safe", "unsafe"]
  -h, --help                                Show help                  [boolean]

Examples:
  optimize-js-code-cache input.js > output.js    optimize input.js
  optimize-js-code-cache < input.js > output.js  read from stdin, write to stdout

JavaScript API

const { optimizeJs } = require('optimize-js-code-cache');
const input = "!function() {console.log('wrap me!')}";
const output = optimizeJs(input); // "!(function() {console.log('wrap me!')})()"

You can also pass in arguments:

const { optimizeJs } = require('optimize-js-code-cache');
const input = "!function() {console.log('wrap me!')}";
const output = optimizeJs(input, {
  sourceMap: true,
  ecmaVersion: 2024
}); // now the input is parsed as ES2024 and the output has source maps

FAQs

How does it work?

The current implementation is to parse to a syntax tree and check for functions that:

  1. Are immediately-invoked via any kind of call statement (function(){}(), !function(){}(), etc.)
  2. Are passed in directly as arguments to another function
  3. Are just plain function expressions or function declarations

The first method is an easy win – those functions are immediately executed. The second method is more of a heuristic, but tends to be a safe bet given common patterns like Node-style errbacks, Promise chains, and UMD/Browserify/Webpack module declarations. The third method supposes that most function expressions will be compiled and executed during the execution of code bundle.

In all such cases, optimize-js-code-cache wraps the function in parentheses.

But... you're adding bytes!

Yes, optimize-js-code-cache might add as many as two bytes (horror!) per function expression and up to seven bytes per function declaration, which amounts to practically nil once you take gzip into account.

Is optimize-js-code-cache intended for library authors?

If you are already shipping a bundled, minified version of your library, then there's no reason not to apply optimize-js-code-cache (assuming you benchmark your code to ensure it does indeed help!). However, note that optimize-js-code-cache should run after Terser/Uglify/any other minification, since they strip extra parentheses and also negate IIFEs by default. This also means that if your users apply Uglification to your bundle, then the optimization will be undone.

Also note that because optimize-js-code-cache optimizes for some patterns that are based on heuristics rather than known eagerly-invoked functions, it may actually hurt your performance in some cases. (See benchmarks below for examples.) Be sure to check that optimize-js-code-cache is a help rather than a hindrance for your particular codebase, using something like:

<script>
var start = performance.now();
</script>
<script src="myscript.js"></script>
<script>
var end = performance.now();
console.log('took ' + (end - start) + 'ms');
</script>

Note that the script boundaries are actually recommended, in order to truly measure the full parse/compile time. If you'd like to avoid measuring the network overhead, you can see how we do it in our benchmarks.

You may also want to check out marky, which allows you to easily set mark/measure points that you can visually inspect in the Dev Tools timeline to ensure that the full compile time is being measured.

Shouldn't this be Uglify's job?

Possibly! This is a free and open-source library, so I encourage anybody to borrow the code or the good ideas. :)

Does this really work for every JavaScript engine?

Based on tests, this optimization seems to work best for V8 (Chrome), followed by SpiderMonkey (Firefox). For JavaScriptCore (Safari) it seems to be basically a wash, and may actually be a slight regression overall depending on your codebase. (Again, this is why it's important to actually measure on your own codebase, on the browsers you actually target!)

See also

Contributing

Build and run tests:

npm install
npm test

Run the benchmarks:

npm run benchmark # then open localhost:9090 in a browser

Test code coverage:

npm run coverage