This package provides a variety of loaders to facilitate a quick and easy local development and CI testing environment.
--loader=nodejs-loaders/dev/alias \
--loader=nodejs-loaders/dev/tsx \
--loader=nodejs-loaders/dev/svgx \
--loader=nodejs-loaders/dev/mismatched-format
Sequence here is important (you want to correct a mismatched package format before you try to use it, and SVGX is a form of JSX, so it needs TSX loader to finish the job).
This loader supports 2 options, both of which follow TypeScript's paths
; if you're using TypeScript, this loader handles the (important) half of work TypeScript ignores. It checks for tsconfig.json
in the project root (the current working directory) and builds aliases from compilerOptions.paths
if it exists.
If you're not using TypeScript (or you're not using compilerOptions.paths
¹), you can specify aliases in package.json
in the project root (the current working directory) in the same way compilerOptions.paths
are defined:
{
"aliases": {
"…/*": "./src/*",
"CONF": "./config.json"
}
}
¹ Note that if you are using aliases and do not set up compilerOptions.paths
, TypeScript will make your life hell.
This is commonly used to reference the project root; common prefixes are @/
(or some variation like @app/
) and …/
: import foo from '…/app/foo.mts;
→ ${project_root}/src/app/foo.mts
.
Tip
Due to package namespacing (aka "scopes") it may be best to avoid using the "at" symbol (@
) since that could lead to confusion over what is a package and what is an alias (especially if you eventually add a package named with the alias you're using).
Important
When configuring these aliases, ensure astrisks (*
) are used correctly; configuring this for TypeScript can be extremely confusing. See Why are these tsconfig paths not working? for some of the litany of ways configuration can fail.
This is a static specifier similar to a bare module specifier: foo
→ ${project_root}/src/app/foo.mts
. This may be useful when you have a commonly referenced file like config (which may conditionally not even live on the same filesystem): import CONF from 'conf';
→ ${project_root}/config.json
.
Many packages are incorrectly configured, claiming to be ESM yet not actually surfacing ESM. This is most commonly due to a package.json
using the non-standard "module"
field:
{
"name": "mismatched-example",
"type": "module",
"main": "./dist/cjs.js",
"module": "./dist/esm.js"
}
mismatched-example
has told node its main entry point is ./dist/cjs.js
and that it is ESM. Therefore, trying to import this package will (likely) explode in a SyntaxError
as node loads ./dist/cjs.js
as ESM (instead of the CJS it actually is).
This loader detects the explosion and re-instructs node to ignore the misconfiguration and instead load ./dist/cjs.js
as CJS (the loader doesn't try to find a potential ESM main entry point the package may have—there are too many options, several of which are non-standard).
Note to package authors reading this: The simplest fix here is to distribute only CJS. See Configuring CommonJS & ES Modules for Node.js for a thorough explanation of options.
Important
Node.js now has experimental support that better handles this via --experimental-detect-module
. This loader may be re-purposed to address the root of the problem instead: that mismatched-example
's configuration is wrong.
This loader checks for a esbuild.config.mjs
in the project root (if you want to keep it elsewhere, consider a symlink in the project root pointing to its actual location); only options for esbuild's "transform" API are valid (esbuild handles looking for a tsconfig). When none is found, it uses a few necessary default.
This loader does not handle TypeScript's file extension nonsense. Import specifiers must use the actual file extension of the file actually on disk:
./
├ …
└ foo.ts
💥 import foo from './foo.js';
✅ import foo from './foo.ts';
Supported file extensions
.jsx
.mts
.ts
.tsx
--loader=nodejs-loaders/testing/css-module \
--loader=nodejs-loaders/testing/media \
--loader=nodejs-loaders/testing/text
Sequence here is not important.
This loads the module as a plain-object of simple key-value pairs of the css specifiers like:
/* main.module.css */
#Bar { font-weight: bold }
.Foo {
text-decoration: none
.Baz { color: red }
}
.Qux .Zed { font-size: 1.1em }
import styles from 'main.module.css';
styles.Bar; // 'Bar'
styles.Baz; // 'Baz'
styles.Foo; // 'Foo'
styles.Zed; // 'Zed'
This ensures snapshots are unaffected by unrelated changes.
Warning
This loader does not differentiate classes vs ids; thus duplicate names can create a last-wins conflict. For example #Foo
and .Foo
will result in just Foo: 'Foo'
. This is unlikely to cause any real-world problems (and you probably shouldn't be doing this anyway).
This loader returns the specifier (truncated from project root / current working directory) as the default export:
import photo from './team.jpg'; // photo = '[…]/team.jpg'
This ensures snapshots are unaffected by the file system on which the test is run.
Supported file extensions
Audio/Video:
.av1
.mp3
.mp3
.mp4
.ogg
.webm
Images:
.avif
.gif
.ico
.jpeg
.jpg
.png
.webp
This loader handles files that are effectively plain text.
Supported file extensions
.graphql
.gql
.md
.txt