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

lazy-imports

v0.0.8

Published

Enable lazy-loading of dependencies while using normal `import` syntax, without a bundler. Supports TypeScript's downlevel compilation.

Downloads

11

Readme

lazy-imports

Enable lazy-loading of dependencies while using normal import syntax, without a bundler. Supports TypeScript's downlevel compilation.

I created this to boost the performance of a CLI tool. If the user runs cli-tool --help they should see usage info very quickly without loading, for example, the aws-sdk. If they run cli-tool upload-report-to-s3 then it should load only the dependencies used for that subcommand. I wanted to accomplish this lazy-loading without sprinkling our codebase with manual, delayed require() or import() calls.

Example

For TS support, you must have importHelpers enabled, since we monkey-patch 'tslib'.

import 'lazy-imports/enable';
import {parseCliArgs} from './cli-parser';
import {foo, bar} from 'some-expensive-module';
require('lazy-imports/disable'); // <-- as a function call so that autogenerated import statements will appear *above* it.
                                 //     Write as an `import` if you do not want this behavior.

const args = parseCliArgs(); // <-- this should be really fast without loading the expensive module

if(args.doExpensiveOperation) {
    foo(); // <-- first usage will trigger require()ing of the expensive module
    bar();
}

Caveats and Gotchas

I don't know what will happen if you leave lazy-imports enabled after your import statements. I always disable it.

The return value from a lazy require() will be a Proxy object pretending to be a function. Typically this covers all the bases: if the module is a function or constructor, you can invoke it, and if it's an object, you can access properties of it. This might break if the module does something atypical like module.exports = 'a string';

How it works

We replace require('module')._load with a version that returns lazy Proxy objects. We also replace require('tslib').__importStar and .__importDefault since TypeScript generates code that looks like const some_import_1 = __importStar(require('some-expensive-module')); which would otherwise immediately trigger eager loading.

lazy-imports/{enable|disable} immediately remove themselves from require cache, so each time you import them, they execute and enable / disable lazy loading. This is necessary because import statements are hoisted above all other statements, so our enable / disable logic must be in the form of import statements. We can't, for example, do enableLazyLoading().

TODOs

Allow automatically enabling laziness across an entire codebase, without enabling and disabling in each file. For example, pass a root directory, and any imports performed by files under that directory will be automatically lazy-imported. This allows us to apply lazy-loading to our own codebase and skip it for external codebases.

  • could use globs, but that's more runtime weight; potentially slows things down
  • trick is enabling at the top of our entry-point file. We'll still need to use the import trick there
#!/usr/bin/env node
// entry point file
import 'lazy-imports/enable';
//... imports ...
require('lazy-imports/disable');
require('lazy-imports').enableForPrefix(`${ __dirname }/`);

Needing to manually enable and disable in every file is annoying and problematic. If you forget to do this in even one file, it might trigger expensive loading of dependencies that kinda defeats the whole purpose of doing this.

There should be an alternative API so you can configure a glob pattern or subdirectory of code that will have laziness applied automatically. So you can call automaticallyLazy(__dirname) once in your entrypoint and then all files in your module's src directory will have lazy imports.

The existing lazy-imports/{enable,disable} API should be modified for compatibility:

import 'lazy-imports/enable'; forces lazyness, ignoring whatever you may have configured via automaticallyLazy import 'lazy-imports/disable'; force lazyness to be disabled, ignoring whatever you may have configured via automaticallyLazy require('lazy-imports/auto'); goes back to automatic behavior, so that automaticallyLazy behavior is followed.