Skip to content

Implement a CommonJS module loader to replace require()#145

Open
cmsj wants to merge 4 commits into
mainfrom
commonjs
Open

Implement a CommonJS module loader to replace require()#145
cmsj wants to merge 4 commits into
mainfrom
commonjs

Conversation

@cmsj

@cmsj cmsj commented Jul 22, 2026

Copy link
Copy Markdown
Owner

NOTE This PR exists as an alternative to #6 without having to use any JavaScriptCore internal API.

Implement a CommonJS-style module loader to replace our naive require() function. Seed a new user's config directory with a package.json and bundler to assist with importing from npm.

These are the steps a new user would take, to make use of this:

  1. Install Hammerspoon 2 and launch it. On first run it creates ~/.config/hammerspoon2/ and seeds package.json and bundle.js into it.
  2. Install Node.js if not already present - e.g. from nodejs.org or brew install node. This also provides npm and npx.
  3. Install the desired package:
cd ~/.config/hammerspoon2
npm install date-fns
  1. Bundle it into a single CommonJS file:
npm run bundle
  1. This runs bundle.js, which calls npx esbuild (downloaded automatically on first use) and writes lib/date-fns.js.
  2. Use it in init.js:
var { format } = require('./lib/date-fns');
console.log(format(new Date(), 'yyyy-MM-dd'));
  1. Reload Hammerspoon - either via the menu bar or hs.reload().

Steps 3–4 repeat whenever a new package is added or an existing one is updated. Step 4 is also needed after npm update since it regenerates the bundles from the updated packages.

@cmsj cmsj self-assigned this Jul 22, 2026
@greptile-apps

greptile-apps Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a CommonJS module loader and npm bundling workflow for user scripts. The main changes are:

  • CommonJS resolution, execution, caching, and JSON support.
  • Native file and evaluation bridges for JavaScript modules.
  • First-run package and bundler assets in the user config directory.
  • Integration tests for module loading and error handling.

Confidence Score: 5/5

This looks safe to merge.

  • The malformed JSON path now clears its provisional cache entry before propagating the parse error.
  • No distinct blocking failure remains in the updated code paths.

Important Files Changed

Filename Overview
Hammerspoon 2/Engine/require.js Adds the CommonJS loader and now removes malformed JSON modules from the cache before rethrowing.
Hammerspoon 2/Engine/JSEngine.swift Installs the native loader primitives, evaluates the bundled loader, and removes the temporary globals.
Hammerspoon 2/Managers/ManagerManager.swift Creates a new configuration directory and copies the bundled npm setup files on first launch.
Hammerspoon 2/UserAssets/seed-bundle.js Adds an esbuild-based script that bundles configured npm dependencies into CommonJS files.
Hammerspoon 2Tests/IntegrationTests/HSRequireIntegrationTests.swift Adds coverage for exports, path resolution, JSON, caching, cycles, module scope, and error cleanup.

Reviews (2): Last reviewed commit: "Make json parsing safer in require.js" | Re-trigger Greptile

Comment thread Hammerspoon 2/Engine/require.js
Comment thread Hammerspoon 2/Managers/ManagerManager.swift
@cmsj

cmsj commented Jul 22, 2026

Copy link
Copy Markdown
Owner Author

@greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant