bare-module
Module support for JavaScript
v7.0.3bare-module — Module support for JavaScript. It is a native addon and requires Bare >=1.32.0.
Version 7 is a breaking change from the 6.x line this page previously documented. Loader configuration (cache, protocol, conditions, builtins, and a new concurrency limit) moved off Module instances onto a new ModuleLoader, which exposes .import()/.link() (plus Sync forms) as the primary entry points. ModuleProtocol dropped its preresolve/postresolve/addon/asset hooks in favor of a leaner resolve/read/exists/list surface, each with a Sync counterpart. See the upstream repo for full migration notes.
npm i bare-moduleUsage
A module is loaded by its WHATWG URL. The source may be read through the module's protocol or passed in directly:
const Module = require('bare-module')
// Load a module directly from source, without it existing on disk.
const foo = await Module.load(
new URL('file:///foo.js'),
'module.exports = function add (a, b) { return a + b }'
)
foo.exports(2, 3)
// 5To resolve and load specifiers relative to a directory, as require() does, create a require() bound to a parent URL. The default protocol has no backing store of its own and cannot read from the file system, so pass a protocol that serves the source:
const Module = require('bare-module')
const require = Module.createRequire('file:///directory/', { protocol })
// Resolves and loads `file:///directory/foo.js`, reading it through `protocol`.
const foo = require('./foo.js')The same machinery backs the require() and import available to modules as they run; see CommonJS modules and ECMAScript modules for what each exposes.
API
Module
new Module(url: URL)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
url | URL | — | The WHATWG URL identifying the module. |
dirname: string
The directory portion of module.url.
exports: unknown
The exports from the module.
filename: string
The file portion of module.url.
id: string
Module.Condition
type Condition = 'require' | 'import' | 'asset' | 'addon'The import condition a specifier is resolved for.
Module.constants
Module.constants: {
SCRIPT: number
MODULE: number
JSON: number
BUNDLE: number
ADDON: number
BINARY: number
TEXT: number
}Constants describing module types (SCRIPT, MODULE, JSON, BUNDLE, ADDON, BINARY, TEXT).
Module.createRequire(parentURL: string | URL, opts?: CreateRequireOptions): Require
Create a preconfigured require() bound to parentURL, so specifiers resolve and load relative to it.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
parentURL | string | URL | — | The parent URL that the returned require() resolves and loads specifiers relative to. |
opts? | CreateRequireOptions | — | Options for the created require(), such as its protocol and cache. |
Returns Require — A require() bound to parentURL, with main, cache, resolve, addon, and asset attached.
Throws
TypeError—parentURLis neither a string nor a WHATWGURL, and noreferrerwas given.
Module.load(url: URL, opts: LoadOptions): Promise<Module>
Load a module with the provided url. url is a WHATWG URL. If provided, the source will be passed to the matching extension for the url.
Overloads:
Module.load(url: URL, opts: LoadOptions): Promise<Module>
Module.load(url: URL, source?: Buffer | string | null, opts?: LoadOptions): Promise<Module>Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
url | URL | — | The WHATWG URL of the module to load. |
opts | LoadOptions | — | Load options; may carry a source to load directly instead of reading it through the protocol. |
Returns Promise<Module> — The loaded Module, reusing the cached instance if url was already loaded.
Throws
TYPE_INCOMPATIBLE— a module is already cached forurlwith a type incompatible with the requestedtype.
Module.loadSync(url: URL, opts: LoadOptions): Module
As load(), but synchronous, for a caller that cannot await one. The protocol is driven through its *Sync methods and so must answer synchronously. A module with a top-level await is returned as soon as its evaluation is started rather than once it has finished, as there is nothing to wait on it here.
Overloads:
Module.loadSync(url: URL, opts: LoadOptions): Module
Module.loadSync(url: URL, source?: Buffer | string | null, opts?: LoadOptions): ModuleParameters
| Parameter | Type | Default | Description |
|---|---|---|---|
url | URL | — | The WHATWG URL of the module to load. |
opts | LoadOptions | — | Load options; may carry a source to load directly instead of reading it through the protocol. |
Returns Module — The loaded Module, reusing the cached instance if url was already loaded.
Throws
UNEXPECTED_PROMISE— the protocol answered asynchronously.TYPE_INCOMPATIBLE— a module is already cached forurlwith a type incompatible with the requestedtype.
Module.resolve(specifier: string, parentURL: URL, opts?: ResolveOptions): Promise<URL>
Resolve the module specifier relative to the parentURL. specifier is a string and parentURL is a WHATWG URL. condition is an optional import condition, defaulting to 'require'; pass 'asset' to resolve an asset rather than a module.
Overloads:
Module.resolve(specifier: string, parentURL: URL, opts?: ResolveOptions): Promise<URL>
Module.resolve(specifier: string, parentURL: URL, condition: Condition, opts?: ResolveOptions): Promise<URL>Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
specifier | string | — | The module specifier to resolve. |
parentURL | URL | — | The WHATWG URL to resolve specifier relative to. |
opts? | ResolveOptions | — | Resolution options. |
Returns Promise<URL> — The WHATWG URL that specifier resolves to.
Throws
MODULE_NOT_FOUND— no module matchingspecifiercould be found relative toparentURL.ASSET_NOT_FOUND— the'asset'condition was used and no matching asset could be found.ADDON_NOT_FOUND— the'addon'condition was used and no matching addon could be found.TypeError—specifieris not a string,parentURLis not a WHATWGURL, orconditionis not a known condition.
Module.resolveSync(specifier: string, parentURL: URL, opts?: ResolveOptions): URL
As resolve(), but synchronous, for a caller that cannot await one. The protocol is driven through its *Sync methods and so must answer synchronously.
Overloads:
Module.resolveSync(specifier: string, parentURL: URL, opts?: ResolveOptions): URL
Module.resolveSync(specifier: string, parentURL: URL, condition: Condition, opts?: ResolveOptions): URLParameters
| Parameter | Type | Default | Description |
|---|---|---|---|
specifier | string | — | The module specifier to resolve. |
parentURL | URL | — | The WHATWG URL to resolve specifier relative to. |
opts? | ResolveOptions | — | Resolution options. |
Returns URL — The WHATWG URL that specifier resolves to.
Throws
UNEXPECTED_PROMISE— the protocol answered asynchronously.MODULE_NOT_FOUND— no module matchingspecifiercould be found relative toparentURL.TypeError—specifieris not a string,parentURLis not a WHATWGURL, orconditionis not a known condition.
path: string
Module.protocol: Protocol
The ModuleProtocol class for resolving, reading and loading modules. See Protocols for usage.
url: URL
The WHATWG URL identifier of the module.
ModuleLoader
Centralizes the configuration a graph of modules loads under — cache, protocol, conditions, builtins, resolutions, and a new concurrency limit — instead of it being threaded through every Module.load()/.resolve() call individually. .import() and .link() (plus their Sync forms) are its primary entry points.
Exposed as Module.Loader on the module's default export, or importable directly from the bare-module/loader subpath.
new ModuleLoader(opts?: Options)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
opts? | Options | — | — |
builtins: Builtins
A map of builtin module specifiers mapped to the loaded module.
cache: Cache
The cache of loaded modules that the loader was created with, shared with every module of its graph.
concurrency: number
The maximum number of module reads to perform concurrently while linking. 0 applies no limit.
conditions: Conditions
An array of conditions used to resolve dependencies while loading the module. See Conditional exports for possible values.
defaultType: number
The assumed type of a module without a type using an ambiguous extension, such as .js. See Module.constants for possible values.
get(url: URL): Module | null
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
url | URL | — | — |
import(entry: URL, opts?: ImportOptions): Promise<unknown>
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
entry | URL | — | — |
opts? | ImportOptions | — | — |
importSync(entry: URL, opts?: ImportOptions): unknown
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
entry | URL | — | — |
opts? | ImportOptions | — | — |
imports: ImportsMap
The import map when the module was loaded.
link(entry: URL, source?: Buffer | string | null, opts?: LinkOptions): Promise<Module>
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
entry | URL | — | — |
source? | Buffer | string | null | — | — |
opts? | LinkOptions | — | — |
linkSync(entry: URL, source?: Buffer | string | null, opts?: LinkOptions): Module
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
entry | URL | — | — |
source? | Buffer | string | null | — | — |
opts? | LinkOptions | — | — |
main: Module
The module representing the entry script where the program was launched.
protocol: Protocol
The ModuleProtocol modules are resolved and read through, shared with every module of the loader's graph.
resolutions: ResolutionsMap
A map of preresolved imports with keys being serialized parent URLs and values being "imports" maps.
ModuleProtocol
Exposed as Module.Protocol on the module's default export, or importable directly from the bare-module/protocol subpath.
new ModuleProtocol(methods?: Partial<ModuleProtocol>, context?: ModuleProtocol)
Defines how modules are resolved, read and loaded; custom protocols can serve modules from outside the file system, such as a Hyperdrive or a bare-bundle.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
methods? | Partial<ModuleProtocol> | — | Protocol method overrides; any of resolve, resolveSync, exists, existsSync, read, readSync, list, or listSync. |
context? | ModuleProtocol | — | An existing protocol to fall back to for any method not provided in methods. |
exists(url: URL): boolean | Promise<boolean>
Return whether the URL exists.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
url | URL | — | The URL to check for existence. |
Returns boolean | Promise<boolean> — Whether url exists. The default implementation returns false.
existsSync(url: URL): boolean
Synchronous form of exists().
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
url | URL | — | The URL to check for existence. |
extend(methods: Partial<ModuleProtocol>): ModuleProtocol
Create a new protocol that uses this protocol as its context, overriding the given methods.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
methods | Partial<ModuleProtocol> | — | Protocol method overrides for the new protocol. |
Returns ModuleProtocol — A new ModuleProtocol that uses this protocol as its context, with methods overriding.
list(url: URL): Iterable<URL> | AsyncIterable<URL>
List the entries of a directory URL.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
url | URL | — | The directory URL to list. |
listSync(url: URL): Iterable<URL>
Synchronous form of list().
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
url | URL | — | The directory URL to list. |
ModuleProtocol.isProtocol(value: unknown): boolean
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
value | unknown | — | The value to test. |
Returns boolean — Whether value is a protocol of the same version as this one, whichever copy of bare-module created it.
read(url: URL): Buffer | string | null | Promise<Buffer | string | null>
Return the source code of a URL, represented as a string or buffer.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
url | URL | — | The URL to read. |
Returns Buffer | string | null | Promise<Buffer | string | null> — The source of url as a Buffer or string, or null if it does not exist.
readSync(url: URL): Buffer | string | null
Synchronous form of read().
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
url | URL | — | The URL to read. |
resolve(url: URL): URL | Promise<URL>
Resolve a module URL to the URL that should be linked. The default implementation returns url unchanged.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
url | URL | — | The URL to resolve. |
Returns URL | Promise<URL> — The resolved URL. A promise must not be returned during synchronous linking.
resolveSync(url: URL): URL
Synchronous form of resolve().
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
url | URL | — | The URL to resolve. |
Types
Attributes
interface Attributes {
type: Lowercase<keyof typeof constants>
}Import attributes instructing how a module should be loaded. A type that is not one of the known strings is turned down rather than passed over.
Cache
interface Cache {
}A map of module URL hrefs to loaded modules.
Options
interface Options {
builtins?: Builtins
cache?: Cache | boolean
concurrency?: number
defaultType?: number
imports?: ImportsMap
protocol?: Protocol
resolutions?: ResolutionsMap
}Shared loader configuration — the same field set LoadOptions, ResolveOptions, CreateRequireOptions, and ModuleLoader's own constructor options all build on.
LoadOptions
interface LoadOptions {
referrer?: Module
builtins?: Builtins
cache?: Cache | boolean
concurrency?: number
defaultType?: number
imports?: ImportsMap
protocol?: Protocol
resolutions?: ResolutionsMap
attributes?: Attributes
conditions?: Conditions
}Options for Module.load() / .loadSync().
ResolveOptions
interface ResolveOptions {
referrer?: Module
builtins?: Builtins
cache?: Cache | boolean
concurrency?: number
defaultType?: number
imports?: ImportsMap
protocol?: Protocol
resolutions?: ResolutionsMap
}Options for Module.resolve() / .resolveSync().
CreateRequireOptions
interface CreateRequireOptions {
referrer?: Module
builtins?: Builtins
cache?: Cache | boolean
concurrency?: number
defaultType?: number
imports?: ImportsMap
protocol?: Protocol
resolutions?: ResolutionsMap
}Options for Module.createRequire().
A module reaches as far as its protocol and its builtins, and a referrer hands on both. Narrowing one does not narrow the other, so code that should not reach what the referrer reaches must be given both:
// The module reads only through `protocol`, but still reaches every builtin the
// referrer was given.
Module.createRequire(parentURL, { referrer, protocol })
// The module reaches no further than what is passed here.
Module.createRequire(parentURL, { referrer, protocol, builtins })LinkOptions
interface LinkOptions {
attributes?: Attributes
conditions?: Conditions
}Options for ModuleLoader.link() / .linkSync().
ImportOptions
interface ImportOptions {
attributes?: Attributes
conditions?: Conditions
}Options for ModuleLoader.import() / .importSync().
RequireOptions
interface RequireOptions {
with?: Attributes
}Options for require(); with holds the import attributes.
RequireAddon
interface RequireAddon {
host: string
resolve: (specifier: string, parentURL?: URL) => unknown
}The require.addon function: imports addon modules, with host and resolve attached. host is the platform and architecture used when resolving addons, following the pattern <platform>-<arch>[-<environment>] — the same value as Bare.Addon.host.
Require
interface Require {
main: Module
cache: Cache
resolve: (specifier: string, parentURL?: URL) => string
addon: RequireAddon
asset: (specifier: string, parentURL?: URL) => string
}The function returned by Module.createRequire(): resolves and loads modules relative to its parent URL, with main, cache, resolve, addon, and asset attached.
CommonJS modules
require(specifier[, options])
Used to import JavaScript or JSON modules and local files. Relative paths such as ./, ./foo, ./bar/baz, and ../foo are resolved against the directory named by __dirname. POSIX-style paths are resolved in an OS-independent fashion, so the same relative paths work on Windows as they do on POSIX systems.
Returns the exported module contents.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
specifier | string | — | The module specifier to resolve and load. |
options? | RequireOptions | — | Options for the call; with.type selects how the file should be loaded — one of 'script', 'module', 'json', 'bundle', 'addon', 'binary', or 'text' (see Module.constants). A type that is not one of these is turned down rather than passed over, as is a type that is not a string. |
require.main
The module representing the entry script where the program was launched.
require.cache
The registry of loaded modules for this module's graph, keyed by URL href.
require.resolve(specifier[, parentURL])
Uses the internal machinery of require() to resolve specifier relative to the URL parentURL and returns the path string.
require.addon([specifier][, parentURL])
Also used to import modules, but loads only addon modules. specifier is resolved relative to parentURL using the addon resolution algorithm.
Returns the exported module contents.
A common pattern for writing an addon module is to use require.addon() as the JavaScript module's exports:
module.exports = require.addon()require.addon.host
The platform and architecture used when resolving addons, following the pattern <platform>-<arch>[-<environment>]. The same value as Bare.Addon.host.
require.addon.resolve([specifier][, parentURL])
Resolves specifier relative to parentURL as an addon and returns the path string, using the addon resolution algorithm.
require.asset(specifier[, parentURL])
Resolves specifier relative to parentURL and returns the path of the asset as a string. Can be used to load assets, for example to load ./foo.txt from the local file system:
const fs = require('bare-fs')
const contents = fs.readFileSync(require.asset('./foo.txt'))ECMAScript modules
import defaultExport, * as name, { export1, export2 as alias2 } from 'specifier' with { type: 'json' }
The static import declaration imports read-only live bindings that are exported by another module. The imported bindings are called live bindings because they are updated by the module that exported the binding, but cannot be re-assigned by the importing module. For more on import syntax, see MDN.
import.meta.url
The string representation of the URL for the current module.
import.meta.main
A boolean representing whether the current module is the entry script where the program was launched.
import.meta.cache
The registry of loaded modules for this module's graph, keyed by URL href. The same value as require.cache for a CommonJS module of the same graph.
import.meta.dirname
The directory name of the current module.
import.meta.filename
The file name of the current module.
import.meta.resolve(specifier[, parentURL])
A module-relative resolution function that returns the URL string for the module. specifier is a string resolved relative to parentURL, a WHATWG URL.
import.meta.addon([specifier][, parentURL])
Also used to import modules, but loads only addon modules. specifier is resolved relative to parentURL using the addon resolution algorithm.
Returns the exported module contents.
import.meta.addon.host
The platform and architecture used when resolving addons, following the pattern <platform>-<arch>[-<environment>]. The same value as Bare.Addon.host.
import.meta.addon.resolve([specifier][, parentURL])
Resolves specifier relative to parentURL as an addon and returns the URL string, using the addon resolution algorithm.
import.meta.asset(specifier[, parentURL])
Resolves specifier relative to parentURL and returns the URL of the asset as a string.
Packages
A package is a directory with a package.json file.
Fields
"name"
{
"name": "my-package"
}The name of the package. This is used for addon resolution, self-referencing, and importing packages by name.
"version"
{
"version": "1.2.3"
}The current version of the package. This is used for addon resolution.
"type"
{
"type": "module"
}The module format used for .js files. If not defined, .js files are interpreted as CommonJS. If set to "module", .js files are instead interpreted as ES modules.
"exports"
{
"exports": {
".": "./index.js"
}
}The entry points of the package. If defined, only the modules explicitly exported by the package may be imported when importing the package by name.
Subpath exports
A package may define more than one entry point by declaring several subpaths with the main export being ".":
{
"exports": {
".": "./index.js",
"./submodule": "./lib/submodule.js"
}
}When importing the package by name, require('my-package') will resolve to <modules>/my-package/index.js whereas require('my-package/submodule') will resolve to <modules>/my-package/lib/submodule.js.
Conditional exports
Conditional exports allow packages to provide different exports for different conditions, such as the loading method the importing module uses (for example require() vs import):
{
"exports": {
".": {
"import": "./index.mjs",
"require": "./index.cjs"
}
}
}When importing the package by name, require('my-package') will resolve to <modules>/my-package/index.cjs whereas import 'my-package' will resolve to <modules>/my-package/index.mjs.
Similarly, conditional exports can be used to provide different entry points for different runtimes:
{
"exports": {
".": {
"bare": "./bare.js",
"node": "./node.js"
}
}
}To provide a fallback for when no other conditions match, the "default" condition can be declared:
{
"exports": {
".": {
"bare": "./bare.js",
"node": "./node.js",
"default": "./fallback.js"
}
}
}The following conditions are supported, listed in order from most specific to least specific as conditions should be defined:
| Condition | Description |
|---|---|
"import" | Matches when the package is loaded via import or import(). |
"require" | Matches when the package is loaded via require(). |
"asset" | Matches when the package is loaded via require.asset(). |
"addon" | Matches when the package is loaded via require.addon(). |
"bare" | Matches for any Bare environment. |
"node" | Matches for any Node.js environment. |
"<platform>" | Matches when equal to Bare.platform. See Bare.platform for possible values. |
"<arch>" | Matches when equal to Bare.arch. See Bare.arch for possible values. |
"simulator" | Matches when Bare was compiled for a simulator. |
"default" | The fallback that always matches. This condition should always be last. |
Export conditions are evaluated in the order they are defined in the "exports" field. This means that less specific conditionals defined first will override more specific conditions define later. For example, the following will always call ./fallback.js because "default" always matches and is defined first.
{
"exports": {
".": {
"default": "./fallback.js",
"bare": "./bare.js"
}
}
}This is why the general rule is that conditions should be from most specific to least specific when defined.
Self-referencing
Within a package, exports defined in the "exports" field can be referenced by importing the package by name. For example, given the following package.json...
{
"name": "my-package",
"exports": {
".": "./index.js",
"./submodule": "./lib/submodule.js"
}
}...any module within my-package may reference these entry points using either require('my-package') or require('my-package/submodule').
Exports sugar
If a package defines only a single export, ".", it may leave out the subpath entirely:
{
"exports": "./index.js"
}"imports"
A private mapping for import specifiers within the package itself. Similar to "exports", the "imports" field can be used to conditional import other packages within the package. But unlike "exports", "imports" permits mapping to external packages.
The rules are otherwise analogous to the "exports" field.
Subpath imports
Just like exports, subpaths can be used when importing a module internally.
{
"imports": {
".": "./index.js",
"./submodule": "./lib/submodule.js"
}
}Conditional imports
Adding conditional imports allows importing different packages based on the configured conditions. As an example:
{
"imports": {
"bar": {
"require": "./baz.cjs",
"import": "./baz.mjs"
}
}
}When importing the package bar as require('bar') will resolve to ./baz.cjs, but when importing with import('bar') will resolve to ./baz.mjs.
To provide a fallback for when no other conditions are met, the "default" condition can be configured like so:
{
"imports": {
"bar": {
"require": "./baz.cjs",
"asset": "./baz.txt",
"default": "./baz.mjs"
}
}
}The following conditions are supported, listed in order from most specific to least specific as conditions should be defined:
| Condition | Description |
|---|---|
"import" | Matches when the package is loaded via import or import(). |
"require" | Matches when the package is loaded via require(). |
"asset" | Matches when the package is loaded via require.asset(). |
"addon" | Matches when the package is loaded via require.addon(). |
"bare" | Matches for any Bare environment. |
"node" | Matches for any Node.js environment. |
"<platform>" | Matches when equal to Bare.platform. See Bare.platform for possible values. |
"<arch>" | Matches when equal to Bare.arch. See Bare.arch for possible values. |
"simulator" | Matches when Bare was compiled for a simulator. |
"default" | The fallback that always matches. This condition should always be last. |
The general rule is that conditions should be from most specific to least specific when defined.
# Prefix
All import maps are private to the package and allow mapping to external packages. Entries in "imports" may start with # to disambiguate from external packages, but it is not required unlike in Node.js.
"engines"
{
"engines": {
"bare": ">=1.0.5"
}
}The "engines" field defines the engine requirements of the package. During module resolution, the versions declared by Bare.versions will be tested against the requirements declared by the package and resolution fail if they're not satisfied.
See also
- Builds on
bare-bundle,bare-module-lexer,bare-module-resolve,bare-path,bare-type-stripper, andbare-url. bare-module-resolveandbare-module-traverse— the resolution and traversal algorithms underneath.- Bare runtime API —
Bare.Addon, the native-addon loaderrequire.addonbuilds on. - Bare modules — the full
bare-*catalog. - Bare runtime API — the runtime these modules extend.
Last updated on