Modern Web development one jump at the time
Photo by Denny Luan on Unsplash
The ungap project was born after years of attempts to always fix the same issue, but never in a modular way and, most importantly, never in a single, 100% code covered, organization.
Each module is written in ES5 compatible syntax to avoid both unnecessary transpilers bloat and potentially unexpected behaviors. Each module is also 100% code-covered through tests able to verify the whole API both as native and polyfilled version. The constrains per module are the following:
- CommonJS, ESM, Worker, and Web compatibility.
- easy to read and maintain ES5 syntax, keeping the code size in mind.
- mandatory 100% code coverage through all possible NodeJS hacks to ensure every part of the code that has a meaning works as expected (some meaningless part can be skipped but functionalities must be ensured).
- every module is stand-alone, allowing incremental patch or polyfilling.
- modules should be bundlers and transpilers resistant to avoid any possible, production code, surprise [1].
[1] as example: stripped out features detections
There are parts of the specifications that are very hard, if not impossible, to polyfill. The main purpose of this project is to help developers move forward, and possibly without unnecessary bloat. This basically means that polyfills are written to support 99% of the use cases, without granting 100% spec compliance.
If you need that, which again is basically impossible in most of the cases, feel free to keep using whatever monolithic polyfill or approach you were using before.
Every single module is made available as ESM, through the package.json
's module
field, CJS via package.json
's main
field, and browser script polyfill / patch via package.json
's unpkg
field so that you can use directly the unpkg CDN.
// as ECMAScript module
import WeakSet from '@ungap/weakset';
// as CommonJS module
const WeakSet = require('@ungap/weakset');
// as Browser global patch
<script src="https://unpkg.com/@ungap/weakset"></script>
Essentials modules covers most common use cases without going full bloated API.
As example, the essential-map exposes only get
, set
, delete
, and has
which is most of the time everything one needs, as opposite of going full map.
The main benefit of the essential modules is their size, simplicity, or even performance.
- @ungap/essential-map with only common method.
- @ungap/essential-set with only common method.
- @ungap/essential-symbol providing just its uniqueness.
- @ungap/essential-weakset with simpler logic but widely compatible.
- @ungap/assign compatible with all JS engines
- @ungap/array-iterator compatible with all engines that have a global
Symbol
. - @ungap/bytes compatible with engines that provide
Blob
,Request
andResponse
classes. - @ungap/compression-stream compatible with modern engines only and mostly targeting Bun.
- @ungap/custom-elements compatible with IE 11 and many other browsers.
- @ungap/custom-event compatible with all browsers.
- @ungap/dom-iterable compatible with all engines that have a global
Symbol
. - @ungap/element-matches compatible with all JS engines with a DOM env.
- @ungap/event with double fallback through
CustomEvent
. - @ungap/event-target compatible with all JS engines.
- @ungap/from-entries compatible with all JS engines.
- @ungap/get-own-property-descriptors compatible with all JS engines.
- @ungap/global-this compatible with all JS engines.
- @ungap/has-own compatible with all JS engines.
- @ungap/import-node compatible with all JS engines.
- @ungap/insert-after compatible with all JS engines.
- @ungap/is-array compatible with all JS engines.
- @ungap/is-connected compatible with all JS engines.
- @ungap/item compatible with all JS engines.
- @ungap/json fixes
\u2028|9
in all JS engines with aJSON
global. - @ungap/map compatible with all JS engines.
- @ungap/new an extension to allow
Class.new(...args)
instead ofnew Class(...args)
- @ungap/node-contains
Element.contains
compatible with all JS engines with a DOM env. - @ungap/once
Function.prototype.once
compatible with modern JS engines. - @ungap/own-keys
Reflect.ownKeys
compatible with all JS engines. - @ungap/promise-any compatible with all JS engines.
- @ungap/promise-all-settled compatible with all JS engines.
- @ungap/queue-microtask compatible with all JS engines.
- @ungap/random-uuid compatible with IE11+ and NodeJS.
- @ungap/raw-json compatible with modern engines only.
- @ungap/remove compatible with all JS engines.
- @ungap/set compatible with all JS engines.
- @ungap/set-methods compatible with ES2015 engines.
- @ungap/structured-clone compatible with ES2015+ engines only.
- @ungap/template-literal compatible with all JS engines.
- @ungap/template-tag-arguments compatible with all JS engines.
- @ungap/trim compatible with all JS engines.
- @ungap/trim-start compatible with all JS engines.
- @ungap/trim-end compatible with all JS engines.
- @ungap/url-search-params compatible with all JS engines.
- @ungap/weakmap compatible with all JS engines.
- @ungap/weakrefs
WeakRef
andFinalizationGroup
compatible with any engine that already has aWeakMap
(i.e. IE11+). - @ungap/weakset compatible with any engine that already has a
WeakMap
(i.e. IE11+). - @ungap/with-resolvers compatible with all JS engines.
Ungap utilities are meant to simplify cross browser development without the bloat of a whole polyfill.
- @ungap/create-content compatible with all JS engines (backend via basichtml or others).
- @ungap/custom-elements-new to use
CustomElement.new()
instead ofnew CustomElement()
due WebKit/Safari built-in extends caveat.
If you are targeting modern browsers only, you might want to exclude some unnecessary code from various ungapped APIs.
Following a list of plugins which aim is to address those cases:
- babel-plugin-remove-ungap provides the ability to arbitrarily exclude polyfills through tree-shaking, an awesome tool from coreyfarrell ♥
- @ungap/degap to make any module either a no-op, just the native version, or the simplified utility (as in element-matches case).
Each module is under the npm default ISC license.
You are welcome to join the organization after your first module is published.
In order to do so, please take any already available module as example of how to create and test any code you need.
The main guideline though, can be summarized as such:
- the entry point is the root
./index.js
. - the ESM module is generated in
./esm/index.js
. - the CJS module is generated in
./cjs/index.js
. - you cannot use any transpiler.
- you might use some bundler as long as the tested code is the one generated by such bundler.
I have personally no interest in enforcing any specific linting rule or code style, as long as common sense and good practices are part of the code.
If these basic constrains are good enough for you, please do help this project grow, allowing the community to leave all monolithic polyfills part of the past.
If you have further questions, you can DM me @webreflection [1]
[1] my DMs are open