Bundlemonkey is a userscript bundler designed to make developing browser userscripts blazing fast and efficient.
npm install bundlemonkeyBundlemonkey is a userscript bundler designed to make developing browser userscripts blazing fast and efficient.
With TypeScript support and type-safe header comments, managing your code becomes a breeze.
Works well with Tampermonkey, Violentmonkey or Greasemonkey.
- Lightning-Fast Builds
Incredibly fast bundling speeds, thanks to esbuild.
- TypeScript Support
- Module Bundling
- Type-Safe Header Comments
Write userscript header metadata in a type-safe and straightforward way. This not only minimizes errors but also makes your code much more maintainable.
- Watch mode
#### source
``typescript
// src/sample/message.ts
export const message = "Hello from sample script and bundlemonkey!";
`
`typescript
// src/sample/index.user.ts
import { defineUserScript } from "bundlemonkey";
import { message } from "./message";
export default defineUserScript({
name: "Sample userscript",
version: "1.0.0",
description: "Write userscripts with ease using bundlemonkey!",
match: ["https://example.com/*"],
main: () => {
console.log(message);
},
});
`
#### output
`typescript
// ==UserScript==
// @name Sample userscript
// @version 1.0.0
// @description Write userscripts with ease using bundlemonkey!
// @match https://example.com/*
// ==/UserScript==
// src/sample/message.ts
var message = "Hello from sample script and bundlemonkey!";
// src/sample/index.user.ts
void (() => {
console.log(message);
})();
`
You can set up new project quickly using the template (1a), or do it manually (1b).
#### 1a. Use template
`bash
npx bundlemonkey --create
#### 1b. Setup manually
Install Bundlemonkey using npm, pnpm, or bun:
`bash
npm install --save bundlemonkeyor like
pnpm add bundlemonkey
bun add bundlemonkey
`Create a directory for your userscripts named with the slug under
src directory. Your project structure might look like this:
`bash
├── src/ # configurable
│ ├── script-a/
│ │ ├── index.user.ts
│ │ └── some-module.ts
│ └── script-b/
│ └── index.user.ts
├── dist/ # configurable
│ └── # bundled code goes here
├── bundlemonkey.config.ts # optional
└── package.json
`> [!TIP]
> Source scripts are collected by glob
src/*/index.user.{ts,js} by default, and srcDir is configurable.$3
Head into any of the source scripts (
index.user.ts or index.user.js) and start writing your code! See Define UserScript section for more details.$3
Run the following command to compile your code:
`bash
npx bundlemonkeyor like
pnpx bundlemonkey
bunx bundlemonkey
`Bundlemonkey compiles your code into
dist directory.Watch mode and Remote watch mode are supported as well, so you can have it rebuild your scripts automatically. See CLI docs below for more details.
Define Userscript
Each source script must define its main code, name, version, etc. using
defineUserScript and export it as the default export. It might look like:`typescript
import { defineUserScript } from "bundlemonkey";export default defineUserScript({
name: "Sample userscript",
version: "1.0.0",
description: "Write userscripts with ease using bundlemonkey!",
match: ["https://example.com/*"],
config: {
message: "hello!",
},
main: (config) => {
// your main code here!
console.log(config.message)
},
});
`$3
Please see docs of Tampermonkey or Violentmonkey for more details about props other than
config and main.✅ - required
name|type|default
:---|:---|:---
config|
T extends any
main ✅|(config: T) => unknown|---
name ✅|string|---
namespace|string|
copyright|string|
version ✅|string|---
description|string|
icon|string|
grant|Grant[] \| "none"|[]
author|string|
homepage|string|
antiFeature|AntiFeature[]|[]
require|string[]|[]
resource|{ name: string; url: string; }[]|[]
match|string[]|[]
excludeMatch|string[]|[]
include|string[]|[]
exclude|string[]|[]
runAt|RunAt|
runIn|string[]|[]
sandbox|"raw" \| "JavaScript" \| "DOM"|
injectInto|"page" \| "content" \| "auto"|
tag|string[]|[]
connect|string[]|[]
noframes|boolean|false
updateURL|string|
downloadURL|string|
supportURL|string|
unwrap|boolean|false
topLevelAwait|boolean|false#### Config
Config for the script which is intended to be modifiable by the users of your script.
If present, the value will be defined at the beginning of the compiled userscript as a variable named
userscriptConfig to make it easy for users to edit.For example:
`typescript
export default defineUserScript({
// ...
config: {
/**
* Edit this to change the message
* @type string
*/
message: "hello!"
},
main: (config) => {
window.alert(config.message);
},
});
`will be compiled into:
`typescript
// ==UserScript==
// ...
// ==/UserScript==var userscriptConfig = {
/**
* Edit this to change the message
* @type string
*/
message: "hello!"
};
void ((config) => {
window.alert(config.message);
})(userscriptConfig);
`#### Main
Your main userscript code.
It can be either a synchronous or an asynchronous function, and can receive config as a prop.
#### Grant
All APIs supported by Tampermonkey, Violentmonkey and Greasemonkey (
GM_, GM., unsafeWindow, window.onurlchange, window.close and window.focus) can be specified.`typescript
type Grant =
| "unsafeWindow"
| "GM_addElement"
| "GM_addStyle"
// ...
| "GM.addStyle"
| "GM.setValue"
// ...
| "window.onurlchange"
| "window.close"
| "window.focus";
`#### AntiFeature
`typescript
type AntiFeature = {
type: "ads" | "tracking" | "miner";
description: string;
};
`#### RunAt
`typescript
type RunAt =
| "document-end"
| "document-start"
| "document-body"
| "document-idle"
| "context-menu";
`Build Modes
$3
All source scripts will be compiled at once.
dist.production directory.$3
Bundlemonkey monitors edits to the source scripts. When an edit is detected, it compiles the source and copies the output to the clipboard.
Please paste and save it in your userscripts manager's editor for use.
dist.dev directory.$3
Similar to Watch mode, it monitors edits to the source scripts; however, in this mode, you do not need to paste into the editor every time you make changes.
When a source script is edited, a remote script will be copied to the clipboard only the first time. Once you paste and save this remote script in your userscripts manager's editor, subsequent edits to the source script will be automatically reflected.
You need to allow your userscript manager access to local files to use this mode. Please refer to Tampermonkey's FAQ for more details.
> [!TIP]
> A remote script is a plain userscript that simply
@requires the actual userscript code.CLI
`bash
bundlemonkey [--watch [--remote]] [--create]
`$3
Enable Watch mode.
$3
Use with
--watch to enable Remote watch mode.Configuration
If you need to customize Bundlemonkey’s behavior, you can create a configuration file named
bundlemonkey.config.ts or bundlemonkey.config.js in your project’s root directory.$3
bundlemonkey.config.ts`typescript
import type { Config } from "bundlemonkey";const config: Config = {
srcDir: "src", // default value
dist: {
dev: ".dev", // default value
production: "dist", // default value
},
defaultMeta: {
author: "John Doe",
namespace: "johndoe",
homepage: "https://github.com/johndoe/userscripts",
updateURL: ({ scriptName }) =>
https://github.com/johndoe/userscripts/raw/main/dist/${scriptName}.user.js,
downloadURL: ({ scriptName }) =>
https://github.com/johndoe/userscripts/raw/main/dist/${scriptName}.user.js,
},
};export default config;
`$3
- type:
string
- Default: "src"Directory where your source scripts are located.
> [!NOTE]
> The glob for collecting the source files is like:
$3
- type:
object#### dist.dev
- type:
string
- Default: ".dev"Dist directory in watch mode.
#### dist.production
- type:
string
- Default: "dist"$3
- type:
object
- Default: undefineddefineUserScript overrides this.defineUserScript can be used here as well, while updateURL/downloadURL have different signatures like below.#### defaultMeta.updateURL
- type:
(args: { scriptName: string; version: string }) => string
- Default: undefined#### defaultMeta.downloadURL
- type:
(args: { scriptName: string; version: string }) => string
- Default: undefined`