Skip to content

Packages for working with invariant(condition, message) assertions

License

Notifications You must be signed in to change notification settings

apollographql/invariant-packages

Repository files navigation

invariant-packages CI

Packages for working with invariant(condition, message) assertions.

⚠️ If you came here because of an Apollo Client error message like the following:

Invariant Violation: Invariant Violation: 27 (see https://github.com/apollographql/invariant-packages)

you should consult the file node_modules/@apollo/client/invariantErrorCodes.js for more details about the numbered invariant:

  27: {
    file: "@apollo/client/react/context/ApolloConsumer.js",

    node: invariant(context && context.client, 'Could not find "client" in the context of ApolloConsumer. ' +
        'Wrap the root component in an <ApolloProvider>.')
  },

The exact contents of the invariantErrorCodes.js file can change between @apollo/client releases, so make sure you're consulting the same version of @apollo/client that threw the error. Note also that the file is generated during the release process, and is not checked into the https://github.com/apollographql/apollo-client repository. This file was first included in @apollo/[email protected].

Usage

This repository is home to the ts-invariant and rollup-plugin-invariant packages.

Runtime usage (ts-invariant)

The ts-invariant package exports the following utilities:

invariant(condition: any, message: string)

Similar to the the invariant function used by React, this function throws an InvariantError with the given message if the condition argument evaluates to a falsy value.

invariant.error(...args: any[])

Equivalent to calling console.error(...args).

invariant.warn(...args: any[])

Equivalent to calling console.warn(...args).

new InvariantError(message: string)

The Error subclass thrown by failed invariant calls.

Build-time usage (rollup-plugin-invariant)

If you're using Rollup to bundle your code, or using a library that was bundled using Rollup and rollup-plugin-invariant, then the above utilities will be transformed so that minifiers can strip the long error strings from your production bundle.

Calls of the form invariant(condition, message) are transformed to

process.env.NODE_ENV === 'production'
  ? invariant(condition)
  : invariant(condition, message)

Expressions of the form new InvariantError(message) are transformed to

process.env.NODE_ENV === 'production'
  ? new InvariantError()
  : new InvariantError(message)

Although this looks like more code, it enables minifiers to prune the unreached branch of the conditional expression based on the value of process.env.NODE_ENV, so only the shorter version remains in production.

Configuration

Here's how you might configure Rollup to use rollup-plugin-invariant and also minify the transformed code effectively:

// rollup.config.js

import invariantPlugin from "rollup-plugin-invariant";
import { terser as minify } from "rollup-plugin-terser";

export default [{
  input: "src/index.js",
  output: {
    file: "lib/bundle.js",
    format: "cjs"
  },
  plugins: [
    invariantPlugin({
      errorCodes: true,
    }),
  ],
}, {
  input: "lib/bundle.js",
  output: {
    file: "lib/bundle.min.js",
    format: "cjs"
  },
  plugins: [
    minify({
      compress: {
        global_defs: {
          "@process.env.NODE_ENV": JSON.stringify("production"),
        },
      },
    }),
  ],
}];

Error codes

If you create an instance of the plugin with the { errorCodes: true } option, message strings will be replaced with numeric error codes instead of simply disappearing, so invariant(condition, message) becomes

process.env.NODE_ENV === 'production'
  ? invariant(condition, <error code>)
  : invariant(condition, message)

and new InvariantError(message) becomes

process.env.NODE_ENV === 'production'
  ? new InvariantError(<error code>)
  : new InvariantError(message)

With errorCodes enabled, InvariantError messages will be displayed as

Invariant Violation: <error code> (see https://github.com/apollographql/invariant-packages)

For example, if you see an error of the form

Invariant Violation: Invariant Violation: 38 (see https://github.com/apollographql/invariant-packages)

you should consult the file node_modules/@apollo/client/invariantErrorCodes.js for more details about the numbered invariant:

  38: {
    file: "@apollo/client/utilities/graphql/directives.js",
    node: invariant(evaledValue !== void 0, "Invalid variable referenced in @" + directive.name.value + " directive.")
  },

The dynamic value of directive.name.value will not be provided because those arguments are pruned in production (leaving just invariant(evaledValue !== void)), but this information should allow you to set a breakpoint in the node_modules/@apollo/client/utilities/graphql/directives.js file to investigate further.

The exact contents of the invariantErrorCodes.js file can change between @apollo/client releases, so make sure you're consulting the same version of @apollo/client that threw the error. Note also that the file is generated during the release process, and is not checked into the https://github.com/apollographql/apollo-client repository. This file was first included in @apollo/[email protected].

Automatic process import

If you create an instance of the plugin with the { importProcessPolyfill: true } option, any import ... from "ts-invariant" declarations will have process added to the list of imported identifiers.

When ts-invariant is used in a JS environment where process is globally defined, the process export will simply be the same as that global object. Otherwise, it will be an object of the shape { env: {} }, to ensure process.env.NODE_ENV is safe to evaluate at runtime, in case it has not been replaced by the minifier.

About

Packages for working with invariant(condition, message) assertions

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Packages

No packages published