Skip to content

Commit a65579d

Browse files
committed
feat!: use webpack externals & @require for libs
1 parent 301fc8c commit a65579d

File tree

7 files changed

+141
-127
lines changed

7 files changed

+141
-127
lines changed

README.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

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

5-
Typescript ESM template for making [userscripts](https://en.wikipedia.org/wiki/Userscript) that supports importing, parsing and minifying 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.
5+
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.
66
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.
77

88
Like this template? Please consider [supporting the development ❤️](https://github.com/sponsors/Sv443)
@@ -52,12 +52,16 @@ Like this template? Please consider [supporting the development ❤️](https://
5252
This makes it so the userscript automatically updates when the code changes (reloading the website is still necessary).
5353
Note: the tab needs to stay open on Firefox or the script won't keep updating itself.
5454
- My library [UserUtils](https://github.com/Sv443-Network/UserUtils) is already included as a dependency. It offers lots of utilities for userscripts like registering listeners for when CSS selectors exist, intercepting events, managing persistent user configurations, modifying the DOM more easily, various math and array functions and more. You can find the full list of features and its documentation [here.](https://github.com/Sv443-Network/UserUtils#table-of-contents)
55+
- Libraries that are required at runtime should be declared inside `dependencies.json`, as long as they are hosted on a CDN and expose a global variable.
56+
This way, they will be loaded using the `@require` directive and will be exempt from [minification rules](https://greasyfork.org/en/help/code-rules) on platforms like GreasyFork.
57+
You may use a service like [jsDelivr](https://www.jsdelivr.com/) to include any npm library this way.
58+
You will still be able to import and use the libraries as usual in your code.
5559
- The final bundled userscript file in the `dist/` folder should be committed and pushed to GitHub.
5660
This way, the `@downloadURL` and `@updateURL` directives make it so the script is automatically updated from that same file.
5761
For this to work properly, don't forget to bump the version in `package.json` before building, so that every user of your userscript may receive the update.
5862
- The name of the emitted bundle inside `dist/` is bound to `userscriptName` in `package.json`
5963
You may want to hard-code it or create a separate property for it if the userscript name contains characters that aren't allowed in a file path.
60-
- If you want other people to use your userscript, I recommend publishing it to [GreasyFork](https://greasyfork.org) and/or [OpenUserJS](https://openuserjs.org)
64+
- If you want other people to use your userscript, I recommend publishing it to [GreasyFork](https://greasyfork.org) and/or [OpenUserJS.](https://openuserjs.org)
6165
Make sure to check out and follow their rules and guidelines before publishing.
6266
- 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.
6367
- 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`

dependencies.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"@sv443-network/userutils": {
3+
"url": "https://greasyfork.org/scripts/472956-userutils/code/UserUtils.js",
4+
"global": "UserUtils"
5+
}
6+
}

dist/EXAMPLE.user.js

+7-12
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
// ==UserScript==
2-
// @name EXAMPLE
2+
// @name Userscript.ts Example
33
// @homepageURL https://github.com/Sv443/Userscript.ts#readme
44
// @namespace https://github.com/Sv443/Userscript.ts
55
// @version 0.1.0
6-
// @description EXAMPLE
6+
// @description Example script - install and visit example.org for a quick and dirty demo
77
// @license WTFPL
88
// @author Sv443
99
// @copyright Sv443 (https://github.com/Sv443)
1010
// @icon https://raw.githubusercontent.com/Sv443/Userscript.ts/main/assets/icon.png
1111
// @run-at document-start
1212
// @match https://example.org/*
1313
// @match https://example.com/*
14-
// @connect self
15-
// @connect github.com
16-
// @connect githubusercontent.com
14+
// @require https://greasyfork.org/scripts/472956-userutils/code/UserUtils.js
1715
// @downloadURL https://raw.githubusercontent.com/Sv443/Userscript.ts/main/dist/EXAMPLE.user.js
1816
// @updateURL https://raw.githubusercontent.com/Sv443/Userscript.ts/main/dist/EXAMPLE.user.js
1917
// ==/UserScript==
@@ -22,11 +20,8 @@
2220

2321
var __webpack_exports__ = {};
2422

25-
;// CONCATENATED MODULE: ./node_modules/@sv443-network/userutils/dist/index.mjs
26-
var h=Object.defineProperty,y=Object.defineProperties;var g=Object.getOwnPropertyDescriptors;var p=Object.getOwnPropertySymbols;var w=Object.prototype.hasOwnProperty,v=Object.prototype.propertyIsEnumerable;var f=(t,e,n)=>e in t?h(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,c=(t,e)=>{for(var n in e||(e={}))w.call(e,n)&&f(t,n,e[n]);if(p)for(var n of p(e))v.call(e,n)&&f(t,n,e[n]);return t},b=(t,e)=>y(t,g(e));var T=(t,e,n)=>new Promise((r,o)=>{var i=s=>{try{a(n.next(s));}catch(m){o(m);}},u=s=>{try{a(n.throw(s));}catch(m){o(m);}},a=s=>s.done?r(s.value):Promise.resolve(s.value).then(i,u);a((n=n.apply(t,e)).next());});function S(t,e,n){return Math.max(Math.min(t,n),e)}function A(t,e,n,r,o){return Number(e)===0&&Number(r)===0?t*(o/n):(t-e)*((o-r)/(n-e))+r}function d(...t){let e,n;if(typeof t[0]=="number"&&typeof t[1]=="number")[e,n]=t;else if(typeof t[0]=="number"&&typeof t[1]!="number")e=0,n=t[0];else throw new TypeError(`Wrong parameter(s) provided - expected: "number" and "number|undefined", got: "${typeof t[0]}" and "${typeof t[1]}"`);if(e=Number(e),n=Number(n),isNaN(e)||isNaN(n))throw new TypeError(`Parameters "min" and "max" can't be NaN`);if(e>n)throw new TypeError(`Parameter "min" can't be bigger than "max"`);return Math.floor(Math.random()*(n-e+1))+e}function H(t){return x(t)[0]}function x(t){if(t.length===0)return [void 0,void 0];let e=d(t.length-1);return [t[e],e]}function I(t){let[e,n]=x(t);if(n!==void 0)return t.splice(n,1),e}function P(t){let e=[...t];if(t.length===0)return t;for(let n=e.length-1;n>0;n--){let r=Math.floor(d(0,1e4)/1e4*(n+1));[e[n],e[r]]=[e[r],e[n]];}return e}function O(){try{return unsafeWindow}catch(t){return window}}function j(t,e){var n;return (n=t.parentNode)==null||n.insertBefore(e,t.nextSibling),e}function R(t,e){let n=t.parentNode;if(!n)throw new Error("Element doesn't have a parent node");return n.replaceChild(e,t),e.appendChild(t),e}function F(t){let e=document.createElement("style");e.innerHTML=t,document.head.appendChild(e);}function W(t,e=!1){let n=t.map(r=>new Promise((o,i)=>{let u=new Image;u.src=r,u.addEventListener("load",()=>o(u)),u.addEventListener("error",a=>e&&i(a));}));return Promise.allSettled(n)}function $(t){let e=document.createElement("a");Object.assign(e,{className:"userutils-open-in-new-tab",target:"_blank",rel:"noopener noreferrer",href:t}),e.style.display="none",document.body.appendChild(e),e.click(),setTimeout(e.remove,50);}function L(t,e,n){typeof Error.stackTraceLimit=="number"&&Error.stackTraceLimit<1e3&&(Error.stackTraceLimit=1e3),function(r){element.__proto__.addEventListener=function(...o){if(!(o[0]===e&&n()))return r.apply(this,o)};}(t.__proto__.addEventListener);}function B(t,e){return L(O(),t,e)}function q(t,e=1){let n=new(window.AudioContext||window.webkitAudioContext),r={mediaElement:t,amplify:o=>{r.gain.gain.value=o;},getAmpLevel:()=>r.gain.gain.value,context:n,source:n.createMediaElementSource(t),gain:n.createGain()};return r.source.connect(r.gain),r.gain.connect(n.destination),r.amplify(e),r}function z(t,e){return (Array.isArray(e)||e instanceof NodeList)&&(e=e.length),`${t}${e===1?"":"s"}`}function U(t){return new Promise(e=>{setTimeout(e,t);})}function D(t,e=300){let n;return function(...r){clearTimeout(n),n=setTimeout(()=>t.apply(this,r),e);}}function J(n){return T(this,arguments,function*(t,e={}){let{timeout:r=1e4}=e,o=new AbortController,i=setTimeout(()=>o.abort(),r),u=yield fetch(t,b(c({},e),{signal:o.signal}));return clearTimeout(i),u})}var l=new Map;function V(t,e){let n=[];l.has(t)&&(n=l.get(t)),n.push(e),l.set(t,n),E(t,n);}function X(t){return l.delete(t)}function E(t,e){let n=[];if(e.forEach((r,o)=>{try{let i=r.all?document.querySelectorAll(t):document.querySelector(t);(i!==null&&i instanceof NodeList&&i.length>0||i!==null)&&(r.listener(i),r.continuous||n.push(o));}catch(i){console.error(`Couldn't call listener for selector '${t}'`,i);}}),n.length>0){let r=e.filter((o,i)=>!n.includes(i));r.length===0?l.delete(t):l.set(t,r);}}function Y(t={}){new MutationObserver(()=>{for(let[n,r]of l.entries())E(n,r);}).observe(document.body,c({subtree:!0,childList:!0},t));}function Z(){return l}
27-
28-
29-
23+
;// CONCATENATED MODULE: external "UserUtils"
24+
const external_UserUtils_namespaceObject = UserUtils;
3025
;// CONCATENATED MODULE: ./changelog.md
3126
// Module
3227
var code = "<!--\n## 0.2.0\n- ...\n\n<br>\n--> <h2 id=\"010\">0.1.0</h2> <ul> <li>Initial release</li> </ul> ";
@@ -66,7 +61,7 @@ function insertExampleElements() {
6661
* Note: if you set `@run-at` to something like `document-end`, the `DOMContentLoaded` event may not be called depending on the userscript extension. In this case you may remove the onDomLoad() function and modify the DOM directly in init().
6762
*/
6863
function init() {
69-
const buildNbr = "c79d7df";
64+
const buildNbr = "301fc8c";
7065
const buildNbrText = !buildNbr.match(/^{{.+}}$/) ? `-${buildNbr}` : "";
7166
// watermark in the console based on values grabbed out of the userscript header
7267
console.log(`${GM.info.script.name} (${GM.info.script.version}${buildNbrText}) - ${GM.info.script.namespace}`);
@@ -90,7 +85,7 @@ function onLoad() {
9085
`;
9186
// if no css file is imported anywhere, no bundle is emitted and so addGlobalStyle has to be skipped
9287
if (!globalStyle.match(/^{{.+}}$/))
93-
F(globalStyle);
88+
(0,external_UserUtils_namespaceObject.addGlobalStyle)(globalStyle);
9489
// go to this function's definition in `example.ts` for an example on how to import HTML, CSS and markdown
9590
insertExampleElements();
9691
}

0 commit comments

Comments
 (0)