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

@harves/nx-node-esm-plugin

v0.2.1

Published

Node executor including ESM module resolution for buildable libraries within Nx workspaces.

Downloads

8

Readme

Node Executor for Nx with ESM support

Node executor including ESM module resolution for buildable libraries within Nx workspaces.

Why this plugin?

Nx allows you to easily add structure to your workspace.

For JavaScript/TypeScript projects this includes a clean structure, DX and tooling for developing multiple applications and libraries:

  • Build. When compiling code that references buildable libraries within the workspace, @nx/js:tsc automatically generates temporary tsconfig's that link the code being compiled and the libraries referenced (imported/required).
  • Execute. When running code during development (within the workspace prior to deployment/release/publication), the @nx/js:node executor includes support for requireing CommonJS code from libraries referenced from other buildable libraries within the workspace.

[!WARNING] However, this currently works for CommonJS applications ("type": "commonjs" in package.json) but not for ESM applications ("type": "module").

Errors look something like this:

Error: Cannot find package '@my-scope/my-lib' imported from /Users/daniel/projects/test/dist/apps/test-app/src/lib/test-app.js

Nx will probably address this in the future - it's discussed at least here, and here - but for today this plugin seeks to provide a close to drop-in replacememt.

Getting started

The nx-node-esm-plugin plugin includes a sample application and a preset to enable you to try it easily:

nx-node-esm-plugin demo

View demo screencast.

Using the preset

# Create Nx workspace with preset sample app
npx create-nx-workspace test --preset=@harves/nx-node-esm-plugin

# Take a look at the sampleapp
cd test

# Run the standard Node executor (fails)
npx nx run test-app:run-js-node

# Run using the nx-node-esm-plugin executor
npx nx run test-app:run-node-esm-plugin

Adding a sample app to an existing workspace

# Add plugin
npx nx add @harves/nx-node-esm-plugin

# Use code generator to add the sample library + application
npx nx g @harves/nx-node-esm-plugin:sample-app test

# View sample app project details
npx nx show project test-app --web

# Run the standard Node executor (fails)
npx nx run test-app:run-js-node

# Run using the nx-node-esm-plugin executor
npx nx run test-app:run-node-esm-plugin

The nx-node-esm-plugin:node executor

A quickstart guide to using the node executor in this plugin:

From this project.json:

  "targets": {
    "serve": {
      "executor": "@nx/js:node",
      "dependsOn": ["build"],
      "options": {
        "buildTarget": "build",
        "watch": false
      }
    }
  }

To this:

  "targets": {
    "serve": {
      "executor": "@harves/nx-node-esm-plugin:node",
      "dependsOn": ["build"],
      "options": {
        "buildTarget": "build"
      }
    }
  }

(*) The nx-node-esm-plugin:node executor in this plugin does not support file watch mode.

Node Loader Details

The resolver and loader function provided with this plugin includes support for module resolution for ESM and require support for CommonJS (equivalent to the existing Nx Node executor).

This plugin requires at least Node v18.19.0, when the module.register() API used to customise module resolution for ESM was added.

Module Resolution for ESM

This plugin resolves Node ESM import specifiers for buildable Nx libraries by mapping the library specifiers to the library's built output paths.

It also includes support for configurable overrides.

All other specifiers are deferred to the parent resolver.

The resolution algorithm works as follows (based on the Node specification):

  1. Assumes that the mapped Nx library output paths contain a valid package.json.

  2. Attempts to resolve the library imports for mapped libraries using the Node's ESM Module resolution algorithm, with the assumption that all Nx library specifiers are "bare specifiers".

  3. Attempts to resolve using the package.json exports property using the resolve-pkg-maps package.

  4. Falls back to attempting resolution using the package.json main property using Node's legacy CommonJS resolution algorithm.

The legacy CommonJS main resolution is as follows:

  1. let M = pkg_url + (json main field)
  2. TRY(M, M.js, M.json, M.node)
  3. TRY(M/index.js, M/index.json, M/index.node)
  4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node)
  5. NOT_FOUND

References:

Require Loader for CommonJS

This plugin resolves Node CommonJS require's for buildable Nx libraries by mapping the library require request to the library's built output paths.

It also includes support for configurable overrides.

All other request values are deferred to the parent loader.

Executor Documentation

The @harves/nx-node-esm-plugin:node executor in this plugin functions very similarly to the @nx/js:node that is provided by Nx.

The basic operation of the executor:

  1. Utilise the provided buildTarget and create a task graph (**) from which the build dependencies may be computed.

  2. For these dependencies, assemble mappings from the library specifiers (e.g. @my-scope/my-lib) to the build output directory (e.g. dist/libs/my-lib).

  3. Invoke the selected Node file with module resolution and require loaders customised to utilise these mappings.

Use the --verbose flag or NX_VERBOSE_LOGGING environment variable when running Nx to see logs of the mappings and the module resolution / loader activity.

(**) The task graph algorithm is based on a more recent Nx changes enabled by the NX_BUILDABLE_LIBRARIES_TASK_GRAPH environment variable (not required to be set for this plugin) - see here, here, and here.

The full executor schema may be found in libs/nx-node-esm-plugin/src/executors/node/schema.json.

Executor Options

The available options are as follows:

buildTarget

string The target to run to build you the app.

buildTargetOptions

object Additional options to pass into the build target.

fileToRunMode

string; enum ("packageJson", "fromBuildTarget", "specified") Mode specifying how the Node file to run is determined; either from the package.json of the build target, inferred from the build target or specified explicitly.

fileToRun

string Optional specification of the Node file to run (if present this setting overrides fileToRunMode).

args

array [string] Arguments passed to the Node script.

moduleResolutionOverrides

object Optional ESM module resolution overrides; key is the specifier, value if the full absolute path of the file to load. e.g.

{
  "moduleResolutionOverrides": {
    "@my-scope/my-lib": "/Users/daniel/project-name/libs/some-dir"
  }
}

color

boolean (default false) Use colors when showing output of command.

cwd

string Current working directory of the commands. If it's not specified the commands will run in the workspace root, if a relative path is specified the commands will run in that path relative to the workspace root and if it's an absolute path the commands will run in that path.

env

object Environment variables that will be made available to the commands. This property has priority over the .env files.

{
  "env": {
    "SOME_ENV_VAR": "true"
  }
}

envFile

string You may specify a custom .env file path.

__unparsed__

array [string] Additional arguments added to args and passed to the Node script. Allows command line args to be passed to the script by the executor.

Changelog

Learn about the latest changes.

Contributing

Read about contributing to this project. Please report issues on GitHub.

Credits

This workspace has been generated by Nx, Smart Monorepos · Fast CI.

Rather than recreating from scratch, much of the code in this plugin is taken from Nx. Links to the relevant Code in the Nx GitHub repo are included.