sycho/codecs-base64vlq
Base64 VLQ codec for PHP: encode and decode variable-length quantity values using Base64 VLQ, the compact format commonly used in source maps. Lightweight and easy to integrate into PHP or Laravel projects that need VLQ serialization.
The package is a single-purpose codec: it encodes and decodes integers using the Base64 VLQ algorithm that JavaScript source maps use in the mappings field. That gives you the fastest possible path to "getting started":
composer require sycho/codecs-base64vlq
vendor/sycho/codecs-base64vlq/ first — the library is tiny and you'll learn the public API in a couple of minutes faster than any docs (the repo has no usage docs beyond a short description).src/. You'll typically find an encoder/decoder class (e.g., Base64VLQ or a Codec interface implementation) exposing encode(int): string and decode(string): int style static or instance methods. Run a quick sanity check:
use Sycho\Codecs\Base64VLQ\Base64VLQ;
var_dump(Base64VLQ::encode(16)); // expect "gB"
var_dump(Base64VLQ::decode('gB')); // expect 16
(Verify against the actual methods in src/ before writing tests — the class name may differ slightly.)Your first real use case should be decoding a source-map mappings segment. That's the reason this codec exists in the wild: source maps encode each absolute integer in the mappings array as a Base64 VLQ string, and the decoder turns those back into the column/line offsets you need in Laravel tooling (stack-trace de-minification, asset diagnostics, CI reporting).
If you just need to parse a full source map, wrap this package in source-map or your own thin layer — this package is intentionally a primitive, not a source-map parser.
1. Decoding a source-map segment
The mappings field is a stream of Base64 VLQ values separated by , (segment) and ; (line). The typical pattern:
// Pull the mappings string from a .map file
$map = json_decode(file_get_contents($path), true);
$lines = explode(';', $map['mappings']);
foreach ($lines as $lineIndex => $line) {
if ($line === '') continue;
$prevColumn = 0;
foreach (explode(',', $line) as $segment) {
// Each character in $segment is a Base64 VLQ digit —
// split by digits? No: the codec consumes the whole segment.
$values = $this->decodeSegment($segment); // custom helper
// [0] = generated column (delta)
// [1] = source index (delta)
// [2] = source line (delta)
// [3] = source column (delta)
// [4] = name index (delta, optional)
}
}
The Base64 VLQ codec decodes integers, not comma-separated segments — you must split on , first, then feed each contiguous run of base64 digits into the decoder. Be aware that a single logical value can span multiple decode calls if you naively split on character boundaries; read the whole segment as one token.
2. Encoding for tooling that emits maps
If you're generating a .map file (e.g., a Blade/CSS asset pipeline that produces a small source map), build the segments in order and let the codec encode the integers. The values must be relative deltas against the previous segment on the same line, and the first value in each line is a delta from column 0.
$encoded = '';
$prevCol = $prevSrc = $prevLine = $prevSrcCol = 0;
foreach ($segments as $seg) {
$encoded .= Base64VLQ::encode($seg['col'] - $prevCol);
$encoded .= Base64VLQ::encode($seg['src'] - $prevSrc);
$encoded .= Base64VLQ::encode($seg['line'] - $prevLine);
$encoded .= Base64VLQ::encode($seg['srcCol'] - $prevSrcCol);
$prevCol = $seg['col']; /* etc. */
$encoded .= ',';
}
3. Wrapping it in a service
Because of the 0-star / 0-dependent status, treat this package as a transitive utility, not a framework dependency. Wrap it:
final class SourceMapMappings
{
public function decode(string $segment): array { /* call codec */ }
public function encode(int $value): string { return Base64VLQ::encode($value); }
}
This isolates your app from the package's unversioned API and lets you swap in your own 40-line implementation if the library is abandoned.
4. Integration spots in a Laravel app
vite emits .map files in public/build/).php artisan sourcemap:decode path/to/file.js.map for developer debugging.5. Testing
Assert against known-good pairs from the source-map spec: 0 → "A", 1 → "C", -1 → "D", 16 → "gB", 1234 → "iBE". This is the cleanest way to verify the package behaves as advertised before you build on it.
composer.json, and keep a fallback implementation handy — the algorithm is ~80 lines with base64_decode/manual bit-shifting.($v >> 1) ^ -($v & 1) yourself, or check whether the package exposes a signed variant. Do not assume decode() returns the "real" number without verifying.0x20). Base64 VLQ uses one continuation bit per character. A single number is one or more characters. If your segment splitter treats each character as a separate number, decoding breaks silently. Always hand complete segments to the decoder.base64_decode alphabet order. Source maps use the standard 64-character set but map digits to A..Z a..z 0..9 + /. base64_decode() alone will not work — that's precisely why this package exists. Don't try to shortcut it.php artisan vendor:publish. Register a binding or just use the class directly; the package is framework-agnostic by design.? union type guarantees. Given the package's age signals, run composer check-platform-reqs and add a CI matrix entry for your target PHP version before promoting it to production.int overflow on 32-bit builds. Base64 VLQ in source maps is capped at the JS safe integer range, but the encoder should be int-based. Test with large values (2**31, 2**32) if you run on 32-bit PHP.--verbose flag to your decoder command that prints the raw encoded substring alongside the decoded value.Codec interface with encode/decode — the package's single-purpose design makes it a clean primitive to compose, but not something to build a plugin system around.How can I help you explore Laravel packages today?