npm-specifier-loader
Version:
Node.js module loader enabling support for npm specifier imports
86 lines (59 loc) • 3.42 kB
Markdown
# npm-specifier-loader
Node.js ["experimental" module loader](https://nodejs.org/api/esm.html#loaders) enabling support for npm specifier imports.
This is inspired by the [similar feature announced for Deno](https://deno.com/blog/changes#compatibility-with-node-and-npm),
and is a proof of concept providing the same functionality in Node.js.
Using this module loader, you can write code like the following and execute it in Node.js:
```js
import express from "npm:express@4";
const app = express();
const port = 3000;
app.get("/", (req, res) => {
res.send("Hello World!");
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
```
See the `demos` folder in the repository for other examples of the syntax.
Demos can be ran from the repository checkout as follows:
```
npm run demo -- ./demos/express.mjs
```
## Setup
Requires Node 16+.
Node needs to be invoked with a couple special command line flags in order to use this module loader.
- `--experimental-loader /path/to/npm-specifier-loader.mjs`
- To configure use of the loader.
- `--experimental-import-meta-resolve`
- To enable an experimental API that the loader relies on.
There are a few ways you could go about supplying these command line args.
For example, if you want this to work at the system level for any script, the following works:
```bash
# Install the loader globally.
npm install -g npm-specifier-loader
# Set or update the NODE_OPTIONS environment variable so all invocations of node use the loader.
# The way to do this varies based on your operating system / shell.
export NODE_OPTIONS=--experimental-import-meta-resolve --experimental-loader npm-specifier-loader
# Run scripts anywhere!
node ./my-script.mjs
```
If you want to only use the loader in certain circumstances, you can `npm install` it into a local location
and explicitly pass the flags to node.
```
node --experimental-import-meta-resolve --experimental-loader ./path/to/npm-specifier-loader.mjs ./my-script.mjs
```
## Configuration
The loader works by installing npm packages on the fly as they are needed.
By default, the packages are downloaded into the `~/.npm-specifier-cache` home directory folder.
To customize this location, set the full path of a different directory to the `NPM_SPECIFIER_LOADER_CACHE_PATH` environment variable.
By default, the loader invokes `npm install` assuming `npm` is available in the system path.
To customize which `npm` to use, set the `NPM_SPECIFIER_LOADER_NPM_PATH` environment variable to the full path where npm is found.
## Caveats
- This is an _experimental_ package, since the module loaders API in Node itself is experimental.
- The loader is not guaranteed to be thread safe across multiple instances of Node.
- Multiple instances of Node could attempt to install packages into the cache directory at the same time. This could be mitigated by isolating the cache directory used by each process.
- Each time you start node and import a given npm specifier, `npm install` will be performed.
With the local file cache, this should not take too long for subsequent runs, but it still
involves a process execution. This approach is done to ensure that the npm package requested
is always up to date.
- If you ask for `express@5` for example, you'll always get the latest patch version for `express` v5, regardless of the cache folder contents at the time of startup.