Bundling and minification toolset for Deno
Preface
🦕📦 denopack is a CLI tool and a collection of plugins that for bundling Typescript code to be used with Deno or in the browser. This library uses the browser versions of Rollup (bundling) and Terser (compression/minification).
This library is made for Deno and is thus fully usable in Deno as a package or as a CLI app with
deno install
. No node_modules, npm/yarn scripts, etc are needed.
Contents
Goals
There is absolutely nothing wrong with deno bundle
, but in its current state it is missing several features that are present in the NodeJS ecosystem. The goal is to provide an alternative bundling method that can - together with a plugin system, extending functionality - provide several key wishlist features without turning to Node:
- Tree shaking comes built-in with Rollup
- Minification by the usage of the Terser plugin
- Source Maps (should also come built-in with Rollup, coming soon)
- Lock file support, checking checksums from the lockfile against loaded code
- File watching (pretty sure this can be implemented, coming soon)
More to come, also see the deno bundle
roadmap/wishlist over at denoland/deno/issues/4549
CLI
Installation
deno install --unstable --allow-read --allow-write --allow-env --allow-net -n denopack https://cdn.jsdelivr.net/gh/denofn/denopack@latest/cli.ts
eggs install --unstable --allow-read --allow-write --allow-env --allow-net -n denopack https://x.nest.land/denopack@0.3.0/cli.ts
NOTE: denopack uses unstable Deno APIs. These APIs are not final and may break, but this does mean --unstable
is mandatory!
Usage
Usage:
$ denopack -i mod.ts
Options:
-v, --version Display version number
-i, --input <pathToFile> The input file (most likely mod.ts)
-o, --output [pathToFile] The output file name
-d, --dir [pathToDir] The output directory
-c, --config [pathToConfig] The config file. Use --defaultConfig for default values
-p, --print Prints the generated bundle to stdout
--defaultConfig Prints the default config to stdout
-h, --help Display this message
Examples:
denopack -i mod.ts
denopack -i mod.ts -o bundle.js
denopack -i mod.ts --dir dist
denopack -c denopack.config.ts
denopack -i mod.ts -o out.js --dir dist -c denopack.config.ts
Usage with script runners
In case you don’t want to globally install denopack, but want to use it locally with script runners: this is absolutely, totally possible since denopack uses 0 NodeJS specific code!
Script runners that should work out-of-the-box:
# example
scripts:
start: deno run --unstable --allow-read --allow-write https://cdn.jsdelivr.net/gh/denofn/denopack@latest/cli.ts
vr run start -i mod.ts -o bundle.js
#example
scripts:
start:
file: https://cdn.jsdelivr.net/gh/denofn/denopack@latest/cli.ts
deno_options:
allow-read: true
allow-write: true
unstable: true
denox run start -i mod.ts -o bundle.js
{
"config": {
"start": "--unstable --allow-read --allow-write https://cdn.jsdelivr.net/gh/denofn/denopack@latest/cli.ts -i mod.ts -o bundle.js"
}
}
Commands start
Permissions
NOTE: both denopack and its plugins use unstable Deno APIs. These APIs are not final and may break, but this does mean --unstable
is mandatory!
The CLI itself can run with a base permission of --allow-read
, printing to stdout with the -p
flag. Writing to file naturally requires --allow-write
.
Additionally, the various built-in plugins can require extra permissions like --allow-net
and --allow-env
. More info can be found here.
Config file
Importing a Rollup config file is supported using the -c <path/to/config>
flag and follow the same conventions as Rollup:
- use default export for your config
- ideally call it
rollup.config.ts
ordenopack.config.ts
Plugins
Since the bundling logic - aside file system/network access - is handled by Rollup, the remaining core functionality of denopack is based around plugins that use Deno APIs for key features.
A list of included plugins and a collection of strategies are included in the plugin directory. Documentation from Rollup regarding plugins is available on their docs site.
Usage
If you only need plugins or hooks - for example to create a config file - you can import straight from the mod.ts
in the plugin directory.
import /* whatever plugins/hooks are needed */ "https://cdn.jsdelivr.net/gh/denofn/denopack@latest/plugin/mod.ts";
export default {
file: "mod.ts",
plugins: [
/* whatever plugins or hooks were imported */
],
};
Usage without CLI
If you want to handle the building/bundling yourself, the toplevel mod.ts
also includes rollup
that exposes the Rollup Javascript API and several typings.
import {
rollup /* whatever plugins/hooks are needed */,
} from "https://cdn.jsdelivr.net/gh/denofn/denopack@latest/mod.ts";
import type { RollupOptions } from "https://cdn.jsdelivr.net/gh/denofn/denopack@latest/mod.ts";
Just like the CLI, you can use it out-of-the-box with deno run
or script runners like the ones mentioned up above.
Contributing
- If you are using vscode, install and enable the required extensions.
- If you are not using vscode, sort your imports and use the following prettier settings:
- semi: true
- singleQuote: false
- printWidth: 100
- trailingComma: “es5”
- tabWidth: 2
- useTabs: false
- If you are not using vscode, sort your imports and use the following prettier settings:
- Functions, constants and variables are always camelCase
- Classes are allowed to be PascalCase
- Extract shared code to util
- Code that is not a plugin or hook lives in cli
Contributing denopack plugins
Contributing a plugin to the denopack repo is not only extremely welcomed, it’s even encouraged. That does mean a few conventions are in order, extending from the existing Rollup conventions these are:
- Plugins should have a clear plugin name with a
denopack-plugin-
prefix - Plugin functions are always camelCased
- Plugins and their documentation should be stored in a separate folder inside the plugin directory
- Optionally also indicating what the most impactful action is (resolve, load, transform, …). The typescriptCompile plugin is an obvious exception, but do take a look at the naming of the other plugins
- Use async Deno APIs (readFile not readFileSync, etc.)
- Document your plugin in English and detail what flags are required! Here’s an example
Contributing denopack hooks
Contributing a hook follows the following conventions:
- Hooks start with the keyword use
- Hooks are always camelCased
- Hooks are stored inside of hooks.ts
- Hooks are always functions and always return an array of plugins
- Using plugins that accept configuration options in hooks should always be allowed to pass config down to that plugin
- Configuration options are stored in one object containing all configuration options, see hooks.ts for examples
Acknowledgements
- Reddit user u/HarmonicAscendant - unrelated to this library - who coined the name name Denopack
- The sauropod and package emoji’s courtesy of Twemoji