Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Searches for and loads your tool's JavaScript configuration files with full support for CJS, ESM, TypeScript and more.

NotificationsYou must be signed in to change notification settings

natemoo-re/proload

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

69 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Proload searches for and loads your tool's JavaScript configuration files. Users have complex expectations when it comes to configuration files—the goal of Proload is to offer a single, straightforward and extensible API for loading them.

importloadfrom'@proload/core';awaitload('namespace');

@proload/core can be used innode@12.20.1 and up. It relies on Node's native ESM semantics.

Motivation

Configuration files are really difficult to get right. Tool authors tend to think, "Easy solve! I'll just have everyone use onenamespace.config.js!" In most cases that should work, but sincenode@12.17.0, plain.js files can be written in either ESM or CJS—both formats are officially supported and can be configured on a per-project basis. Additionally,node is able to load any file using a.cjs or.mjs extension, not just.js.

Many popular libraries get these semantics wrong, but maintaining and testing this resolution logic in library code can be a huge maintanence burden. As a library author, you don't need to know (or care) which module format your users choose—you just need to load the contents of the config file.@proload/core is a well-tested solution that gets these semantics right, so you can focus on more important things.

You probably have TypeScript users, too! They would definitely appreciate being able to write a.ts config file.@proload/core uses a plugin system to load non-JavaScript files. SeePlugins or@proload/plugin-typescript specifically.

Resolution

Out of the box,@proload/core searches up the directory tree for the following files:

  • a[namespace].config.js,[namespace].config.cjs, or[namespace].config.mjs file
  • any of thejs/cjs/mjs files inside ofconfig/ directory
  • apackage.json file with a top-level[namespace] key

Here's an overview of all the files supported by default for a tool nameddonut.

await load('donut');.├── donut.config.js        // Either ESM or CJS supported├── donut.config.cjs├── donut.config.mjs├── config/                // Great for organizing many configs│   ├── donut.config.js│   ├── donut.config.cjs│   └── donut.config.mjs└── package.json           // with top-level "donut" property

resolve

resolve is an additional named export of@proload/core. It is anasync function that resolvesbut does not load a configuration file.

  • namespace is the name of your tool. As an example,donut would search fordonut.config.[ext].
  • opts configure the behavior ofload. SeeOptions.
resolve(namespace: string,opts?:ResolveOptions);

load

Thedefault export of@proload/core is anasync function to load a configuration file.

  • namespace is the name of your tool. As an example,donut would search fordonut.config.[ext].
  • opts configure the behavior ofload. SeeOptions.
load(namespace: string,opts?:LoadOptions);

Options

cwd

load searches up the directory tree, beginning from this loaction. Defaults toprocess.cwd().

importloadfrom'@proload/core';awaitload('namespace',{cwd:'/path/to/user/project'});

filePath

If you already have the exact (absolute or relative)filePath of your user's config file, set thefilePath option to disable Proload's search algorithm.

importloadfrom'@proload/core';awaitload('namespace',{cwd:'/path/to/user/project',filePath:'./custom-user-config.js'});

mustExist

mustExist controls whether a configurationmust be found. Defaults totrue—Proload will throw an error when a configuration is not found. To customize error handling, you may check the shape of the thrown error.

Setting this option tofalse allows a return value ofundefined when a configuration is not found.

importload,{ProloadError}from'@proload/core';try{awaitload('namespace',{mustExist:true});}catch(err){// Proload couldn't resolve a configuration, log a custom contextual errorif(errinstanceofProloadError&&err.code==='ERR_PROLOAD_NOT_FOUND'){console.error(`See the "namespace" docs for configuration info`);}throwerr;}

context

Users may want to dynamically generate a different configuration based on some contextual information passed from your tool. Any{ context } passed to theload function will be forwarded to configuration "factory" functions.

// Library codeimportloadfrom'@proload/core';awaitload('namespace',{context:{isDev:true}});// namespace.config.jsexportdefault({ isDev})=>{return{featureFlag:isDev}}

accept

If you need complete control over which file to load, theaccept handler can customize resolution behavior. A return value oftrue marks a file to be loaded, any other return values (even truthy ones) is ignored.

See theaccept interface.

Note thatPlugins are able to modify similar behavior. To load non-JavaScript files, you should use a plugin instead ofaccept.

importloadfrom'@proload/core';awaitload('donut',{accept(fileName){// Support alternative spelling for any European friendsreturnfileName.startsWith('doughnut.config');}})

The following example uses@proload/plugin-typescript to add support for loading.ts files and anaccept handler to require all config files to use the.ts extension.

importloadfrom'@proload/core';importtypescriptfrom'@proload/plugin-typescript';load.use([typescript]);awaitload('namespace',{accept(fileName){// Only accept `.ts` config filesreturnfileName.endsWith('.ts');}})

merge

To customizeextends behavior, you may pass a custommerge function to theload function. By default,deepmerge is used.

// Library codeimportloadfrom'@proload/core';constshallowMerge=(a,b)=>({ ...a, ...b})awaitload('namespace',{merge:shallowMerge});// namespace.config.jsexportdefault{extends:['./a.js','./b.js']}// a.jsexportdefault{a:true}// b.jsexportdefault{b:true}// result{a:true,b:true}

Automaticextends

Tools liketypescript andbabel have popularized the ability to share configuration presets through a top-levelextends clause.extends also allows you to share a local base configuration with other packages, which is extremely useful for monorepo users.

Custom implementation of this behavior can be difficult, so@proload/core automatically recognizes top-levelextends clauses (string[]) for you. It recursively resolves and merges all dependent configurations.

// namespace.config.jsexportdefault{extends:['@namespace/preset','../namespace.base.config.js']}

Extending local configuration files

In many cases, particularly in monorepos, it's useful to have a base configuration file and useextends in any sub-packages to inherit the base configuration.@proload/core resolves paths inextends relative to the configuration file itself.

.├── namespace.base.config.js└── packages/    ├── package-a/    │   └── namespace.config.js    └── package-b/        └── namespace.config.js

Extending configuration presets

@proload/core uses the same strategy to resolve a configuration file from projectdependencies as it does for user configurations. When publishing a configuration preset, use the same file naming strategy as you would for local configuration.

.├── node_modules/│   └── @namespace/│       └── preset-env/│           ├── package.json│           └── namespace.config.js├── package.json└── namespace.config.js

Assuming@namespace/preset-env is a project dependency, the top-levelnamespace.config.js file can useextends to reference the dependency.

exportdefault{extends:['@namespace/preset-env']}

Plugins

In order to support as many use cases as possible,@proload/core uses a plugin system. Plugins build on each other and are designed to be combined. For example, to support anamespacerc.json file, you could use both@proload/plugin-json and@proload/plugin-rc.

importloadfrom'@proload/core';importrcfrom'@proload/plugin-rc';importjsonfrom'@proload/plugin-json';load.use([rc,json]);awaitload('namespace');

TypeScript

In order to load a[namespace].config.ts file, use@proload/plugin-typescript.

importloadfrom'@proload/core';importtypescriptfrom'@proload/plugin-typescript';load.use([typescript]);awaitload('namespace');

JSON

In order to load a[namespace].config.json file, use@proload/plugin-json.

importloadfrom'@proload/core';importjsonfrom'@proload/plugin-json';load.use([json]);awaitload('namespace');

YAML

In order to load a[namespace].config.yaml or[namespace].config.yml file, use@proload/plugin-yaml.

importloadfrom'@proload/core';importyamlfrom'@proload/plugin-yaml';load.use([yaml]);awaitload('namespace');

RC files

In order to load a[namespace]rc file with any extension, use@proload/plugin-rc.

importloadfrom'@proload/core';importrcfrom'@proload/plugin-rc';load.use([rc]);awaitload('namespace');

All Plugins

For illustrative purposes (please don't do this), combining all of these plugins would support the following resolution logic:

.├── namespace.config.js├── namespace.config.cjs├── namespace.config.mjs├── namespace.config.ts├── namespace.config.json├── namespace.config.yaml├── namespace.config.yml├── namespacerc.js├── namespacerc.cjs├── namespacerc.mjs├── namespacerc.ts├── namespacerc.json├── namespacerc.yaml├── namespacerc.yml├── config/│   ├── namespace.config.js│   ├── namespace.config.cjs│   ├── namespace.config.mjs│   ├── namespace.config.ts│   ├── namespace.config.json│   ├── namespace.config.yaml│   ├── namespace.config.yml│   ├── namespacerc.js│   ├── namespacerc.cjs│   ├── namespacerc.mjs│   ├── namespacerc.ts│   ├── namespacerc.json│   ├── namespacerc.yaml│   └── namespacerc.yml└── package.json

Credits

Proload is heavily inspired by tools likecosmiconfig andrc.

Proload would not be possible without@lukeed's amazing work onescalade anduvu.

About

Searches for and loads your tool's JavaScript configuration files with full support for CJS, ESM, TypeScript and more.

Topics

Resources

Stars

Watchers

Forks

Sponsor this project

 

[8]ページ先頭

©2009-2025 Movatter.jp