Giter VIP home page Giter VIP logo

hullabaloo-config-manager's Introduction

hullabaloo-config-manager

Manages complex Babel config chains, avoiding duplicated work and enabling effective caching.

Hullabaloo: informal of "babel" (noun)

A confused noise, typically that made by a number of voices: the babel of voices on the road.

Use this package to resolve Babel config chains. The resulting options result in equivalent compilation behavior as if @babel/core had resolved the config.

A Node.js-compatible JavaScript module can be generated which exports a function that provides the options object, applicable for the current environment. This module can be written to disk and reused.

Config sources and plugin and preset dependencies can be hashed and used as cache keys. The cache keys and generated module can be verified to avoid having to repeatedly resolve the config chains, and to be sure a previously transformation result can be reused.

This module is used by AVA.

Installation

$ npm install --save hullabaloo-config-manager

Usage

const configManager = require('hullabaloo-config-manager')

API

currentEnv(): string

Returns the current environment value, just like @babel/core would determine it.

fromDirectory(dir: string, options?: {cache?: Cache, expectedEnvNames?: string[]}): Promise<ResolvedConfig | null>

Asynchronously resolves config chains from the dir directory. If no config can be found the promise is resolved with null. Otherwise it is resolved with the resulting config object. The promise is rejected if errors occur.

A cache object may be provided.

Provide expectedEnvNames when the config chain may contain JavaScript sources (such as .babelrc.js files). You must specify all environment names you want to use with the resolved config. Defaults to [currentEnv()].

createConfig(options: {options: BabelOptions, source: string, dir?: string, hash?: string, fileType?: 'JSON' | 'JSON5'}): Config

Creates and returns an in-memory config object. The first argument must be provided, and it must have a valid options object and source value.

If the dir value is not provided it's derived from the source value. Dependencies are resolved relative to this dir.

If the config source does not exist on disk the hash value should be provided, otherwise hashes cannot be created for the config.

The fileType property can be set to JSON if the options object can be serialized using JSON.stringify(). It defaults to JSON5. Use JS if the options object contains functions, maps, et cetera.

Note that the options object is cloned before use. Options are not validated to the same extend as when configuration files are loaded using fromDirectory or when the extends option is resolved.

fromConfig(baseConfig: Config, options?: {cache: Cache}): Promise<ResolvedConfig>

Asynchronously resolves config chains, starting with the baseConfig. The baseConfig must be created using the createConfig() method. The promise is resolved with the resulting config object. The promise is rejected if errors occur.

A cache object may be provided.

Provide expectedEnvNames when the config chain may contain JavaScript sources (such as .babelrc.js files). You must specify all environment names you want to use with the resolved config. Defaults to [currentEnv()].

restoreVerifier(buffer: Buffer): Verifier

Deserializes a Verifier. The buffer should be created using Verifier#toBuffer().

prepareCache(): Cache

Creates a cache object that can be passed to the above functions. This may improve performance by avoiding repeatedly reading files from disk or computing hashes.


Config

Use createConfig() to create this object.

Config#extend(config: Config)

Extend the config with another config. Throws a TypeError if the config was created with an extends clause in its options. It throws an Error if it has already been extended.


BabelOptions

See https://babeljs.io/docs/usage/api/#options. Note that the envName option must not be provided.


ResolvedConfig

Returned by fromConfig() and fromDirectory().

ResolvedConfig#generateModule(): string

Generates a Node.js-compatible JavaScript module which exports a getOptions() function. This function returns a unique options object, applicable for the current environment, that can be passed to @babel/core methods.

This module needs to evaluated before the getOptions() method can be accessed.

An environment name can be provided when calling getOptions(), e.g. getOptions('production'). If no name is provided, or the name is not a string, the environment is determined by checking process.env.BABEL_ENV, process.env.NODE_ENV, and finally defaulting to 'development'.

A second cache argument must be provided if the resolved configuration contains JavaScript sources, e.g. getOptions('production', cache). This should be the same object as passed to fromConfig() and fromDirectory().

ResolvedConfig#createVerifier(): Promise<Verifier>

Asynchronously hashes plugin and preset dependencies of the resolved config, as well as config sources, and resolves the promise with a Verifier object.


Verifier

Use restoreVerifier() or ResolvedConfig#createVerifier() to create this object.

Verifier#cacheKeysForCurrentEnv(): {dependencies: string, sources: string}

Synchronously returns cache keys for the plugin and preset dependencies, and config sources, that are applicable to the current environment. Use these values to cache the result of @babel/core transforms.

Verifier#verifyCurrentEnv(fixedHashes?: {sources: {[source: string]: string}}, cache?: Cache): Promise<{badDependency: true} | {missingSource: true} | {sourcesChanged: true} | {cacheKeys: {dependencies: string, sources: string}, dependenciesChanged: boolean, sourcesChanged: false, verifier: Verifier}>

Asynchronously verifies whether the config is still valid for the current environment.

Provide fixedHashes if the verifier was derived from a created config with a fixed hash value. A cache object may also be provided.

The promise is resolved with an object describing the verification result:

  • If the object has a badDependency property then a plugin or preset dependency could not be hashed, presumably because it no longer exists.

  • If it has a missingSource property then a config source no longer exists.

  • If its sourcesChanged property is true then config sources have changed and the config is no longer valid.

  • If its dependenciesChanged property is true then plugin or preset dependencies have changed, but the config itself is still valid. The verifier property holds a new Verifier object which takes the new dependencies into account. The cacheKeys property contains the same result as calling Verifier#cacheKeysForCurrentEnv() on the returned verifier.

  • If its sourcesChanged and dependenciesChanged properties are both false then the config is valid and cache keys won't have changed. The verifier property holds the same Verifier object. The cacheKeys properties contains the same result as calling Verifier#cacheKeysForCurrentEnv().

Verifier#toBuffer()

Serializes the verifier state into a Buffer object. Use restoreVerifier() to deserialize.


Errors

Error constructors are not publicly available, but errors can be identified by their name property.

BadDependencyError

Used when a plugin or preset dependency couldn't be resolved. The corresponding package or file name is available through the source property. There may be another error with more details, available through the parent property.

ExtendsError

Used when an extends clause points at a non-existent file. The config file that contains the clause is available through the source property. The clause itself is available through the clause property. Has a parent property that contains a NoSourceFile error.

InvalidFileError

Used when a config file is invalid. The file path is available through the source property.

MultipleSourcesError

Used when multiple configuration files are found. File paths are available through the source and otherSource properties.

NoSourceFileError

Used when a file does not exist. The file path is available through the source property.

ParseError

Used when a config file cannot be parsed (this is different from it being invalid). The file path is available through the source property. The parsing error is available through the parent property.

hullabaloo-config-manager's People

Contributors

greenkeeper[bot] avatar novemberborn avatar reconbot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

reconbot

hullabaloo-config-manager's Issues

Support .babelrc.js files

Babel 7.0 adds support for .babelrc.js files. We need to follow suit.

  • When looking for babelrc, prioritize .babelrc.js over reading "babel" from package.json
  • Include a hash for the .babelrc.js source in the source hashes and cache keys
  • When verifying hashes for the current environment, if there is a babelrcDir, and .babelrc is not one of the sources, and neither is .babelrc.js, ensure .babelrc.js is still missing

Since the output of .babelrc.js files can vary, we cannot recurse through it when collecting configs. Instead we need to terminate the chain at the .babelrc.js file and communicate its existence to consuming code. That code then needs to call a different routine which can then resolve the config and build a fuller chain, fit for the current environment. Ideally this chain can then be hashed again to utilize caches, and serialized if necessary.

Of course the .babelrc.js file may return function references for plugins and presets, and option values for plugins / presets which cannot be serialized. This needs to be detected so the consuming code can use the earlier, incomplete chain, as its Babel config.

When loading the .babelrc.js file keep in mind that it should support faux-ES-modules. It might also be good to load it in a different context without access to the current require cache or non-standard globals. This to discourage "clever" hacks that are then foiled by the resulting config being cached by consuming code.

ResolveError: Couldn't find preset

Hi there,

Im trying to introduce ava to a package however I'm running into issues with it pulling in babel presets

The error I'm receiving is

ResolveError: C:\code\mypackage\package.json: Couldn't find preset "transform-es2015-modules-commonjs" relative to directory
    at resolve (C:\code\mypackage\node_modules\hullabaloo-config-manager\lib\resolvePluginsAndPresets.js:111:17)
    at resolvePluginsAndPresets (C:\code\mypackage\node_modules\hullabaloo-config-manager\lib\resolvePluginsAndPresets.js:125:9)
    at reduceChains (C:\code\mypackage\node_modules\hullabaloo-config-manager\lib\reduceChains.js:119:29)
    at new ResolvedConfig (C:\code\mypackage\node_modules\hullabaloo-config-manager\lib\ResolvedConfig.js:12:21)
    at collector.fromConfig.then.chains (C:\code\mypackage\node_modules\hullabaloo-config-manager\index.js:35:21)
"ava": {
    "require": "babel-register",
    "babel": "inherit"
  },
  "babel": {
    "presets": [
      "transform-es2015-modules-commonjs"
    ]
  },
  "scripts": {
    "avaTest": "ava test/the.test.js"
}

No .babelrc files. Running on windows.

I've also tried having the babel config within the ava config but that throws the same error.

Any tips would be great, thanks in advance!

`Error: Could not find the configuration module for '/foo/.babelrc.js' in the cache`

I get this message often.

To git rid of it, I have to rm -rf node_modules/.cache, then it works for a while. But then I change something (maybe its after installing a new package), and I get this message.

  Error: Could not find the configuration module for '/foo/.babelrc.js' in the cache
      at Object.loadCachedModule (/foo/node_modules/.registry.npmjs.org/hullabaloo-config-manager/2.0.0-beta.4/node_modules/hullabaloo-config-manager/build/helpers.js:201:15)
      at defaultOptions (/foo/node_modules/.cache/ava/3f40f9aa425d78e9a8bf2493dee7de25.babel-options.js:9:13)
      at exports.getOptions (/foo/node_modules/.cache/ava/3f40f9aa425d78e9a8bf2493dee7de25.babel-options.js:61:7)
      at CachingPrecompiler.getOptions [as getBabelOptions] (/foo/node_modules/.registry.npmjs.org/ava/1.0.0-beta.4/node_modules/ava/lib/babel-config.js:188:13)
      at CachingPrecompiler._transform (/foo/node_modules/.registry.npmjs.org/ava/1.0.0-beta.4/node_modules/ava/lib/caching-precompiler.js:57:59)
      at transform (/foo/node_modules/.registry.npmjs.org/caching-transform/1.0.1/node_modules/caching-transform/index.js:43:10)
      at CachingPrecompiler.transform (/foo/node_modules/.registry.npmjs.org/caching-transform/1.0.1/node_modules/caching-transform/index.js:60:17)
      at CachingPrecompiler.precompileFile (/foo/node_modules/.registry.npmjs.org/ava/1.0.0-beta.4/node_modules/ava/lib/caching-precompiler.js:36:9)
      at map.files.concat.reduce (/foo/node_modules/.registry.npmjs.org/ava/1.0.0-beta.4/node_modules/ava/api.js:134:51)
      at Array.reduce (<anonymous>)
      at AvaFiles.findTestHelpers.then.helpers (/foo/node_modules/.registry.npmjs.org/ava/1.0.0-beta.4/node_modules/ava/api.js:131:36)
  From previous event:
      at _setupPrecompiler.then.precompilation (/foo/node_modules/.registry.npmjs.org/ava/1.0.0-beta.4/node_modules/ava/api.js:128:83)
      at <anonymous>

Plugin and preset mapping with array refs breaks if array doesn't include options

When mapping plugins and presets, if the ref is an array with only the first item, just return the entry for that reference. Currently we're assuming the ref array also includes options, which isn't always the case. Returning an undefined option item stops Babel from defaulting it to an empty object.

The code lives here:

return [mapPluginOrPreset(getEntry, ref[0]), ref[1]]

Discovered through avajs/ava#1360 (comment).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.