mirror of
https://github.com/lancedikson/bowser
synced 2026-09-22 20:14:20 +00:00
`bundled.js` stopped being ES5 when the webpack build was replaced by tsdown in #628. It parses at ecmaVersion 2015 but not 5: var t=(t,e)=>()=>(e||(t((e={exports:{}}).exports,e),t=null),e.exports) That is rolldown's `__commonJS` interop helper. `@rolldown/plugin-babel` only transforms input modules, and rolldown appends the helper afterwards; terser with `ecma: 5` avoids introducing newer syntax but does not transpile, so the arrow functions reached the published file. `es5.js` has no CommonJS dependencies and never gets the helper, which is why only `bundled.js` broke. The effect is total rather than partial: in an ES5 engine the whole script is a SyntaxError, so `bundled.js` — the bundle that exists specifically to serve those engines, polyfills included — does not load at all there. Lower the emitted chunk with a babel renderChunk pass that runs after bundling and before terser, so rolldown's own helpers are covered too. Costs 2.8 kB (+1.6%) on bundled.js; es5.js is unchanged at 34 kB. The existing guard was a grep for backticks, which this syntax slips straight past. Replace it with an acorn parse at ecmaVersion 5 over both legacy bundles, plus a tokeniser check for real template literals (backticks inside core-js string literals are fine, and 2.14.1 shipped three of them). Verified by reverting the build fix: `bundled.js parses as ES5` fails, and passes again once restored. Also confirmed bundled.js loads and parses the live navigator.userAgent in a real browser.
51 lines
2.1 KiB
JavaScript
51 lines
2.1 KiB
JavaScript
import test from 'ava';
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
import * as acorn from 'acorn';
|
|
|
|
/**
|
|
* `es5.js` and `bundled.js` exist to serve browsers that predate ES2015. If a
|
|
* single arrow function or template literal reaches either file, the whole
|
|
* script is a SyntaxError there and bowser is not merely degraded, it is dead.
|
|
*
|
|
* A grep for backticks is not enough. When the webpack build was replaced by
|
|
* tsdown, rolldown's `__commonJS` interop helper — appended *after* babel runs,
|
|
* and left alone by terser, which avoids introducing new syntax but does not
|
|
* transpile — shipped arrow functions into `bundled.js`:
|
|
*
|
|
* var t=(t,e)=>()=>(e||(t((e={exports:{}}).exports,e),t=null),e.exports)
|
|
*
|
|
* Parsing the emitted files at `ecmaVersion: 5` is the only check that covers
|
|
* the whole file, including helpers no source-level transform ever sees.
|
|
*
|
|
* These are build outputs — run `pnpm build` before `pnpm test`.
|
|
*/
|
|
const root = path.join(__dirname, '..', '..');
|
|
|
|
const legacyBundles = ['es5.js', 'bundled.js'];
|
|
|
|
legacyBundles.forEach((file) => {
|
|
test(`${file} parses as ES5`, (t) => {
|
|
const source = fs.readFileSync(path.join(root, file), 'utf8');
|
|
t.notThrows(
|
|
() => acorn.parse(source, { ecmaVersion: 5 }),
|
|
`${file} contains syntax newer than ES5 — it will throw on load in the `
|
|
+ 'browsers this bundle exists to support',
|
|
);
|
|
});
|
|
|
|
test(`${file} contains no template literals`, (t) => {
|
|
// Backticks inside string literals are fine (core-js has a few). Only a
|
|
// real template-literal token is a problem, so tokenise rather than grep.
|
|
const source = fs.readFileSync(path.join(root, file), 'utf8');
|
|
const templates = [...acorn.tokenizer(source, { ecmaVersion: 2020 })]
|
|
.filter((token) => token.type.label === '`' || token.type.label === 'template');
|
|
t.is(templates.length, 0, `${file} contains a template literal`);
|
|
});
|
|
});
|
|
|
|
test('bowser.mjs is a valid ES module', (t) => {
|
|
const source = fs.readFileSync(path.join(root, 'bowser.mjs'), 'utf8');
|
|
t.notThrows(() => acorn.parse(source, { ecmaVersion: 'latest', sourceType: 'module' }));
|
|
});
|