Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V4 #51

Merged
merged 14 commits into from
May 18, 2020
Merged

V4 #51

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
*.pem
*.crt

.DS_Store
.DS_Store
node_modules
40 changes: 29 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,35 @@

> A dependency free dev server for modern web application development

The new and enhanced version of [http-server-spa](https://npmjs.com/http-server-spa). A very compact but capable static file server with https, live reloading, gzip and other useful features to support web app development on localhost and over a local network.
A very compact but capable static file server with https, live reloading, gzip and other useful features to support modern web app development on localhost and over a local network. The motivation here was to write a package from the ground up with no dependencies; using only native, node and browser APIs to do some specific tasks with minimal code.

Servør can be invoked via the command line or programmatically using the node API.

**Quickstart Example**

The following command instructs servør to; clone [perflink](https://github.com/lukejacksonn/perflink), start a server at the project root, open the url in a browser, open the source code in an editor and reload the browser when files change.

```s
npx servor gh:lukejacksonn/perflink --browse --editor --reload
```

Most features are disabled by default but you can customize behaviour by passing positional arguments and flags to enable features.

<hr>

<img src="https://user-images.githubusercontent.com/1457604/68399629-979e8480-016e-11ea-89b3-0f852a018042.gif" alt="servor" width="800">

## Features

The motivation here was to write a package from the ground up with no dependencies; using only native node and browser APIs to do a specific task with minimal code.

- 🗂 Serves static content like scripts, styles, images from a given directory
- 🗜 Uses gzip on common filetypes like html, css and js to give a production feel
- ♻️ Reloads the browser when project files get added, removed or modified
- 🗜 Uses gzip on common filetypes like html, css, js and json
- 🔐 Supports https and http2 with trusted self signed certificates
- 🖥 Redirects all path requests to a single file for frontend routing
- 🔎 Discovers freely available ports to serve on if no port is specified
- 📦 Accepts both HTML and JavaScript files as the root file for a directory
- 🔎 Discovers freely available ports to start if the default is in use
- 📄 Renders directory listing for urls ending with a trailing slash
- 🗃 Opens browser tab and code editor to streamline quick start

## CLI Usage

Expand All @@ -29,6 +40,8 @@ Run as a terminal command without adding it as a dependency using `npx`:
npx servor <root> <fallback> <port>
```

> You can pass a GitHub repo as `<root>` using the syntax `gh:<user>/<repository>`

- `<root>` path to serve static files from (defaults to current directory `.`)
- `<fallback>` the file served for all non-file requests (defaults to `index.html`)
- `<port>` what port you want to serve the files from (defaults to `8080`)
Expand All @@ -38,14 +51,17 @@ Optional flags passed as non-positional arguments:
- `--browse` causes the browser to open when the server starts
- `--reload` causes the browser to reload when files change
- `--secure` starts the server with https using generated credentials
- `--silent` prevents the node process from logging to stdout
- `--silent` prevents the server node process from logging to stdout
- `--module` causes the server to wrap the root in script type module tags
- `--static` causes the server to route nested index files if they exist
- `--editor` opens a code editor (currently only vscode) at the project root

Example usage with npm scripts in a `package.json` file after running `npm i servor -D`:

```json
{
"devDependencies": {
"servor": "3.1.0"
"servor": "4.0.0"
},
"scripts": {
"start": "servor www index.html 8080 --reload --browse"
Expand All @@ -55,7 +71,7 @@ Example usage with npm scripts in a `package.json` file after running `npm i ser

### Generating Credentials

> NOTE: This process depends on the `openssl` command existing (tested on macOS only)
> NOTE: This process depends on the `openssl` command existing (tested on macOS and linux only)

The files `servor.crt` and `servor.key` need to exist for the server to start using https. If the files do not exist when the `--secure` flag is passed, then [`certify.sh`](/certify.sh) is invoked which:

Expand Down Expand Up @@ -86,10 +102,12 @@ const servor = require('servor');
const instance = await servor({
root: '.',
fallback: 'index.html',
port: 8080,
module: false,
static: false,
reload: false,
inject: ''
credentials: {},
credentials: null,
port: 8080,
});
```

Expand All @@ -101,7 +119,7 @@ const { url, root, protocol, port, ips } = await servor(config);

### Inject

The `inject` property accepts a string that gets prepended to the servers root document (which is `index.html` by default). This could be used to inject config or extend the development servers behavior and capabilities to suit specific environments.
The `inject` property accepts a string that gets appended to the servers root document (which is `index.html` by default). This could be used to inject config or extend the development servers behavior and capabilities to suit specific environments.

```js
const config = require('package.json');
Expand Down
6 changes: 3 additions & 3 deletions certify.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fi

# Generate Certificate Authority
openssl genrsa -out "tmp/${name}CA.key" 2048 &>/dev/null
openssl req -x509 -config ca.conf -new -nodes -key "tmp/${name}CA.key" -sha256 -days 1825 -out "${name}CA.pem" &>/dev/null
openssl req -x509 -config utils/ca.conf -new -nodes -key "tmp/${name}CA.key" -sha256 -days 1825 -out "${name}CA.pem" &>/dev/null

# This is the part that demands root privileges
if [ "$EUID" -eq 0 ] ; then
Expand All @@ -33,10 +33,10 @@ fi

# Generate CA-signed Certificate
openssl genrsa -out "${name}.key" 2048 &>/dev/null
openssl req -new -config ca.conf -key "${name}.key" -out "tmp/${name}.csr" &>/dev/null
openssl req -new -config utils/ca.conf -key "${name}.key" -out "tmp/${name}.csr" &>/dev/null

# Generate SSL Certificate
openssl x509 -req -in "tmp/${name}.csr" -CA "${name}CA.pem" -CAkey "tmp/${name}CA.key" -CAcreateserial -out "${name}.crt" -days 1825 -sha256 -extfile ssl.conf &>/dev/null
openssl x509 -req -in "tmp/${name}.csr" -CA "${name}CA.pem" -CAkey "tmp/${name}CA.key" -CAcreateserial -out "${name}.crt" -days 1825 -sha256 -extfile utils/ssl.conf &>/dev/null

# Cleanup files
rm servorCA.pem servorCA.srl
Expand Down
35 changes: 32 additions & 3 deletions cli.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env node
const fs = require('fs');
const servor = require('./servor.js');
const openBrowser = require('./utils/openBrowser.js');

const readCredentials = () => ({
cert: fs.readFileSync(__dirname + '/servor.crt'),
Expand All @@ -24,6 +25,33 @@ const open =
const admin = process.getuid && process.getuid() === 0;
let credentials;

if (args[0] && args[0].startsWith('gh:')) {
const repo = args[0].replace('gh:', '');
const dest = repo.split('/')[1];
if (!fs.existsSync(dest)) {
try {
require('child_process').execSync(
`git clone https://github.com/${repo}`,
{ stdio: 'ignore' }
);
} catch (e) {
console.log(
`\n ⚠️ Could not clone from https://github.com/${repo}\n`
);
process.exit();
}
}
args[0] = dest;
}

if (~process.argv.indexOf('--editor')) {
try {
require('child_process').execSync(`code ${args[0]}`);
} catch (e) {
console.log(`\n ⚠️ Could not open code editor for ${args[0]}`);
}
}

// Generate ssl certificates

if (~process.argv.indexOf('--secure')) {
Expand All @@ -37,7 +65,7 @@ const open =
credentials = readCredentials();
} catch (e) {
console.log(
' ⚠️ There was a problem generating ssl credentials. Try removing `--secure`'
'\n ⚠️ There was a problem generating ssl credentials. Try removing `--secure`\n'
);
process.exit();
}
Expand All @@ -51,6 +79,8 @@ const open =
fallback: args[1],
port: args[2],
reload: !!~process.argv.indexOf('--reload'),
module: !!~process.argv.indexOf('--module'),
static: !!~process.argv.indexOf('--static'),
credentials,
});

Expand All @@ -65,6 +95,5 @@ const open =

// Browser the server index

!!~process.argv.indexOf('--browse') &&
require('child_process').execSync(`${open} ${url}`);
!!~process.argv.indexOf('--browse') && openBrowser(url);
})();
18 changes: 10 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
{
"name": "servor",
"version": "3.3.1",
"version": "4.0.0",
"description": "A dependency free dev server for single page app development",
"repository": "lukejacksonn/servor",
"main": "./servor.js",
"bin": {
"servor": "./cli.js"
},
"keywords": [
"development",
"server",
"node",
"spa",
"reload"
"https",
"livereload",
"spa"
],
"scripts": {
"start": "sudo node cli tests/example --reload --browse --secure --static --module",
"cleanup": "rm -f servor.key servor.crt",
"test": "node cli test --browse --reload",
"test:secure": "yarn test --secure"
"test": "npm run cleanup && cd tests && node index.js"
},
"author": "Luke Jackson <lukejacksonn@gmail.com>",
"license": "MIT"
"license": "MIT",
"devDependencies": {
"puppeteer": "^3.0.4"
}
}
Loading