npm package: @quikdev/js
Description: A build and test utility for JavaScript libraries.
Author: Corey Butler
Latest version: 1.0.0-beta.7

# Quikdev-JS Library Development Utility

> _To build web **applications** with JavaScript, use [Quikdev-Web](https://github.com/quikdev/web) instead._

Quikdev-JS is a build tool and test runner for developers who create JavaScript **libraries** for multiple runtimes. This primarily (but not exclusively) caters to [ES Module](https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/) libraries.

_Supported Runtimes:_

- Node.js
- Deno
- Chromium (V8)
- Firefox (SpiderMonkey)
- Safari (JavaScriptCore)

Quikdev-JS itself is designed to be used in a Node.js working environment. It is an npm/CLI tool that can easily be used in npm scripts to automate build and test processes.

Behind the scenes, Quikdev-JS uses [esbuild](https://esbuild.io) to bundle/build JavaScript. It configures and launches temporary Docker containers for testing, assuring tests run in an isolated environment. Browser-based runtimes leverage Microsoft's [Playwright](https://playwright.dev/) container to simulate browser environments.

## Requirements

- [Docker Desktop](https://www.docker.com/products/docker-desktop/) (or just the Docker daemon on servers)
- [Node.js](https://nodejs.org) 16+

These tools are readily accessbile in Github Actions.

## Example Output

**Build**
```sh
quikdev-js build --pack --external crypto --external os --outdir ./.dist/@ngnjs/libcrypto
```
<img width="536" alt="image" src="https://user-images.githubusercontent.com/770982/195740467-0b68343a-eee4-4567-a894-c8cedd108247.png">

**Example Test Output:**

```bash
quikdev-js test --platform deno --verbose --output pretty --external crypto --external os --sourcemap --entry ./tests
```
<img width="666" alt="image" src="https://user-images.githubusercontent.com/770982/195740685-e16a463b-10af-429e-ac10-ff146b4b49de.png">

_(pretty results)_

<img width="650" alt="image" src="https://user-images.githubusercontent.com/770982/195740756-0302ee04-9ea1-4967-ad43-412242b539e2.png">

## Setup

Add Quikdev-JS to your project: `npm install @quikdev/js --save-dev`.

In the project's `package.json` file, add scripts to automate your build and test processes. For example:

```javascript
{
  "scripts": {
    "build": "quikdev-ds build --outdir dist/@myorg/mylibrary",
    "test": "npm run build && quikdev-js test --platform node@18.0.0 --platform deno --output pretty --entry ./tests"
  }
}
```

Using the configuration above, running `npm run build` will bundle the library into a directory called `dist/@myorg/mylibrary`. By default, the entry point (i.e. main file to bundle) will be extracted from `package.json`. There are several flags available to configure the output (described later in this document).

Running `npm test` (or `npm run test`) first runs the build process, then launches the tests found in the `./tests` directory. Two runtimes (Node.js v18.0.0 and Deno's latest version) are specified, so the tests will be run in both of these runtimes.

**Global CLI**

It is also possible to install Quikdev-JS globally: `npm install -g @quikdev/js`. This will make the `quikdev-js` command (and `qdjs` alias) available for use from a terminal/console window.

## Usage (CLI Documentation)

```bash
quikdev-js [COMMAND]

  A build and test utility for JavaScript libraries.

Commands:

  build               build the library
  test                build the library and run tests
```

### `quikdev-js build`

```bash
quikdev-js build [FLAGS]

  build the library

Flags:

  --aliases       [-a]        map import names to file paths | example: -a
                              "mymodule:/path/to/entry.js" Can be used multiple
                              times.
  --displayexports[-de]
  --entry         [-in,       display bundle's generated exports in the results
                              the entry point/source file (Default: ./src/index.
                  -source]    js)
  --outdir        [-out, -o]  the output directory (Default: ./.dist)
  --minify        [-m]        minify output
  --sourcemap     [-map]      generate sourcemaps
                              external libraries to ignore in build Can be used
  --external      [-e]        multiple times.
                              embed library in the build Can be used multiple
  --embed         [-i]        times.
                              bundle output format Options: esm, iife, cjs. (
  --format                    Default: esm)
                              configuration attribute in package.json file (
  --config        [-c, -cfg]  Default: quikdev-js)
                              platform to run the test on - this can be node,
                              deno, or browser. The specific version can be
                              specified using @ syntax, such as node@18, node@18.
                              0, node@18.0.0, node@lts, node@latest, or
                              node@current; all of which correspond to Docker
                              containers. Can be used multiple times. (Default:
  --platform      [-p]        node@lts)
                              environment variable to pass to build/test process.
                              ex: --env myvar=value or --env DEBUG. If no value
                              is specified, the value of the host environment
                              variable of that same name will be used. Can be
  --env                       used multiple times.
                              replace a string. ex: --replace "string=newvalue"
  --replace       [-r]        Can be used multiple times.
                              the output type Options: pretty, tap. (Default:
  --output                    pretty)
  --verbose       [-v]        verbose output (displays docker commands)
                              forcibly stop processing after this duration is
  --timeout       [-to]       exceeded (milliseconds) (Default: 60000)
                              mount a directory or file to the test image - ex:
                              -v "/path/to/dir:/mapped/dir" Can be used multiple
  --volumes       [-v]        times.
                              the type of documentation to produce Options: md,
                              markdown, json. Can be used multiple times. (
  --type          [-t]        Default: md)
```

### `quikdev-js test`

```bash
quikdev-js test [FLAGS]

  build the library and run tests

Flags:

  --aliases       [-a]        map import names to file paths | example: -a
                              "mymodule:/path/to/entry.js" Can be used multiple
                              times.
  --displayexports[-de]
  --entry         [-in,       display bundle's generated exports in the results
                              the entry point/source file (Default: ./src/index.
                  -source]    js)
  --outdir        [-out, -o]  the output directory (Default: ./.dist)
  --minify        [-m]        minify output
  --sourcemap     [-map]      generate sourcemaps
                              external libraries to ignore in build Can be used
  --external      [-e]        multiple times.
                              embed library in the build Can be used multiple
  --embed         [-i]        times.
                              bundle output format Options: esm, iife, cjs. (
  --format                    Default: esm)
                              configuration attribute in package.json file (
  --config        [-c, -cfg]  Default: quikdev-js)
                              platform to run the test on - this can be node,
                              deno, or browser. The specific version can be
                              specified using @ syntax, such as node@18, node@18.
                              0, node@18.0.0, node@lts, node@latest, or
                              node@current; all of which correspond to Docker
                              containers. Can be used multiple times. (Default:
  --platform      [-p]        node@lts)
                              environment variable to pass to build/test process.
                              ex: --env myvar=value or --env DEBUG. If no value
                              is specified, the value of the host environment
                              variable of that same name will be used. Can be
  --env                       used multiple times.
                              replace a string. ex: --replace "string=newvalue"
  --replace       [-r]        Can be used multiple times.
                              the output type Options: pretty, tap. (Default:
  --output                    pretty)
  --verbose       [-v]        verbose output (displays docker commands)
                              forcibly stop processing after this duration is
  --timeout       [-to]       exceeded (milliseconds) (Default: 60000)
                              mount a directory or file to the test image - ex:
                              -v "/path/to/dir:/mapped/dir" Can be used multiple
  --volumes       [-v]        times.
                              the type of documentation to produce Options: md,
                              markdown, json. Can be used multiple times. (
  --type          [-t]        Default: md)
```

### Flags/Arguments

|Flag|Purpose|Examples|
|-|-|-|
|***aliases** [-a]|Map aliases. This helps the build tool identify where other code sources can be found.| -a&nbsp;"chalk:./node_modules/chalk/index.js"</br>-a&nbsp;"mod:/path/to/entry.js"|
|**displayexports** [-de]|Displays the exported elements on the console during the build process.|
|**entry** [-in,-source]|The main file to bundle. If this is not specified, the entrypoint is retrieved from `package.json`. If no package.json file is available, Quikdev will attempt to locate an `index.js` file.| -in ./src/index.js|
|**outdir** [-out,-o]|The location where output will be written to.|-o /.dist|
|**minify** [-m]|Minify the bundle.|--minify|
|**sourcemap** [-map]|Produce sourcemaps (only applicable when minification is enabled.|--sourcemap|
|***external** [-e]|Ignore modules, treating them as runtime dependencies/externally loaded.|--external fs|
|***embed** [-i]|Embed a library in the build (i.e. include it, even if it is an external library)| --embed /path/to/module.js|
|**format**|The output format.| - `esm`: ECMAScript Module (default/recommended)<br/>- `iife`: Immediately invoked function expression<br/>- `cjs`: CommonJS|
|**config** [-c,-cfg]|This specifies an attribute in a `package.json` file containing a Quikdev-JS configuration|_See configuration section below_|
|***platform** [-p]|Specify which platform/runtime to run tests in|--platform node<br/>--platform node@18.0.0<br/>--platform node@18.0<br/>--platform node@18<br/>See below for more options.|
|***env**|Specify environment variables to pass to the build/test process. When an environment variable is specified with no value, the local computer's value for that variable will be passed through to the build/test process.|--env myvar=value<br/>--env DEBUG|
|***replace** [-r]|Find/replace values in the code. Package.json attributes can also be specified, such as `package.version`, which will use the value of the package.json `version` attribute.|--replace "string=newvalue"<br/>--replace "myversion=package.version"|
|**output**|Output types for test results. Valid options include `pretty` and `tap`. The `pretty` option outputs tap-spec results||
|**verbose** [-v]|Display the Docker command used to launch the environment.||
|**timeout** [-to]|Forcibly stop processing after the specified duration. Defined in milliseconds|-to 60000 (one minute)|
|***volumes** [-v]|Map directories (volumes) to the build/test process.|-v "/path/to/dir:/mapped/dir"|
|**package** [-pack]|Package for npm. Copy `package.json`, `README.md`, `LICENSE.md` (or `LICENSE`), and `.npmignore` to the output directory. All files except `package.json` are skipped if they do not exist.||

_*Flag can be specified multiple times._

## Configuring Flags Automatically With `package.json`

If a `package.json` file is available, Quikdev-JS can automatically extract configuration properties from it.

For example:

```js
{
  "name": "@my/lib",
  "version": "1.0.1",
  "type": "module",
  "main": "./src/index.js",
  "exports": {
    ".": {
      "import": "./index.js"
    },
  },
  "scripts": {
    "build": "quikdev-ds build --outdir dist/@myorg/mylibrary",
    "test": "npm run build && quikdev-js test --platform node@18.0.0 --platform deno --output pretty --entry ./tests"
  },
  "quikdev-js": {
    "replace": {
      "<#REPLACE_VERSION#>": "package.version"
    },
    "alias": {
      "ngn": "./node_modules/ngn/index.js",
      "rfc4648": "./node_modules/rfc4648/lib/index.mjs"
    },
    "embed": [
      "tappedout"
    ]
  }
}
```

Notice the `quikdev-js` attribute. It contains several Quikdev-JS flags that will be applied to any quikdev command.

For example, running **`npm test`** would first run the Quikdev-JS build process as:

```bash
quikdev-ds build \
  --replace "<#REPLACE_VERSION#>=package.version" \
  --alias "ngn:./node_modules/ngn/index.js" \
  --alias "rfc4648:./node_modules/rfc4648/lib/index.mjs" \
  --embed tappedout
  --outdir dist/@myorg/mylibrary
```

Remember, `package.<attribute>` will be replaced with the corresponding package.json value, so the command above will actually work like:

```bash
quikdev-ds build \
  --replace "<#REPLACE_VERSION#>=1.0.1" \
  --alias "ngn:./node_modules/ngn/index.js" \
  --alias "rfc4648:./node_modules/rfc4648/lib/index.mjs" \
  --embed tappedout
  --outdir dist/@myorg/mylibrary
```

Once the build is complete, the remaining command would be executed as the equivalent of:

```bash
quikdev-js test \
  --replace "<#REPLACE_VERSION#>=1.0.1" \
  --alias "ngn:./node_modules/ngn/index.js" \
  --alias "rfc4648:./node_modules/rfc4648/lib/index.mjs" \
  --embed tappedout
  --platform node@18.0.0 \
  --platform deno \
  --output pretty \
  --entry ./tests
  --outdir ./.dist
```

This command will first launch a Node.js 18.0.0 Docker container, running the code found in `./.dist`. It repeats the same process in a Deno container.

## Unit Tests

This tool supports [TAP (Test Anything Protocol)](https://testanything.org/) output. Any test runner capable of outputting TAP output is supported, but the author's of this tool also created [tappedout](https://github.com/coreybutler/tappedout), a cross-runtime test runner that requires no special transpilation (works in all runtimes, including Node, Deno, and browsers). Naturally, we recommend using it.

# Roadmap/Wishlist

This tool currently has an experimental documentation feature for producing markdown docs for a library. It is very limited in its current state. We hope to produce a more robust documentation generator capable of markdown and JSON output.

- Test Coverage Reports
- File Size Reports
- Better ESLint Support