serve Documentation

Static file serving and directory listing

9,906 stars TypeScript TypeScript 1 file ยท ~5,408 tokens #cli#command#http#node
RAW Doc

File: readme.md


serve helps you serve a static site, single page application or just a static file (no matter if on your device or on the local network). It also provides a neat interface for listing the directory's contents:

Once it's time to push your site to production, we recommend using Vercel.

Usage

serve v14 onwards requires Node v14 to run. Please use serve v13 if you cannot upgrade to Node v14.

The quickest way to get started is to just run npx serve in your project's directory.

If you prefer, you can also install the package globally (you'll need at least Node LTS):

bash
> npm install --global serve

Once that's done, you can run this command inside your project's directory...

bash
> serve

...or specify which folder you want to serve:

bash
> serve folder-name/

Finally, run this command to see a list of all available options:

bash
> serve --help

Now you understand how the package works! :tada:

Configuration

To customize serve's behavior, create a serve.json file in the public folder and insert any of these properties.

API

The core of serve is serve-handler, which can be used as middleware in existing HTTP servers:

js
const handler = require('serve-handler');
const http = require('http');

const server = http.createServer((request, response) => {
  // You pass two more arguments for config and middleware
  // More details here: https://github.com/vercel/serve-handler#options
  return handler(request, response);
});

server.listen(3000, () => {
  console.log('Running at http://localhost:3000');
});

You can also replace http.createServer with micro.

Issues and Contributing

If you want a feature to be added, or wish to report a bug, please open an issue here.

If you wish to contribute to the project, please read the contributing guide first.

Credits

This project used to be called list and micro-list. But thanks to TJ Holowaychuk handing us the new name, it's now called serve (which is much more definite).

Author

Leo Lamprecht (@leo)


File: CHANGELOG.md

serve

14.2.6

Patch Changes

  • 7fcb924: Bump ajv to 8.18.0
  • b3888f9: Update serve-handler to 6.1.7 to fix ReDoS vulnerabilities

14.2.5

Patch Changes

  • f4b6fbd: Update compression to v1.8.1

File: contributing.md

Contributing Guide

Thanks for your interest in contributing to serve! This guide will
show you how to set up your environment and contribute to this library.

Set Up

First, you need to install and be familiar the following:

  • git: Here is a great guide by GitHub on
    installing and getting started with Git.
  • node and pnpm:
    This guide will help you
    install Node and this one will help you install PNPM. The
    recommended method is using the n version manager if you are on MacOS or Linux. Make sure
    you are using the current version of
    Node.

Once you have installed the above, follow
these instructions
to
fork
and clone the repository
(vercel/serve).

Once you have forked and cloned the repository, you can
pick out an issue
you want to fix/implement!

Making Changes

Once you have cloned the repository to your computer (say, in
~/code/serve) and picked the issue you want to tackle, create a
branch:

sh
> git switch --create branch-name

While naming your branch, try to follow the below guidelines:

  1. Prefix the branch name with the type of change being made:
    • fix: For a bug fix.
    • feat: For a new feature.
    • test: For any change related to tests.
    • perf: For a performance related change.
    • build: For changes related to the build process.
    • ci: For all changes to the CI files.
    • refc: For any refactoring work.
    • docs: For any documentation related changes.
  2. Make the branch name short but self-explanatory.

Once you have created a branch, you can start coding!

The CLI is written in
Typescript and uses the
current version of Node.
The code is structured as follows:

sh
serve
โ”œโ”€โ”€ config
โ”‚  โ””โ”€โ”€ husky
โ”‚     โ”œโ”€โ”€ _
โ”‚     โ””โ”€โ”€ pre-commit
โ”œโ”€โ”€ media
โ”‚  โ”œโ”€โ”€ banner.png
โ”‚  โ””โ”€โ”€ listing-ui.png
โ”œโ”€โ”€ source
โ”‚  โ”œโ”€โ”€ utilities
โ”‚  โ”‚  โ”œโ”€โ”€ cli.ts
โ”‚  โ”‚  โ”œโ”€โ”€ config.ts
โ”‚  โ”‚  โ”œโ”€โ”€ http.ts
โ”‚  โ”‚  โ”œโ”€โ”€ logger.ts
โ”‚  โ”‚  โ”œโ”€โ”€ promise.ts
โ”‚  โ”‚  โ””โ”€โ”€ server.ts
โ”‚  โ”œโ”€โ”€ main.ts
โ”‚  โ””โ”€โ”€ types.ts
โ”œโ”€โ”€ contributing.md
โ”œโ”€โ”€ license.md
โ”œโ”€โ”€ package.json
โ”œโ”€โ”€ pnpm-lock.yaml
โ”œโ”€โ”€ readme.md
โ””โ”€โ”€ tsconfig.json

Most files have a little description of what they do at the top.

`./`

  • package.json: Node package manifest. This file contains the name, version,
    description, dependencies, scripts and package configuration of the project.
  • pnpm-lock.yaml: PNPM lock file, please do not modify it manually. Run
    pnpm install to update it if you add/remove a dependency to/from
    package.json manually.
  • tsconfig.json: The Typescript configuration for this project.
  • contributing.md: The file you are reading. It helps contributors get
    started.
  • license.md: Tells people how they can use the code.
  • readme.md: The file everyone should read before running the server. Contains
    installation and usage instructions.

`config/husky/`

  • pre-commit: This file is a script that runs before Git commits code.

`source/utilities/`

  • utilities/config.ts: Searches and parses the configuration for the CLI.
  • utilities/http.ts: Defines and exports helper functions for the server.
  • utilities/server.ts: Exports a function used to start the server with a
    given configuration on a certain port.
  • utilities/promise.ts: Exports utility functions and wrappers that help
    resolve Promises.
  • utilities/cli.ts: Exports functions that help with CLI-related stuff, e.g.,
    parsing arguments and printing help text.
  • utilities/logger.ts: A barebones logger.

`source/`

  • main.ts: Entrypoint for the CLI.
  • types.ts: Typescript types used in the project.

When adding a new feature/fixing a bug, please add/update the readme. Also make
sure your code has been linted and that existing tests pass. You can run the linter
using pnpm lint, the tests using pnpm test and try to automatically fix most lint
issues using pnpm lint --fix.

You can run the CLI tool using pnpm develop, which will re-run the CLI everytime you
save changes made to the code.

Once you have made changes to the code, you will want to
commit (basically, Git's version
of save) the changes. To commit the changes you have made locally:

sh
> git add this/folder that/file
> git commit --message 'commit-message'

While writing the commit-message, try to follow the below guidelines:

  1. Prefix the message with type:, where type is one of the following
    dependending on what the commit does:
    • fix: Introduces a bug fix.
    • feat: Adds a new feature.
    • test: Any change related to tests.
    • perf: Any performance related change.
    • build: For changes related to the build process.
    • ci: For all changes to the CI files.
    • refc: Any refactoring work.
    • docs: Any documentation related changes.
  2. Keep the first line brief, and less than 60 characters.
  3. Try describing the change in detail in a new paragraph (double newline after
    the first line).

Contributing Changes

Once you have committed your changes, you will want to
push (basically, publish your
changes to GitHub) your commits. To push your changes to your fork:

sh
> git push -u origin branch-name

If there are changes made to the main branch of the
vercel/serve repository, you may wish to
rebase
your branch to include those changes. To rebase, or include the changes from the
main branch of the vercel/serve repository:

text
> git fetch upstream main
> git rebase upstream/main

This will automatically add the changes from main branch of the
vercel/serve repository to the current branch. If you encounter
any merge conflicts, follow
this guide
to resolve them.

Once you have pushed your changes to your fork, follow
these instructions
to open a
pull request:

Once you have submitted a pull request, the maintainers of the repository will
review your pull requests. Whenever a maintainer reviews a pull request they may
request changes. These may be small, such as fixing a typo, or may involve
substantive changes. Such requests are intended to be helpful, but at times may
come across as abrupt or unhelpful, especially if they do not include concrete
suggestions on how to change them. Try not to be discouraged. If you feel that a
review is unfair, say so or seek the input of another project contributor. Often
such comments are the result of a reviewer having taken insufficient time to
review and are not ill-intended. Such difficulties can often be resolved with a
bit of patience. That said, reviewers should be expected to provide helpful
feedback.

In order to land, a pull request needs to be reviewed and approved by at least
one maintainer and pass CI. After that, if there are no objections from other
contributors, the pull request can be merged.

Congratulations and thanks for your contribution!


File: license.md

The MIT License (MIT)

Copyright (c) 2023 Vercel, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


File: package.json

{
"name": "serve",
"version": "14.2.6",
"description": "Static file serving and directory listing",
"keywords": [
"vercel",
"serve",
"micro",
"http-server"
],
"repository": "vercel/serve",
"license": "MIT",
"type": "module",
"bin": {
"serve": "./build/main.js"
},
"files": [
"build/"
],
"engines": {
"node": ">= 14"
},
"scripts": {
"develop": "tsx watch ./source/main.ts",
"start": "node ./build/main.js",
"compile": "tsup ./source/main.ts",
"test:tsc": "tsc --project tsconfig.json",
"test:unit": "vitest run --config config/vitest.ts",
"test:watch": "vitest watch --config config/vitest.ts",
"test": "pnpm test:tsc && pnpm test:unit",
"lint:code": "eslint --max-warnings 0 source//.ts",
"lint:style": "prettier --check --ignore-path .gitignore .",
"lint": "pnpm lint:code && pnpm lint:style",
"format": "prettier --write --ignore-path .gitignore .",
"prepare": "husky install config/husky && pnpm compile",
"changeset": "changeset",
"version-packages": "changeset version",
"release": "pnpm compile && changeset publish"
},
"dependencies": {
"@zeit/schemas": "2.36.0",
"ajv": "8.18.0",
"arg": "5.0.2",
"boxen": "7.0.0",
"chalk": "5.0.1",
"chalk-template": "0.4.0",
"compression": "1.8.1",
"is-port-reachable": "4.0.0",
"serve-handler": "6.1.7",
"tinyclip": "^0.1.12",
"update-check": "1.5.4"
},
"devDependencies": {
"@changesets/cli": "2.29.6",
"@types/compression": "1.7.2",
"@types/serve-handler": "6.1.1",
"@vercel/style-guide": "3.0.0",
"@vitest/coverage-v8": "2.1.3",
"eslint": "8.19.0",
"got": "12.1.0",
"husky": "8.0.1",
"lint-staged": "13.0.3",
"prettier": "2.7.1",
"tsup": "8.3.0",
"tsx": "4.19.1",
"typescript": "5.6.3",
"vitest": "2.1.3"
},
"tsup": {
"target": "esnext",
"format": [
"esm"
],
"outDir": "./build/"
},
"prettier": "@vercel/style-guide/prettier",
"eslintConfig": {
"extends": [
"./node_modules/@vercel/style-guide/eslint/node.js",
"./node_modules/@vercel/style-guide/eslint/typescript.js"
],
"parserOptions": {
"project": "tsconfig.json"
}
},
"lint-staged": {
"
": [
"prettier --ignore-unknown --write"
],
"source/
/*.ts": [
"eslint --max-warnings 0 --fix",
"vitest related --run"
],
"tests": [
"vitest --run"
]
},
"packageManager": "[email protected]+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319"
}


File: pnpm-workspace.yaml

allowBuilds:
core-js-pure: true
esbuild: true
minimumReleaseAge: 2880


File: tsconfig.json

{
"extends": "@vercel/style-guide/typescript",
"compilerOptions": {
"lib": ["es2020"],
"target": "es2020",
"module": "esnext",
"moduleResolution": "node",
"noEmit": true,
"resolveJsonModule": true
},
"include": ["source/"]
}


File: tests/__fixtures__/config/custom/config.json

{
"public": "app/",
"renderSingle": true
}


File: tests/__fixtures__/config/deprecated/package.json

{
"static": {
"public": "app/"
}
}


File: tests/__fixtures__/config/invalid/serve.json

{
"symlink": ["app/"]
}


File: tests/__fixtures__/config/valid/serve.json

{
"public": "app/",
"renderSingle": true
}


File: tests/__fixtures__/server/serve.json

{
"public": "app/",
"renderSingle": true
}


File: tests/__fixtures__/server/ssl/serve.json

{
"public": "app/",
"renderSingle": true
}


File: .changeset/clipboardy-to-tinyclip.md


'serve': patch

Replace clipboardy with tinyclip


File: .changeset/config.json

{
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": [],
"snapshot": {
"useCalculatedVersion": true
}
}


File: .github/ISSUE_TEMPLATE/bug_report.yaml

name: Report a bug
labels: [bug]
body:

  • type: markdown
    attributes:
    value: |
    # Thanks for reporting this bug!

    Help us replicate and find a fix for the issue by filling in this form.
  • type: textarea
    attributes:
    label: Description
    Describe the issue and how to replicate it. If possible, please include
    a minimal example to reproduce the issue.

    validations:
    required: true
  • type: input
    attributes:
    label: Library version
    Output of the serve --version command

    validations:
    required: true
  • type: input
    attributes:
    label: Node version
    validations:
    required: true

File: .github/ISSUE_TEMPLATE/feature_request.yaml

name: Suggest an improvement or new feature
labels: [enhancement]
body:

  • type: markdown
    attributes:
    value: |
    # Thanks for filing this feature request!

    Help us understanding this feature and the need for it better by filling in this form.
  • type: textarea
    attributes:
    label: Description
    validations:
    required: true
  • type: textarea
    attributes:
    label: Why
    validations:
    required: true
  • type: textarea
    attributes:
    label: Alternatives
    validations:
    required: true

File: .github/PULL_REQUEST_TEMPLATE/default.md

Description

Added

Changed

Removed

Caveats/Problems/Issues

Checklist

  • The issues that this PR fixes/closes have been mentioned above.
  • What this PR adds/changes/removes has been explained.
  • All tests (pnpm test) pass.
  • The linter (pnpm lint) does not throw an errors.
  • All added/modified code has been commented, and
    methods/classes/constants/types have been annotated with TSDoc comments.

File: .github/workflows/ci.yaml

.github/workflows/ci.yaml

Lints and tests the server every time a commit is pushed to the remote

repository.

name: CI
on: [push, pull_request]
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v4
- name: Setup PNPM
uses: pnpm/action-setup@v4
- name: Setup Node 22
uses: actions/setup-node@v4
with:
node-version: 22
registry-url: 'https://registry.npmjs.org/'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Check for errors in code/formatting
run: pnpm lint
test:
name: Test
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v4
- name: Setup PNPM
uses: pnpm/action-setup@v4
- name: Setup Node 22
uses: actions/setup-node@v4
with:
node-version: 22
registry-url: 'https://registry.npmjs.org/'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Run all tests
run: pnpm test


File: .github/workflows/release-snapshot.yaml

name: Release Snapshot

env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}

on:
workflow_dispatch:

jobs:
release-snapshot:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v4
- name: Setup PNPM
uses: pnpm/action-setup@v4
- name: Setup Node 22
uses: actions/setup-node@v4
with:
node-version: 22
registry-url: 'https://registry.npmjs.org/'
cache: 'pnpm'
- name: Add npm auth token to pnpm
run: pnpm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN_ELEVATED}"
env:
NPM_TOKEN_ELEVATED: ${{secrets.NPM_TOKEN_ELEVATED}}
- name: Install dependencies
run: pnpm install
- name: Add SHORT_SHA env property with commit short sha
run: echo "SHORT_SHA=echo ${{ github.sha }} | cut -c1-8" >> $GITHUB_ENV
- name: Version Packages
run: pnpm changeset version --snapshot ${SHORT_SHA}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN_ELEVATED }}
- name: Compile
run: pnpm compile
- name: Publish Snapshot Release
run: pnpm changeset publish --no-git-tag --tag snapshot
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN_ELEVATED }}


File: .github/workflows/release.yaml

name: Release

on:
push:
branches:
- main

concurrency: ${{ github.workflow }}-${{ github.ref }}

jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v4
- name: Setup PNPM
uses: pnpm/action-setup@v4
- name: Setup Node 22
uses: actions/setup-node@v4
with:
node-version: 22
registry-url: 'https://registry.npmjs.org/'
cache: 'pnpm'
- name: Add npm auth token to pnpm
run: pnpm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN_ELEVATED}"
env:
NPM_TOKEN_ELEVATED: ${{secrets.NPM_TOKEN_ELEVATED}}
- name: Install dependencies
run: pnpm install
- name: Compile
run: pnpm compile
- name: Run all tests
run: pnpm test
- name: Create Release Pull Request or Publish to npm
id: changesets
uses: changesets/action@v1
with:
publish: pnpm release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN_ELEVATED }}