Compile one .user.js file into three reviewable packages:
- a userscript artifact for Tampermonkey, Violentmonkey, Greasemonkey, or Safari userscript apps
- browser-extension packages for Chrome, Firefox, and Safari
- a standalone web harness for baseline testing
The compiler also generates one consolidated review/submission-guide.md for Chrome Web Store, Mozilla Add-ons, Safari/App Store review notes, Firefox for Android notes, package validation, and troubleshooting.
When run through the CLI it also writes store-ready release artifacts separately from the project/audit bundle.
The original compiler always used the native userScripts API. That is high-friction for review and installation:
- Chrome requires the
userScriptspermission plus a browser toggle. - Mozilla policy allows the
userScriptsAPI only for user-script managers. - Safari does not have the same cross-browser
userScriptsAPI path.
2.0 defaults to static content-script packaging and only uses native userScripts mode when you explicitly choose it.
npm ci
npm run devBuild the GitHub Pages site:
npm run buildRun the local checks:
npm run checknpm run compile -- path/to/script.user.js --out ./compiled-scriptUseful options:
npm run compile -- ./dist/yomu.user.js \
--out ./compiled-yomu \
--target chrome,firefox,safari \
--runtime content-script \
--newtab-dir ./dist/newtabRuntime modes:
content-script: default, avoids the nativeuserScriptspermission.user-scripts: advanced mode using Chrome/FirefoxuserScripts.auto: compiler chooses per target.
Use --newtab for a generated placeholder new-tab page, or --newtab-dir ./dist/newtab to package a real built new-tab app such as Yomu's.
packages/
userscript/script.user.js
extension/chrome/
extension/firefox/
extension/safari/
standalone/
review/
submission-guide.md
audit/
release/
chrome/*.zip
firefox/*.xpi
safari/*-safari-web-extension/
tools/verify.mjs
Load packages/extension/chrome unpacked in Chrome, packages/extension/firefox in Firefox, and package packages/extension/safari through Apple's Safari Web Extension tooling.
The *-extension-project.zip file is a source/audit bundle. Store uploads should use the target-specific files under release/, where Chrome and Firefox archives have manifest.json at the archive root and Safari output is a WebExtension source folder for Apple's packager.
Run npm run verify from the generated output directory to check required files, package validation errors, and release artifact presence.
The userscript package is copied exactly from your input file. The compiler does not minify, obfuscate, or rewrite it. Greasy Fork rejects posted scripts that are minified or packed, so build your .user.js with JavaScript and CSS minification disabled before compiling or publishing. If the source body looks minified, the compiler emits a greasyfork.source-readability warning and the generated userscript README explains what to fix.
- Chrome privacy fields and permission justifications: https://developer.chrome.com/docs/webstore/cws-dashboard-privacy
- Chrome
userScripts: https://developer.chrome.com/docs/extensions/reference/api/userScripts - Chrome single-purpose FAQ: https://developer.chrome.com/docs/webstore/program-policies/quality-guidelines-faq
- Mozilla Add-on Policies: https://extensionworkshop.com/documentation/publish/add-on-policies/
- Mozilla source submission: https://extensionworkshop.com/documentation/publish/source-code-submission/
- Safari Web Extensions: https://developer.apple.com/documentation/SafariServices/safari-web-extensions
- Safari permissions: https://developer.apple.com/documentation/safariservices/managing-safari-web-extension-permissions
Build Yomu first, then compile it:
cd ../yomu-reader
npm ci
npm run build
npm run verify
cd ../UserScript-Compiler
npm ci
npm run compile -- ../yomu-reader/dist/yomu.user.js --out ./compiled-yomu --target chrome,firefox,safari --runtime content-script --newtab-dir ../yomu-reader/dist/newtab
node ./compiled-yomu/tools/verify.mjsUse the generated review/submission-guide.md as the starting point for Chrome, Mozilla, and Safari submissions. Read it before pasting: it is generated from metadata and should stay truthful to the final package.