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

@fab/static

v0.1.8

Published

Compile static-site projects into FABs

Readme


name: "@fab/static" route: "/packages/fab-static" menu: Packages

💎 @fab/static

Builds a FAB from a directory of static HTML and assets, with an optional server-side component.

oclif  Version  Downloads/week  License 

Getting Started

Install @fab/static as a development dependency:

yarn add --dev @fab/static
npm install --dev @fab/static

Add a couple of scripts to your package.json:

  "scripts": {
    "build": "[your existing build step]",
+   "build:fab": "npm run build && npm run fab:compile",
+   "fab:compile": "fab-static [dirname]"
  },
}

Replace dirname with wherever your built files live (build for Create React App & friends, public for Gatsby, dist for some others)

We've added two scripts here, fab:compile which runs the fab-static builder, and build:fab that builds the project first. Most of the time, and especially you're using a FAB-enabled platform like linc.sh, you'll mostly run build:fab, but having a separate fab:compile step can be handy as you set things up.

You can test it out by running:

npm run build:fab

Once this is complete, you should have a fab.zip file (and a .fab directory with a bunch of build files). Those don't need to be checked in to your repository, so you can add them to your .gitignore file with this one-liner:

echo "\n.fab\nfab.zip" >> .gitignore

If you want to spin up your fab.zip file locally, you can use @fab/serve. You can either install it globally:

yarn global add @fab/serve
npm install --global @fab/serve

fab-serve fab.zip

Or use the awesome npx (which is bundled with NodeJS) to run a command-line NPM package without needing to install it:

npx @fab/serve fab.zip

You should see your app running on http://localhost:3000!

Note: this process will add one file fab.zip and one directory .fab into your project.

Usage

@fab/static takes the following options:

USAGE
  $ fab-static [DIRECTORY]

OPTIONS
  -h, --help                         show CLI help
  -o, --output=output                Output FAB file (default fab.zip)
  -p, --prod-settings=prod-settings  Path to production settings json
  -s, --server=server                Path to server entry file or directory
  -w, --working-dir=working-dir      Intermediate directory for working (default .fab)
  --intermediate-only

EXAMPLE
  $ fab-static ~/src/my-project/build

Efficiently handling assets

The fab.zip file only allows two components—the first is a server.js, which is auto-generated by @fab/static, and the second is an _assets directory. If your assets aren't in an _assets subdirectory (e.g. a public or static directory instead), @fab/static will automatically move them and generate server-side code to wire things up at runtime. This process works fine, but it's inefficient.

To read more about the rewriting process, visit the @fab/compile documentation, or for a more general overview of why _assets is a core part of the FAB spec, visit https://fab.dev/kb/no-assets-dir

Environment Variables

The FAB format has first-class support for environment variables which you can read about here: https://fab.dev/kb/environment-variables.

To specify production environment variables to be bundled into the FAB itself, add a production-settings.json file in the same directory as your package.json file and it will be automatically included into the build. You can also specify a path with -p or --prod-settings if you'd prefer to keep your settings file elsewhere/name it differently.

A production settings file might look like:

{
  "API_URL": "https://api.example.com",
  "CLIENT_ID": "1cd5e6a4871f98616a38abb2eada56868ca5aad2"
}

These values are for the production environment (read why). To supply non-production variables that will be injected in place of these settings, consult the documentation of your hosting platform e.g. Linc

Accessing Environment Variables at Runtime

@fab/static dynamically injects a <script> tag into any HTML response as it's being streamed to the client:

<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- FAB SETTINGS SCRIPT TAG INJECTED HERE -->
    <meta charset="UTF-8" />
    <title>Document</title>
    <!-- ... -->
  </head>
  <body>
    <!-- ... -->
  </body>
</html>

That <script> tag has the following format:

<script type="text/javascript">
  window.FAB_SETTINGS = {
    "API_URL": "https://staging.api.example.com"
  }
</script>

Whatever the settings object passed to render (which will be a combination of production settings as well as any environment-specific overrides), @fab/static will serialise them to JSON and inject them as window.FAB_SETTINGS. This code will execute before any other, meaning you can always rely on FAB_SETTINGS to be available by the time your app is booted.

fetch(`${window.FAB_SETTINGS.API_URL}/endpoint`).then(
  // ...
)

To use the same environment variables during development, it's recommended to add a layer of abstraction between FAB_SETTINGS (available once the FAB is built) and process.env (available during development). For example

// src/config.js

const lookupEnvVar = name => {
  // Use FAB_SETTINGS if defined
  if (typeof FAB_SETTINGS === 'object') {
    return FAB_SETTINGS[name]
    
  // Otherwise use process.env
  } else {
    // Note: some build systems (like Create React App) only expose
    // process.env vars that start with a prefix (like REACT_APP_)
    return process.env[`REACT_APP_${name}`]
  }
}

export default {
  API_URL: lookupEnvVar('API_URL'),
  API_KEY: lookupEnvVar('API_KEY'),
  // ...
}

You can use the config throughout your app like so:

import config from '../config'

fetch(`${config.API_URL}/endpoint`).then(
  // ...
)

Adding a server

Despite the name, @fab/static is capable of running virtually any server-side logic you'd like. From use-cases like rewriting or forwarding URLs, proxying APIs, or simply providing a health check, you can supercharge your FAB by using the -s or --server flag to fab-static.

For simple use-cases, you can use a single file:

fab-static --server path/to/server.js

For more complex setups, you can specify a whole directory which will be bundled into the FAB:

fab-static --server path/to/server

In this example, the path/to/server/index.js will be used as the entry point, but the whole directory will be copied into the FAB.

Server API

Your server.js or server/index.js file can export one of three endpoints:

export async function modifyRequest(settings, request) {
  // default behaviour is nothing, needs no return value
}

export async function route(settings, path, request) {
  // must return something, by default returns the path unchanged
  return path
}

export async function modifyResponse(settings, response) {
  // default behaviour is nothing, needs no return value
}