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

babel-plugin-import-redirect

v1.1.1

Published

Import, export, require path redirect plugin for Babel

Downloads

4,265

Readme

babel-plugin-import-redirect

Build Status npm version Commitizen friendly dependencies Status devDependencies Greenkeeper badge codecov license

A Babel plugin that allows to point import, export from declarations, require() and simple dynamic import() (only string literal as its argument) calls to custom paths. This can be especially useful in testing — for swapping regular production and development files and modules with their mock implementations.

For example, this plugin allows to transform:

import "./path/to/file";
export {variable} from "./path/to/different/file";
require("module");
import("different_module");

to

import "./mocks/mockFile";
export {variable} from "./mocks/differentMockFile";
require("./mocks/mockModule");
import("yet_another_module");

Usage

Install the plugin with

npm install --save-dev babel-plugin-import-redirect

Then add it to your babel configuration (e.g. in .babelrc). A rather exhaustive setup may look like this:

{
  "plugins": [
    "syntax-dynamic-import",
    ["import-redirect",
    {
      "root": "./tests/mocks",
      "extraFunctions": ["custom_require_function", "SystemJS.import"],
      "promisifyReplacementFor": "SystemJS.import",
      "redirect": {
        "connect": "./connect.mocked",
        "path/to/(\\w+)\\.js$": "./$1.mocked",
        "\\.css$" : false,
        "path/to/globals": {"MY_GLOBAL_1": true, "MY_GLOBAL_2": 42}
      }
    }]
  ]
}

Transforming dynamic import() requires that babel-plugin-syntax-dynamic-import be included in plugins before import-redirect

Now when you transpile your source files, any path inside import, export from declarations, require() and dynamic import() calls that matches a redirect.key is resolved to point to the file from a corresponding redirect.value.

Example

To provide an example, given a project structure of

./
  node_modules/
    connect/
  tests/
    mocks/
      connect.mocked.js
      lib.mocked.js
  src/
    index.js
    helpers/
      globals.js
    libs/
      lib.js
    style.css
  .babelrc

with index.js of

import "./style.css";
import connect from "connect";
export {default as libFunction} from "./helpers/lib";
import {MY_GLOBAL_1, MY_GLOBAL_2} from "./helpers/globals";
// ...

and .babelrc of

{
  "plugins": [
    ["import-redirect",
    {
      "root": "./tests/mocks",
      "redirect": {
        "connect": "./connect.mocked",
        "/libs/(\\w+)\\.js$": "./$1.mocked",
        "\\.css$" : false,
        "helpers/globals.js$": {"MY_GLOBAL_1": true, "MY_GLOBAL_2": 42}
      }
    }]
  ]
}

The index.js will transpile to

import connect from "../tests/mocks/connect.mocked";
export {default as libFunction} "../tests/mocks/lib.mocked";
const {MY_GLOBAL_1, MY_GLOBAL_2} = {"MY_GLOBAL_1": true, "MY_GLOBAL_2": 42};
// ...

The transpilation to make it happen will be performed as follows:

  1. import "./style.css";``
    1. ./style.css path is resolved to project/src/style.css absolute path
    2. project/src/style.css is matched against new RegExp("\\.css$")
    3. the corresponding value of false triggers removal of the import declaration

removed

  1. import connect from "connect";
    1. connect path is resolved to project/node_modules/connect/... absolute path
    2. the path matches against new RegExp("connect")
    3. the redirected path of ./test/mocks/connect.mocked is resolved relative to index.js as ../tests/mocks/connect.mocked
    4. the path is changed to ../tests/mocks/connect.mocked

replaced with import connect from "../tests/mocks/connect.mocked";

  1. import libFunction from "./helpers/lib";
    1. ./helpers/lib path is resolved to project/node_modules/helpers/lib.js absolute path
    2. the path matches against new RegExp("/libs/(\\w+)\\.js$")
    3. as the redirect value contains a replacement group ($1), it is converted to ./tests/mocks/lib.mocked
    4. the redirected path of ./tests/mocks/lib.mocked is resolved relative to index.js as ../tests/mocks/lib.mocked
    5. the path is changed to ../tests/mocks/lib.mocked

replaced with import libFunction from "../tests/mocks/lib.mocked";

  1. import {MY_GLOBAL_1, MY_GLOBAL_2} from "./helpers/globals";
    1. ./helpers/globals path is resolved to project/src/helpers/globals.js absolute path
    2. project/src/helpers/globals.js matches against new RegExp("helpers/globals.js$")
    3. the corresponding value of an object triggers replacement of the import declaration with a variable declaration

replaced with const {MY_GLOBAL_1, MY_GLOBAL_2} = {"MY_GLOBAL_1": true, "MY_GLOBAL_2": 42};

Options

{
  "root": String,
  "extraFunctions": String | Array<String>,
  "promisifyReplacementFor": String | Array<String>,
  "redirect": {
    matchPattern: replacement
  },
  "extensions": Array<String>,
  "suppressResolveWarning": Boolean
}
  • root : path, relative to which replacement paths are resolved. Equals project root folder by default.
  • extraFunctions : functions to consider when matching against keys in redirect in addition to import, export from declarations, require() and dynamic import(). It can be a simple function name ("custom_require") or an object.property pair ("SystemJS.import").
  • promisifyReplacementFor : functions, in addition to import(), for which replacement Objects should be wrapped in Promise.resolve().
  • redirect : Object with matchPattern keys and replacement values.
  • extensions: Array of extensions to use for resolving filenames. Equals [".js", ".jsx", ".es", "es6"] by default, providing custom extensions will override the default.
  • suppressResolveWarning: Boolean, false by default. During path resolution plugin shows a warning when it can't find a module. It will still do its best to resolve to the right path. This option suppresses that warning.

matchPattern

A String to be used as a pattern in a RegExp. This RegExp will be matched against the source of import and export from declarations and the first argument of require(), import() and functions from extraFunctions. If the match is successful the whole expression will be transformed depending on the corresponding replacement.

Take care to escape (\) every special character, namely backslash (\). That is, escape twice every time you would escape once in a literal regexp. E.g. a RegExp constructed from "\\w+" pattern is equivalent to /\w+/, to use backslash in your pattern escape it like so "\\\\".

To match only the node module required_module and not accidentally pick up paths that would otherwise match /required_module/ (e.g. "./src/my_required_module/index.js"), it is recommended to specialize the pattern like this: "/node_modules/required_module/".

replacement

Can be

  • A String path to a file to be used in place of the originally required / imported file. The path will be resolved relative to root if provided or to project root folder (process.cwd()) otherwise. If replacement contains a replacement group (e.g. $1), a corresponding parenthesized match result from the matchPattern will be substituted in prior to resolving the path. E.g. given a project structure of
./
  src/
    index.js
    lib.js
  mocks/
    lib.js

require("./lib"); inside ./src/index.js file when matched against "/(\\w+).js": "./mocks/$1" with no root provided will transpile to require("../mocks/lib");.

  • false, which will result in removal of simple import declarations, require(), import() and custom require function calls without side effects. That is, functions which are not part of a larger expression:
// will be removed
require("path/to/file");
import("path/to/file");

// won't be removed
const lib = require("path/to/file");
require("path/to/file").prop;
fn(require("path/to/file"));
import("path/to/file").then(module => module.default);

and simple, non-named, non-namespace, non-default import statements:

// will be removed
import "path/to/file";

// won't be removed
import lib from "pat/to/file";
import * as lib from "pat/to/file";
import {lib} from "pat/to/file";
  • An Object, which will result in removal of simple import declarations, require(), import() and custom require function calls without side effects (same as for false) and in replacement of default, named, namespace imports, require(), import() and custom require function calls with these objects. This Object must be JSON-serialazable. Additionally replacement objects for import() calls and calls of custom functions from promisifyReplacementFor will be wrapped in Promise.resolve().

E.g. for a "path/to/file": {"key": val} matchPattern - replacement pair

| will be removed | was removed |:---------------------------------------------------------|:-| | import "path/to/file"; | | | require("path/to/file"); | | | import("path/to/file"); | | | will be replaced | was replaced with | const lib = require("path/to/file"); | const lib = {"key": val}; | require("path/to/file").prop; | ({"key": val}).prop; | fn(require("path/to/file")); | fn({"key": val}); | import("path/to/file").then(module => module.default); | Promise.resolve({"key": val}).then(module => module.default); | import lib from "pat/to/file"; | const {default: lib} = {"key": val}; | import * as lib from "pat/to/file"; | const lib = {"key": val}; | import {lib} from "pat/to/file"; | const {lib} = {"key": val}; | import lib, {lib1 as lib2} from "./style.css"; | const {default: lib, lib1: lib2} = {"key": val}; | import lib, * as libAll from "./style.css"; | const libAll = {"key": val}, {default: lib} = libAll;

To summarize,

  • a String replacement handles import, export from declarations, require(), simple dynamic import() and custom function calls.
  • false replacement removes aforementioned declarations and function calls, except for export from, without side effects.
  • Object replacement does the same as false and also replaces relevant expressions with side effects.