Skip to content

New template based on rollup and with extra boilerplate stuff #3

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

Merged
merged 4 commits into from
Apr 14, 2024
Merged
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
1 change: 1 addition & 0 deletions .build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"sizeKiB":8.09,"mode":"development","timestamp":1713129529244}
9 changes: 3 additions & 6 deletions .env.template
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
# whether to trigger a bell sound in the terminal when the build is finished - defaults to false if empty, invalid or unset
RING_BELL=false

# HTTP port of the dev server where the userscript will be served (when using `npm run watch`) - defaults to 8710 if empty, invalid (NaN or <1024) or unset
# HTTP port of the dev server where the userscript will be served (when using `npm run dev`) - defaults to 8710 if empty
DEV_SERVER_PORT=8710

# whether to log dev server requests to the console - defaults to false if empty, invalid or unset
DEV_SERVER_LOG=false
# Whether to trigger the bell sound in some terminals when the code has finished (re)compiling - default is false
RING_BELL=false
23 changes: 21 additions & 2 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ module.exports = {
},
ignorePatterns: [
"*.min.*",
"webpack.config.js",
"*.user.js",
"*.map",
"dist/**",
"test.ts",
],
extends: [
"eslint:recommended",
Expand All @@ -19,10 +19,15 @@ module.exports = {
Atomics: "readonly",
SharedArrayBuffer: "readonly",
GM: "readonly",
unsafeWindow: "writable",
},
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: "latest",
ecmaFeatures: {
jsx: true,
},
sourceType: "module",
},
plugins: [
"@typescript-eslint",
Expand All @@ -33,18 +38,32 @@ module.exports = {
"semi": [ "error", "always" ],
"eol-last": [ "error", "always" ],
"no-async-promise-executor": "off",
"no-cond-assign": "off",
"indent": ["error", 2, { "ignoredNodes": ["VariableDeclaration[declarations.length=0]"] }],
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unused-vars": ["warn", { "ignoreRestSiblings": true, "argsIgnorePattern": "^_" }],
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/ban-types": ["error", {
types: {
"{}": false,
},
extendDefaults: true,
}],
"@typescript-eslint/no-explicit-any": "off",
"comma-dangle": ["error", "only-multiline"],
"no-misleading-character-class": "off",
},
overrides: [
{
files: ["**.js"],
files: ["**.js", "**.mjs", "**.cjs"],
rules: {
"@typescript-eslint/no-var-requires": "off",
"quotes": [ "error", "double" ],
"semi": [ "error", "always" ],
"eol-last": [ "error", "always" ],
"no-async-promise-executor": "off",
"indent": ["error", 2, { "ignoredNodes": ["VariableDeclaration[declarations.length=0]"] }],
"comma-dangle": ["error", "only-multiline"],
},
},
],
Expand Down
26 changes: 14 additions & 12 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
name: "Lint"

on:
workflow_dispatch:
pull_request:
branches: [main] # runs on every push
branches: [main, develop]
push:
branches: [develop]

jobs:
lint:
name: Lint
runs-on: ubuntu-latest

timeout-minutes: 10
timeout-minutes: 5

strategy:
matrix:
node-version: [18.x]
node-version: [20.x]

env:
CI: "true"

steps:
- uses: actions/checkout@v3 # checkout latest commit
- name: Use Node.js ${{ matrix.node-version }} # set up Node.js
uses: actions/setup-node@v2
- uses: actions/checkout@v3
- name: Set up Node.js v${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Clean install of dependencies # runs the npm ci command to install all dependencies
- name: Install dependencies # runs the npm ci command to install from package-lock.json
run: npm ci
env:
CI: "true"
- name: Lint # runs ESLint
- name: Build with tsc & lint
run: npm run lint
env:
CI: "true"
8 changes: 2 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
.env
test.js
test.ts

node_modules/
dist/*.map
dist/out/
dist/*.css
dist/
!dist/*.user.js
10 changes: 10 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"recommendations": [
"andywang.vscode-scriptmonkey",
"dbaeumer.vscode-eslint",
"fabiospampinato.vscode-highlight",
],
"unwantedRecommendations": [
"adpyke.vscode-userscript",
],
}
47 changes: 47 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"javascript.preferences.importModuleSpecifier": "relative",
"typescript.tsdk": "node_modules/typescript/lib",

"search.exclude": {
"**/*.user.js": true,
},
"files.associations": {
"*.env": "dotenv",
"*.env.template": "dotenv",
},
"editor.tabSize": 2,

// requires extension: fabiospampinato.vscode-highlight
"highlight.regexes": {
"(TODO(\\((\\s|\\d|\\w|[,.-_+*&])+\\))?:?)": { // TODO: or TODO or TODO(xy): but not todo or todo:
"backgroundColor": "#ed0",
"color": "black",
"overviewRulerColor": "#ed0",
},
"((//\\s?)?#region ([^\\S\\r\\n]*[\\(\\)\\w,.\\-_&+#*'\"]+)*[:]*)": { //#region test (abc):
"backgroundColor": "#069",
"color": "#fff",
"overviewRulerColor": "#069",
},
"((<!--\\s*)?</?\\{\\{[A-Z_-]+\\}\\}>(\\s*-->)?)": { // <!-- <{{FOO}}> --> and <!-- </{{FOO}}> --> or <{{BAR}}> and </{{BAR}}>
"backgroundColor": "#9af",
"overviewRulerColor": "#9af",
"color": "#000",
},
"(#?(DEBUG|DBG)#?)": { // #DEBUG or DEBUG or #DBG or #DBG#
"backgroundColor": "#ff0",
"color": "blue",
"overviewRulerColor": "#ff0",
},
"(IMPORTANT:)": { // IMPORTANT:
"backgroundColor": "#a22",
"color": "#fff",
},
"(FIXME:)": { // FIXME:
"backgroundColor": "#a22",
"color": "#fff",
"overviewRulerColor": "#752020",
},
},
}

4 changes: 2 additions & 2 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004

Copyright (C) 2023 Sv443
Copyright (C) 2024 Sv443

Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
Expand All @@ -10,4 +10,4 @@ as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

0. You just DO WHAT THE FUCK YOU WANT TO.
0. You just DO WHAT THE FUCK YOU WANT TO.
110 changes: 92 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

<h1><img alt="icon" src="./assets/icon.png"><br>Userscript.ts</h1>

Typescript ESM template for making [userscripts](https://en.wikipedia.org/wiki/Userscript) that supports importing and parsing HTML, CSS, Markdown and misc. files directly in code, packing it all up with webpack and applying custom injections for the userscript header and more.
Extensive Typescript ESNext template and boilerplate for [userscripts](https://en.wikipedia.org/wiki/Userscript).
Supports importing and parsing HTML and Markdown files directly in code, packing it all up with rollup and applying custom injections for the userscript header and more.
It also offers ESLint to lint and auto-fix the code and GitHub Actions with ESLint to lint the code in pull requests and CodeQL to check it for vulnerabilities on every push.
Intended to be used in conjunction with a Git repo as a resource CDN and build versioning system for the userscript.

Like this template? Please consider [supporting the development ❤️](https://github.com/sponsors/Sv443)

Expand All @@ -24,26 +26,99 @@ Like this template? Please consider [supporting the development ❤️](https://

## First steps:
1. Copy `.env.template` to `.env` and change the values inside if needed
2. Inside `package.json`, update the properties `name`, `userscriptName`, `description`, `homepage`, `author`, `license` and `repository.url`
2. Search for `#REPLACE:` with your IDE in the entire project and replace all placeholders with your own values
3. Replace the icon at `assets/icon.png` with your own or use [Google's or DuckDuckGo's favicon API](https://codepen.io/djekl/pen/QWKNNjv) in the userscript header
4. Replace the LICENSE.txt file with your own license or remove it if you want your code to be "all rights reserved"
5. Modify the variables and userscript header inside `src/tools/post-build.ts` to whatever you need (see also [GM header reference](https://wiki.greasespot.net/Metadata_Block))
5. Modify the userscript header inside `src/tools/post-build.ts` to whatever you need (see also [GM header reference](https://wiki.greasespot.net/Metadata_Block))
6. The eslint configuration at `.eslintrc.cjs` is what I use, feel free to remove rules if there are too many or modify them to your preferences
7. Add your own initialization functions to `init()` and `onLoad()` inside the entrypoint file at `src/index.ts` (read the comments for more info)
8. Remove the example HTML, CSS and TS files
9. Refer to [commands](#commands) and [development](#development-tips-and-notes)
7. Add your own initialization functions to `init()` and `run()` inside the entrypoint file at `src/index.ts` (read the comments for more info)
8. Refer to the sections [project structure](#project-structure), [commands](#commands) and [development](#development-tips-and-notes) next

<br>

## Project structure:
- **`assets/`**
Contains all the assets that are used in the userscript, like images, stylesheets, and any other misc files.
- **`assets/require.json`**
Contains a list of all modules that should be loaded using the `@require` directive.
Props:
- `pkgName` (required) - The npm name of the package
- `baseUrl` - The base URL of the CDN to load from (defaults to `https://cdn.jsdelivr.net/npm/`)
- `path` - The path to the file inside the package (uses jsdelivr's standard path by default)
- **`assets/resources.json`**
Contains a list of all resources that should be loaded using the `@resource` directive.
This is useful for loading files like stylesheets, images, and other assets that should not be included in the code bundle, but loaded in and cached by the userscript extension.
The object's key is used with the `getResourceUrl()` function in `src/utils.ts` to get the URL of the resource. The value is the path to the file inside the `assets/` folder.
If the path starts with a slash, it will be resolved relative to the root of the project (where the `package.json` file is located).
- **`src/`**
Contains all the source files for the userscript.
- **`src/tools/`**
Contains all scripts that are used in the build process.
- **`src/tools/post-build.ts`**
Contains the post-build script that is run after the userscript is built.
This script inserts the userscript header and other custom injections into the final userscript file.
If you need to modify userscript directives or add custom injections, this is the place to do it.
- **`src/tools/serve.ts`**
Contains the development server that serves the userscript on port 8710 (by default).
- **`src/index.ts`**
The entrypoint for the userscript. This is where you should call your own code from.
- **`src/config.ts`**
This file contains the DataStore instance that should be used to hold your userscript's configuration object.
The DataStore class is really powerful and does a lot of the heavy lifting for you. More instances can also be created to hold different types of data that should be persisted between sessions.
For more info, please read the [DataStore documentation.](https://github.com/Sv443-Network/UserUtils#datastore)
- **`src/constants.ts`**
Contains some constant variables that are used throughout the userscript's runtime code.
This is where arguments are injected into the userscript's runtime code by `tools/post-build.ts`
- **`src/declarations.d.ts`**
The declarations in this file allow you to import HTML and MD files directly in your code, using rollup plugins.
- **`src/observers.ts`**
This file should be filled up with many `SelectorObserver` instances. These observe a designated part of the DOM for changes.
With the function `addSelectorListener()`, you can then add a listener, given a specific CSS selector, that gets called when the selector has been found in the DOM.
For more info, please read the [SelectorObserver documentation.](https://github.com/Sv443-Network/UserUtils#selectorobserver)
- **`src/types.ts`**
Contains all generic TypeScript types that are used in multiple files.
- **`src/utils.ts`**
Contains utility functions that are used throughout the userscript's runtime code.
This is where you should put functions that are used in multiple places in your code.
Once it gets too big you should split it up into multiple files.


<br>

## Commands:
| Command | Description |
| --- | --- |
| `npm i` | Run once to install dependencies |
| `npm run lint` | Lints the userscript with ESLint |
| `npm run build-dev` | Builds the userscript in development mode (sourcemaps enabled) |
| `npm run build-prod` | Builds the userscript in production mode (optimized code, sourcemaps disabled) |
| `npm run dev` | Watches, rebuilds and serves the userscript so it can be updated live ([more info below](#development-tips-and-notes)) |
<!-- first column uses non-breaking space U+00A0 (' ') -->
- **`npm i`**
Run once to install dependencies
- **`npm run dev`**
This is the command you want to use to locally develop and test your script.
It watches for any changes, then rebuilds and serves the userscript on port 8710, so it can be updated live if set up correctly in the userscript manager (see [development tips](#development-tips-and-notes)).
Once it has finished building, a link will be printed to the console. Open it to install the userscript.
You can also configure request logging and more in `.env` and `src/tools/serve.ts`, just make sure to restart the dev server after changing anything.
- **`npm run build-prod`**
Builds the userscript for production for all host platforms (GitHub, GreasyFork and OpenUserJS) with their respective options already set.
Outputs the files using a suffix predefined in the `package.json` file.
Use this to build the userscript for distribution on all hosts.
- **`npm run build -- <arguments>`**
Builds the userscript with custom options
Arguments:
- `--config-mode=<value>` - The mode to build in. Can be either `production` or `development` (default)
- `--config-branch=<value>` - The GitHub branch to target. Can be any branch name, but should be `main` for production and `develop` for development (default)
- `--config-host=<value>` - The host to build for. Can be either `github` (default), `greasyfork` or `openuserjs`
- `--config-assetSource=<value>` - Where to get the resource files from. Can be either `local` or `github` (default)
- `--config-suffix=<value>` - Suffix to add just before the `.user.js` extension. Defaults to an empty string

Shorthand commands:
- `npm run build-prod-base` - Sets `--config-mode=production` and `--config-branch=main`
Used for building for production, targeting the main branch
- `npm run build-develop` - Sets `--config-mode=development`, `--config-branch=develop` and `--config-assetSource=github`
Used for building for experimental versions, targeting the develop branch
- **`npm run lint`**
Builds the userscript with the TypeScript compiler and lints it with ESLint. Doesn't verify *all* of the functionality of the script, only syntax and TypeScript errors!
- **`npm run --silent invisible -- "<command>"`**
Runs the passed command as a detached child process without giving any console output.
Remove `--silent` to see npm's info and error messages.
- **`npm run node-ts -- <path>`**
Runs the TypeScript file at the given path using the regular node binary and the node-ts loader.
Also enables source map support and disables experimental warnings.

<br>

Expand All @@ -65,9 +140,8 @@ Like this template? Please consider [supporting the development ❤️](https://
Make sure to check out and follow their rules and guidelines before publishing.
- Use an IDE like [VS Code](https://code.visualstudio.com/) so Intellisense and Typescript can work together to give you really awesome code completion and warn you about potential runtime errors before you even build the code.
- If you are using VS Code, install the ESLint extension ([`dbaeumer.vscode-eslint`](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)) and bind a hotkey for the `ESLint: Fix all auto-fixable problems` command so you can quickly format the currently active file according to the rules in `.eslintrc.cjs`
- Try to get familiar with the [webpack config](https://webpack.js.org/configuration/) at `webpack.config.js`
In there you may add and configure webpack plugins and configure the build process.
- To see an example of how the code in `src/index.ts` will be packed in production mode, check out the file at [`dist/EXAMPLE.user.js`](./dist/EXAMPLE.user.js)
- Try to get familiar with the [rollup config](https://rollupjs.org/configuration-options/) at `rollup.config.mjs`
In there you may add and configure rollup plugins and configure the build process.

<br><br><br>

Expand All @@ -76,6 +150,6 @@ Like this template? Please consider [supporting the development ❤️](https://
Made with ❤️ by [Sv443](https://github.com/Sv443)
If you like this template, please consider [supporting me](https://github.com/sponsors/Sv443)

© 2023 Sv443 - [WTFPL license](./LICENSE.txt)
© 2024 Sv443 - [WTFPL license](./LICENSE.txt)

</div>
8 changes: 8 additions & 0 deletions assets/require.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
{
"pkgName": "@sv443-network/userutils",
"path": "dist/index.global.js",
"global": "UserUtils"
}
]

5 changes: 5 additions & 0 deletions assets/resources.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"img-logo": "images/logo.png",
"img-logo-48": "images/logo_48.png",
"doc-changelog": "/CHANGELOG.md"
}
11 changes: 2 additions & 9 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,2 @@
<!--
## 0.2.0
- ...

<br>
-->

## 0.1.0
- Initial release
# 0.1.0
- Initial release
6 changes: 0 additions & 6 deletions dependencies.json

This file was deleted.

Loading
Loading