spackle home Test this deviceCompareQuick startRead the paper

Spackle

Self-contained polyfills for older hardware. Measured against core-js 3.50, 2026-10-30. Spackle release 0.1.0-alpha.9.

Abstract. Polyfill libraries often route API calls through shared helpers. Spackle instead keeps each polyfill self-contained, reducing helper work and temporary allocations. In a simulated front-end workload across 24 Chromium WebViews (41 to 150), the oldest engines used up to 6× less polyfill time and produced up to 7× less garbage with Spackle. From Chromium 69, results were within 10%, as both libraries relied more on native implementations. On one 2017 LG TV, the SolidTV demo app's median initial render was 4.53 seconds with core-js and 1.03 seconds with Spackle (4.4× faster). These results describe the tested workload and device; they are not a guarantee for every application.

1. The problem

Many devices ship WebViews years behind desktop browsers, often with slower CPUs and less available memory. Applications support those engines through a polyfill library (a common choice is core-js). It is built the way a library should be: every API routed through shared internals (toObject, lengthOfArrayLike, getIteratorMethod, and so on), each one correct, each one small. Most engineers learn DRY early, and it is usually the right call.

DRY is costing us. For example, a single polyfilled Array.from walks a chain of nested helper functions, and several of those allocate: an iterator record, a bound function, an options object. On a modern machine this is a negligible slowdown. But on older, slower hardware (where these polyfills are needed), garbage collection runs on the main thread, which causes UI jitter and makes apps feel sluggish.

2. Approach: islands

Each Spackle polyfill is one function with no imports. Instead of DRY, Spackle was built to be WET (write everything twice): polyfills that rely on other polyfills have those dependencies inlined.

So there are no helper chains: the hot path is a single frame with the work in it and nothing else. Spackle also avoids temporary per-call allocations in its polyfill paths, reducing the short-lived objects the collector would otherwise need to clean up.

The obvious objection is maintenance: a fix to shared logic has to be made in every island that carries it. In practice this has not been as much of a burden as expected. The functions are small by nature, and the duplicated part is a few lines of coercion.

Shared helpers have the opposite problem: a change to one helper changes every API routed through it, so a fix for Array.from is also, silently, a change to Map, Promise.all and forty other entry points. An island's blast radius is the island.

The trade is scope. core-js tracks the whole language and unfinished proposals, across Node and most browsers. Spackle focuses on established APIs, in browsers only, from Safari 7.1 and Chromium 38 up.

As a direct test of the WET design: the same Map polyfill written twice, once as an island and once routed through shared helpers, with nothing else different. The island was 1.66× faster and produced 2.2× less garbage.

3. Method

Spackle was run against core-js in a WebView running each Chromium version from 41 to 150, about every fifth release, 24 versions in all. Every run had a fresh browser, a 64 MB JavaScript heap and one CPU core. Each test ran twice with the library order swapped; the median is reported. Garbage collection counts, pause times and heap sizes come from V8's own log, not from a sampling profiler.

SettingValue
WebViews24 Chromium versions, 41 to 150
Heap64 MB
CPUSingle core
Passes2,000
Runs2 per test, library order swapped, median reported
GC measurementV8's own log
core-js entrycore-js/stable and the full bundle: results within noise of each other

The stress test is a render loop that calls polyfilled built-ins the way a front-end framework does on each render: Object.assign, Array.from, Map, URL, string and array helpers, hundreds of calls per pass. It is deliberately a worst case for a polyfill library. It measures what the polyfills cost, not whole-application speed.

The hot-path test calls one API 500 times in a row and times it, after a warm-up, averaged over 10 executions.

4. Results

Stress test, by Chromium version

Spackle relative to core-js. ≈ means within 10%.

Chromium414550566169+
Polyfill time6.1× less5.6× less3.5× less2.5× less1.6× less≈
Garbage6.6× less6.0× less3.6× less1.6× less1.4× less≈
Minor GCs7.4× fewer7.2× fewer3.7× fewer1.7× fewer1.5× fewer≈
GC pause time6.2× less2.7× less1.5× less1.5× less1.2× less≈

From Chromium 69 both libraries step aside for native built-ins and the two are level.

Hot paths, by Chromium version

How many times faster Spackle's polyfill ran than core-js's. ≈ means within 10%.

Chromium41505678
Object.assign9.3×≈≈≈
Object.keys≈≈≈≈
Array.from18.6×3.3×≈≈
Array#includes10.9×≈≈≈
Array#find1.4×≈≈≈
String#padStart7.3×3.0×≈≈
Map get/has2.8×≈≈≈
Set#has≈≈≈≈
Promise chain≈≈≈≈
new URL29.4×7.6×4.5×≈
URLSearchParams9.9×8.3×2.5×≈

5. Real hardware

A 2017 LG smart TV, webOS 3.5, Chromium 38. Both results are from the same physical TV, read from the device's own performance trace.

Application: SolidTV demo

The SolidTV demo app, default build against the same build with Spackle. Five-run medians.

MetricBaselineWith SpackleChange
Initial render4.53 s1.03 s4.4× faster
Visually complete5.64 s2.07 s2.7× faster
Frame rate34.8 fps47.1 fps36% higher
Longest frame3.32 s0.13 s~25× shorter

Stress test on the TV

The same stress test as section 3, cut to 500 passes, the most the TV can run. Three runs.

MetricSpackle vs core-js
Garbage~9× less
Garbage collections~5× fewer
Peak heap37% lower

6. Spec compliance

Behavior was checked with 1,357 selected checks derived from test262 and web-platform-tests, run in the browser with each library installed over the engine's own natives. This is a targeted check set covering each polyfill Spackle supports. Some checks are skipped where a polyfill crashes the WebView (this happens with core-js). An important note: neither core-js nor Spackle passes everything. In the recorded runs, Spackle's pass rate was at or above core-js's on each engine. The per-engine table and the same 1,357 checks for your browser are on Verify.

7. Data

The files the tables came from, as recorded. JSON traces open in Chrome DevTools, Performance, Load profile.

FileWhat it is
webview-summary.csvWebView runs, Chromium 41 to 150: one row per test, library and version
webview-results.jsonThe same runs in full: timings, GC counts and heap per run
LG-2017-500pass-compare-core-js-first.jsonLG 2017 TV, stress test, 500 passes, performance trace
solid-js-default-bench.txtSolidTV demo app, default build, 5 runs
solid-js-default-bench-spackle.txtSolidTV demo app, with Spackle, 5 runs