npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

graphile-export

v1.0.1

Published

Export in-memory generated GraphQL schemas to JS files when built with our helpers.

Downloads

7,459

Readme

graphile-export

Graphile Export enables you to export a GraphQL Schema (or other code) as executable JavaScript code. You must, however, write your code in a way that makes it exportable; we have ESLint plugins to make this less onerous.

How it works

The system works by converting values in memory into source code strings. One of the key things that's challenging to export is functions (and function-derived things such as classes). In JavaScript you can see the source code of a function by calling .toString() on it:

> (function add(a, b) { return a + b }).toString()
'function add(a, b) { return a + b }'

However this quickly falls down if you are using values from a parent closure:

> const a = 7;
undefined
> function add(b) { return a + b };
undefined
> add(3)
10
> add.toString()
'function add(b) { return a + b }'

See how the function definition string add.toString() returns its definition, but you cannot determine from that what the value of a is. This is a problem.

Graphile Export solves this by having you define your functions a bit like React hooks - you must state the dependencies explicitly:

> const { EXPORTABLE } = require("graphile-export")
undefined
> const a = 7;
undefined
> const add = EXPORTABLE((a) => function add(b) { return a + b; }, [a]);
undefined

When you do so, the add function is augmented with the properties $exporter$factory and $exporter$args that represent the first and second arguments to the EXPORTABLE(factory, args, nameHint) function respectively.

The function still works as before:

> add(3)
10
> add.toString()
'function add(b) { return a + b; }'

But graphile-export can access these special properties when it writes the code out, and now it can see the value of that "invisible" a=7:

> add.$exporter$factory.toString()
'(a) => function add(b) { return a + b; }'
> add.$exporter$args
[ 7 ]

Thus everything that can have these kinds of hidden properties must be wrapped in an EXPORTABLE call. Sometimes the inputs to the EXPORTABLE call themselves also have to be wrapped in an EXPORTABLE call. You'll figure out which things need wrapping by looking at the exported code and seeing where references are broken.

Using our ESLint plugin

Tracking all these dependencies yourself can to be a royal pain in the aggragate, so we've written a plugin eslint-plugin-graphile-export to do away with a lot of the pain.

To install:

yarn add eslint-plugin-graphile-export

To set up, add "graphile-export" to your ESLint configuration's plugins list, and "plugin:graphile-export/recommended" to the extends list:

// .eslintrc.js
module.exports = {
  //...
  plugins: [
    //...
    "graphile-export",
    //...
  ],
  extends: [
    //...
    "plugin:graphile-export/recommended",
    //...
  ],
  //...
};

To use it, simply add EXPORTABLE(() => before the value exporession to be exported, and ) after and then run eslint --fix against the file. It will automatically convert:

const add = EXPORTABLE(
  () =>
    function add(b) {
      return a + b;
    },
);

to:

const add = EXPORTABLE(
  (
    // The dependencies:
    a,
  ) =>
    function add(b) {
      return a + b;
    },
  [
    // The dependency values
    a,
  ],
);

You don't need to do this yourself everywhere, the plugin will look for common patterns and apply the EXPORTABLE itself as best it can. Do carefully review the changes it has made.

Note: no accommodation for formatting has been made, it is assumed that you are using prettier or similar code formatter and thus there's no need for us to format the code.

EXPORTABLE

Our ESLint plugin isn't smart enough to actually import the EXPORTABLE helper, so after running the autofix you might end up with "undefined variable EXPORTABLE" errors. You can either import { EXPORTABLE } from "graphile-export", or you can copy this definition into your code:

export function EXPORTABLE<T, TScope extends readonly any[]>(
  factory: (...args: TScope) => T,
  args: readonly [...TScope],
  nameHint?: string,
): T {
  const fn: T = factory(...args);
  if (
    ((typeof fn === "object" && fn !== null) || typeof fn === "function") &&
    !("$exporter$factory" in fn)
  ) {
    Object.defineProperties(fn, {
      $exporter$args: { value: args },
      $exporter$factory: { value: factory },
      $exporter$name: { writable: true, value: nameHint },
    });
  }
  return fn;
}

(Or, if you're using plain JavaScript:

export function EXPORTABLE(factory, args, nameHint) {
  const fn = factory(...args);
  if (
    ((typeof fn === "object" && fn !== null) || typeof fn === "function") &&
    !("$exporter$factory" in fn)
  ) {
    Object.defineProperties(fn, {
      $exporter$args: { value: args },
      $exporter$factory: { value: factory },
      $exporter$name: { writable: true, value: nameHint },
    });
  }
  return fn;
}

)

Plans for the future

One issue with this is that it makes your code quite messy. We're hoping to come up with a preprocessor or babel plugin or similar that should mean that your original code doesn't need all this boilerplate. But for now, explicit and functional is what we're going with!