{"id":14989080,"url":"https://github.com/chocolateboy/uncommonjs","last_synced_at":"2025-09-09T06:21:29.933Z","repository":{"id":44338154,"uuid":"258916258","full_name":"chocolateboy/uncommonjs","owner":"chocolateboy","description":"A minimum viable shim for module.exports","archived":false,"fork":false,"pushed_at":"2024-01-21T23:18:49.000Z","size":236,"stargazers_count":9,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-04-23T15:01:00.974Z","etag":null,"topics":["adapter","commonjs","deno","exports","greasemonkey","module","polyfill","quickjs","shim","spidermonkey","stub","tampermonkey","umd","userscript","userscripts","violentmonkey"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chocolateboy.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-26T02:00:19.000Z","updated_at":"2023-09-08T18:06:33.000Z","dependencies_parsed_at":"2024-09-11T20:57:53.542Z","dependency_job_id":"1a36eedd-919b-4bed-9305-6aff2470048f","html_url":"https://github.com/chocolateboy/uncommonjs","commit_stats":{"total_commits":73,"total_committers":1,"mean_commits":73.0,"dds":0.0,"last_synced_commit":"412e743e7cb91bb749b614d3141aa6cbbb7a7e40"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chocolateboy%2Funcommonjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chocolateboy%2Funcommonjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chocolateboy%2Funcommonjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chocolateboy%2Funcommonjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chocolateboy","download_url":"https://codeload.github.com/chocolateboy/uncommonjs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248501427,"owners_count":21114674,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["adapter","commonjs","deno","exports","greasemonkey","module","polyfill","quickjs","shim","spidermonkey","stub","tampermonkey","umd","userscript","userscripts","violentmonkey"],"created_at":"2024-09-24T14:17:40.243Z","updated_at":"2025-04-12T00:32:25.444Z","avatar_url":"https://github.com/chocolateboy.png","language":"JavaScript","readme":"# UnCommonJS\n\n[![Build Status](https://github.com/chocolateboy/uncommonjs/workflows/test/badge.svg)](https://github.com/chocolateboy/uncommonjs/actions?query=workflow%3Atest)\n[![NPM Version](https://img.shields.io/npm/v/@chocolateboy/uncommonjs.svg)](https://www.npmjs.org/package/@chocolateboy/uncommonjs)\n\n\u003c!-- TOC --\u003e\n\n- [NAME](#name)\n- [FEATURES](#features)\n- [INSTALLATION](#installation)\n- [USAGE](#usage)\n- [DESCRIPTION](#description)\n  - [Why?](#why)\n    - [Userscripts](#userscripts)\n    - [ESM-only environments](#esm-only-environments)\n  - [Why not?](#why-not)\n- [TYPES](#types)\n- [GLOBALS](#globals)\n  - [exports](#exports)\n  - [module](#module)\n    - [exported](#moduleexported)\n    - [exports](#moduleexports)\n    - [require](#modulerequire)\n  - [require](#require)\n- [EXPORTS](#exports-1)\n  - [default](#default)\n- [CAVEATS](#caveats)\n  - [Scope](#scope)\n- [DEVELOPMENT](#development)\n- [COMPATIBILITY](#compatibility)\n- [SEE ALSO](#see-also)\n- [VERSION](#version)\n- [AUTHOR](#author)\n- [COPYRIGHT AND LICENSE](#copyright-and-license)\n\n\u003c!-- TOC END --\u003e\n\n# NAME\n\nUnCommonJS - a minimum viable shim for `module.exports`\n\n# FEATURES\n\n- `module.exports`\n- `exports`\n- pluggable `require`\n- supports live exports (ESM emulation)\n- tiny (\u0026lt; 700 B minified + gzipped)\n- no dependencies\n- fully typed (TypeScript)\n- CDN builds - [jsDelivr][], [unpkg][]\n\n# INSTALLATION\n\n    $ npm install @chocolateboy/uncommonjs\n\n# USAGE\n\n```javascript\n// ==UserScript==\n// @name          My Userscript\n// @description   A userscript which uses some CommonJS modules\n// @include       https://www.example.com/*\n// @require       https://unpkg.com/@chocolateboy/uncommonjs@3.2.1\n// @require       https://cdn.jsdelivr.net/npm/crypto-hash@1.3.0\n// @require       https://cdn.jsdelivr.net/npm/tiny-once@1.0.0\n// ==/UserScript==\n\nconsole.log(module.exported) // { once: ..., sha1: ..., sha256: ..., ... }\nconsole.log(exports === module.exports) // true\n\nconst { once, sha256: encrypt } = exports\n\n// ...\n```\n\n# DESCRIPTION\n\nUnCommonJS is a tiny library which exposes a `module.exports` global (and\n`exports` alias) which behaves like the CommonJS built-in. It can be used to\ngather exports in environments which don't otherwise support CommonJS.\n\nNames are deduplicated, so that e.g. if multiple modules export the same name\nor assign multiple values to `module.exports`, each export is given a distinct\nname.\n\nThis shim is useful in very constrained environments in which it's not possible\n(usually for political or policy reasons) to use transpilers or bundlers to\nintegrate third-party modules.\n\n## Why?\n\n### Userscripts\n\nI mainly use it to work around NPM modules that don't have UMD builds when I\nwant to use one in a [userscript][userscripts] (and as a way to import\ndependencies that *are* available as UMD bundles without polluting `window`).\n\nFor example, let's say I want to use the following modules, which are available\non NPM but don't have UMD builds:\n\n- [crypto-hash](https://www.npmjs.com/package/crypto-hash)\n- [tiny-once](https://www.npmjs.com/package/tiny-once)\n\nSince both of these modules are simple, small, and standalone — i.e. they don't\nuse `require` — I can use UnCommonJS to expose `module.exports` and `exports`\nglobals which they can attach their exports to. I can then pull these exported\nvalues (functions in this case) into a userscript simply by extracting them\nfrom the `module.exports`/`exports` object:\n\n```javascript\n// ==UserScript==\n// @name     My Userscript\n// @require  https://unpkg.com/@chocolateboy/uncommonjs@3.2.1\n// @require  https://cdn.jsdelivr.net/npm/crypto-hash@1.3.0\n// @require  https://cdn.jsdelivr.net/npm/tiny-once@1.0.0\n// ==/UserScript==\n\nconst { once, sha256: encrypt } = module.exports\n\n// ...\n```\n\n### ESM-only environments\n\nIt can also be used to add support for (dependency-free) NPM modules to\nenvironments which only support ESM such as [Deno][] and [QuickJS][].\n\n\u003e $ deno\n\n```\nDeno\nexit using ctrl+d or close()\n\n\u003e import 'https://unpkg.com/@chocolateboy/uncommonjs@3.2.1'\n\u003e import 'https://unpkg.com/micro-down@1.6.2'\n\n\u003e exports.parse('Hi, **this** _is_ [Markdown](#markdown)!')\n'\u003cp\u003eHi, \u003cstrong\u003ethis\u003c/strong\u003e \u003cem\u003eis\u003c/em\u003e \u003ca href=\"#markdown\" \u003eMarkdown\u003c/a\u003e!\u003c/p\u003e'\n```\n\n## Why not?\n\nThis is a hack to get CommonJS modules working in constrained environments such\nas userscripts when no other option is available. It shouldn't be used in\nsituations or environments where sane solutions are available.\n\n# TYPES\n\nThe following types are referenced in the descriptions below.\n\n\u003cdetails\u003e\n\n```typescript\ntype Exports = Record\u003cPropertyKey, any\u003e\ntype Require = (id: string) =\u003e any\n\ntype Module = {\n    get exports (): Exports;\n    set exports (value: any);\n    readonly exported: Exports;\n    require: Require;\n}\n\ntype Environment = {\n    module: Module;\n    exports: Exports;\n    require: Require;\n}\n\ntype Options = {\n    require?: Require;\n}\n```\n\n\u003c/details\u003e\n\n# GLOBALS\n\nWhen the shim is loaded, [`module`](#module), [`exports`](#exports) and\n[`require`](#require) are defined as global variables if they're not defined\nalready. Unless noted, they should have the same behavior as the corresponding\nvalues in Node.js and other CommonJS environments.\n\n```javascript\nimport '@chocolateboy/uncommonjs/polyfill'\n\nmodule.exports = 42\nconsole.log(module.exported) // { \"default\": 42 }\n```\n\nThe API can be [imported](#exports-1) without being automatically registered via\nthe module's main file, e.g.:\n\n```javascript\nimport cjs from '@chocolateboy/uncommonjs'\n\nconst env = cjs() // { module: ..., exports: ..., require: ... }\nObject.assign(globalThis, env)\n```\n\n## exports\n\nAn alias for [`module.exports`](#moduleexports).\n\n## module\n\nAn object which contains the following properties:\n\n\u003c!-- TOC:display:exported --\u003e\n### module.exported\n\n[`module.exports`](#moduleexports) (and its [`exports`](#exports) alias) is\nimplemented as a thin wrapper (an ES6 Proxy) around the actual exports which\ntransparently handles name deduplication.\n\nMost of the time this distinction doesn't matter, but it can crop up when\nlogging/debugging — e.g. when dumping the exported values with `console.log` —\nsince some environments display the Proxy's internals, rather than its target.\nThis can make it hard to see what's actually available. The `module.exported`\nproperty solves this by exposing a (read-only) view of the underlying object.\n\n```javascript\nconsole.log(module.exports)\n// Proxy { \u003ctarget\u003e: {…}, \u003chandler\u003e: {…} }\n\nconsole.log(module.exported)\n// Object { once: ..., sha1: ..., sha256: ..., ... }\n```\n\n\u003c!-- TOC:display:exports --\u003e\n### module.exports\n\nAn object (dictionary) of exported values which can be assigned to by name, e.g.:\n\n```javascript\nmodule.exports.foo = function foo () { ... }\nmodule.exports.bar = function () { ... }\n```\n\n`exports` is an alias for `module.exports`, so named assignments to `exports`\nare identical to named assignments to `module.exports`.\n\nThe first time a named export is assigned, it is given the specified name.\nSubsequent assignments to the same name with the same value are ignored. If\ndifferent values are assigned to the same name, they are assigned unique names\nby appending numeric suffixes, e.g.: `foo`, `foo_1`, `foo_2` etc.\n\nIn addition to named exports, default exports can be assigned directly to\n`module.exports`. Note: unlike named exports, which can be assigned to\n`exports`, default exports only work by assignment to `module.exports`.\n\nIf a named function is assigned to `module.exports`, it is equivalent to a\nnamed export, e.g.:\n\n```javascript\nmodule.exports = function foo () { }\n```\n\nis equivalent to:\n\n```javascript\nmodule.exports.foo = function foo () { }\n```\n\nIf the assigned value is an anonymous function or a non-function, it is\nassigned the name `default`. As with named exports, default assignments with\nthe same value are ignored and default assignments with different values are\nassigned distinct names by appending a numeric suffix, e.g. `default`,\n`default_1`, `default_2` etc.\n\nIf a plain object is assigned to `module.exports`, its properties are assigned\nby name (the object's own, enumerable string keys) in addition to the default\nexport, e.g.:\n\n```javascript\nconst props = { foo, bar }\nmodule.exports = props\n```\n\nis equivalent to:\n\n```javascript\nmodule.exports.foo = foo\nmodule.exports.bar = bar\nmodule.exports.default = props\n```\n\n\u003c!-- TOC:display:require --\u003e\n### module.require\n\nAn alias for the [`require`](#require) export. Can be assigned a new `require`\nimplementation which is used whenever the exported `require` function is\ncalled.\n\n```javascript\nconst mods = {\n    'is-even':     (value =\u003e value % 2 === 0),\n    'is-odd':      (value =\u003e value % 2 === 1),\n    'is-thirteen': (value =\u003e value === 13),\n}\n\nmodule.require = id =\u003e {\n    return mods[id] || throw new Error(...)\n}\n```\n\n## require\n\nA function which takes a module ID (string) and returns the value exported by\nthe module.\n\nThe default implementation is a stub which raises an exception which includes\nthe name of the required module. It can be overridden by assigning to\n[`module.require`](#modulerequire).\n\n# EXPORTS\n\n## default\n\n**Type**: `(options?: Options) =\u003e Environment`\n\n```javascript\nimport cjs from '@chocolateboy/uncommonjs'\n\nconst mods = {\n    'is-even': (value =\u003e value % 2 === 0),\n    'is-odd':  (value =\u003e value % 2 === 1),\n}\n\nconst myRequire = id =\u003e mods[id] || throw new Error(...)\nconst env = cjs({ require: myRequire })\n\nObject.assign(globalThis, env)\n```\n\nA function which generates a new CommonJS environment, i.e. an object\ncontaining CommonJS-compatible [`module`](#module), [`exports`](#exports) and\n[`require`](#require) properties.\n\nTakes an optional options object supporting the following options:\n\n\u003c!-- TOC:ignore --\u003e\n### require\n\n**Type**: `Require`\n\nA `require` implementation which is delegated to by the exported\n[`require`](#require) function. If not supplied, it defaults to a function\nwhich raises an exception with the supplied module ID.\n\n# CAVEATS\n\n- By default, `require` is defined but not implemented (it throws an\n  exception): check the required modules to ensure they don't use it\n- `__filename` and `__dirname` are not supported\n- Pin the versions of the required modules to avoid being caught out if they\n  update their dependencies\n- Unless a compatible [`require`](#require) has been [defined](#modulerequire),\n  load UMD bundles which use `require` **before** this shim, otherwise it will\n  mislead them into thinking it's a real CommonJS environment\n\n## Scope\n\nCare may need to be taken when extracting values from the `exports` object into\nvariables if a CommonJS module (also) defines those variables at its top\nlevel, e.g.:\n\n```javascript\nfunction foo () { ... }\n\nmodule.exports = foo\n```\n\nFor example, while most userscript engines execute userscripts in a (nested)\nscope distinct from that of the `@require`s, at least one popular engine\ndoesn't. This means that the following won't work portably:\n\n```javascript\n// ==UserScript==\n// @name          Non-Portable Userscript\n// @include       *\n// @require       https://unpkg.com/@chocolateboy/uncommonjs@3.2.1\n// @require       https://cdn.jsdelivr.net/npm/just-safe-get@4.0.1\n// ==/UserScript==\n\nconst { get } = exports // SyntaxError\n\nget(obj, path)\n```\n\nBecause the userscript is evaluated in the same scope as the CommonJS module,\nthe name is already defined and the declaration results in an error:\n\n    Uncaught SyntaxError: redeclaration of function `get`\n\nThe same issue can occur in other contexts, e.g. if the shim is being used on a\nwebpage.\n\nThe solution is to wrap the code (or the parts of the code which assign\nproperties of `exports` to local variables) in a nested scope, e.g. a\n[block](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/block)\nor [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE):\n\n```javascript\n(function () {\n    const { get } = exports // OK\n\n    get(obj, path)\n})()\n```\n\nAlternatively, it may be simpler to access the export by its qualified name,\ne.g.:\n\n```javascript\nexports.get(obj, path) // OK\n```\n\n# DEVELOPMENT\n\n\u003cdetails\u003e\n\n\u003c!-- TOC:ignore --\u003e\n## NPM Scripts\n\nThe following NPM scripts are available:\n\n- build - compile the library for testing and save to the target directory\n- build:doc - update the table-of-contents (TOC) in the README\n- build:release - compile the library for release and save to the target directory\n- clean - remove the target directory and its contents\n- rebuild - clean the target directory and recompile the library\n- test - recompile the library and run the test suite\n- test:run - run the test suite\n- typecheck - sanity check the library's type definitions\n\n\u003c/details\u003e\n\n# COMPATIBILITY\n\n- any environment with ES6 support\n- in strict mode, globals are assigned to\n  [`globalThis`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis),\n  which may need to be polyfilled\n\n# SEE ALSO\n\n- [GreasyFork Libraries](https://greasyfork.org/scripts/libraries)\n- [Observable - How to require stubborn modules](https://observablehq.com/@observablehq/how-to-require-stubborn-modules)\n- [packd](https://github.com/Rich-Harris/packd) - a [web service](https://bundle.run/) which converts NPM packages to UMD bundles\n- [quickjs-require](https://github.com/IvanGaravito/quickjs-require) - a CommonJS `require` implementation for QuickJS\n- [REPKG](https://github.com/privatenumber/repkg) - a [web service](https://repkg.now.sh/) which converts NPM packages to UMD bundles\n\n# VERSION\n\n3.2.1\n\n# AUTHOR\n\n[chocolateboy](mailto:chocolate@cpan.org)\n\n# COPYRIGHT AND LICENSE\n\nCopyright © 2020 by chocolateboy.\n\nThis is free software; you can redistribute it and/or modify it under the terms\nof the [MIT license](https://opensource.org/licenses/MIT).\n\n[Deno]: https://deno.land/\n[jsDelivr]: https://unpkg.com/browse/@chocolateboy/uncommonjs\n[QuickJS]: https://bellard.org/quickjs/\n[unpkg]: https://unpkg.com/@chocolateboy/uncommonjs\n[userscripts]: https://github.com/chocolateboy/userscripts\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchocolateboy%2Funcommonjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchocolateboy%2Funcommonjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchocolateboy%2Funcommonjs/lists"}