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

require-falafel

v1.0.13

Published

Use falafel to rewrite require'd modules in node.

Downloads

5

Readme

Require-Falafel

Node.js CI FOSSA Status

Use falafel to rewrite require'd modules in node.

Hook into node's require command to rewrite the module's AST (in memory) before loading.

Author: Olli Jones
License: MIT
npm install require-falafel --save

Introduction

Falafel uses Acorn to transform a JavaScript AST. Require-falafel hooks into node's require method in order to transform the AST of modules as they're loaded.

For example, if we have a library "lib-7" which makes web requests with an unhelpful user-agent string:

const fetch = require("node-fetch");
module.exports = {
  get: function() {
    fetch("https://www.example.com", {
      headers: { "User-Agent": "lib-7" },
    })
  }
}

This code snippet contains lots of AST nodes including 4 Literals. We can see these Literal nodes will be:

{
  "type": "Literal",
  "value": "node-fetch"
}
{
  "type": "Literal",
  "value": "https://www.example.com"
}
{
  "type": "Literal",
  "value": "User-Agent"
}
{
  "type": "Literal",
  "value": "lib-7"
}

Falafel provides node.source() and node.update(s) methods, so if we wanted to replace the "lib-7" literal, to provide a better user-agent string for tracking calls to the API from our new client, we can write a transform method like:

const transform = function (node) {
  // only change the right literal:
  if (node.type == "Literal" && node.value == "lib-7") {
    // node.source() will be "lib-7"
    let source = node.source();
    // we can update the source code (this is quoted JavaScript):
    source = `${source} + "-github.com/ojj11/require-falafel"`;
    // then we can update the AST node:
    node.update(source);
  }
}

We can use this method along with RequireFalafel.INCLUDE_NODE_MODULES, to make an instance of RequireFalafel that we can apply to a block of code that includes the require statements for lib-7 that we want to transform:

// wrap our code with a transformation before requiring the library:
const RequireFalafel = require("require-falafel");

const requireFalafel = new RequireFalafel(
  RequireFalafel.INCLUDE_NODE_MODULES,
  transform);

requireFalafel.applyForBlock(function() {

  // require-ing inside .applyForBlock will swap the internals of require to
  // apply falafel as the library is loaded:
  const lib7 = require("lib-7");

  // calling the library will use "lib-7-github.com/ojj11/require-falafel" as the
  // user-agent now.
  lib7.get();

});

Whilst this example is contrived, it is hopefully relatively straight-forward to see how this library could be used to instrument code as it's loaded in a test pass, or to enable certain developer flags in a development or staging environment.

API documentation

Load require-falafel:

const RequireFalafel = require("require-falafel");

new RequireFalafel(typeOfReplacement, transformer)

Creates a new transformation for require methods, given a typeOfReplacement and transform method, for example:

const requireFalafel = new RequireFalafel(
  RequireFalafel.INCLUDE_NODE_MODULES,
  function (node) {
    if (node.type == "Literal" && node.value == "lib-7") {
      let source = node.source();
      source = `${source} + "-github.com/ojj11/require-falafel"`;
      node.update(source);
    }
  });

typeOfReplacement should be one of:

  • ['/absolute/paths/to/files.js', require.resolve('module-names')] will transform only the absolute paths specified in an array. Use require.resolve to get the absolute paths of libraries.
  • RequireFalafel.INCLUDE_NO_NODE_MODULES, will transform ./ and ../ imports, but will not transform any npm modules in node_modules folders. Only available in node v11+.
  • RequireFalafel.INCLUDE_FIRST_LEVEL_NODE_MODULES same as above, but will transform only the top level of node_modules that are imported from ./ or ../ code. Only available in node v11+.
  • RequireFalafel.INCLUDE_NODE_MODULES the most liberal, will transform all require calls, even those inside node_modules

requireFalafel.applyForBlock(block)

Runs the given block, replacing require calls to load code transformed through the falafel transformer given on construction.

At the end of the block, resets the require method and clears any loaded modules from node's cache, so that a fresh require will get the correct module.

For example:

requireFalafel.applyForBlock(function() {
  const module2 = require("module2");
  // module2 will be transformed and loaded
});

const module2 = require("module2");
// module2 will be re-loaded, but not transformed because it's outside of the
// block

This method will work async functions, but the require hook will continue to apply until await is called:

// always immediately await:
await requireFalafel.applyForBlock(async function() {
  const module2 = require("module2");
  // module2 will be transformed and loaded
});

const module2 = require("module2");
// module2 will be re-loaded, but not transformed because `await` has already
// been called on `applyForBlock`

requireFalafel.replaceRequire()

For cases where supplying a block won't work, use replaceRequire, like so:

requireFalafel.replaceRequire();
const transformedModule2 = require("module2");
// module2 will be transformed and loaded

requireFalafel.restoreRequire();
const untransformedModule2 = require("module2");
// module2 will be re-loaded, but not transformed because we restored the
// require method

requireFalafel.restoreRequire()

Opposite of requireFalafel.replaceRequire() - restores the normal operation of require.