Files
KVideo/scripts/transpile-client-assets.mjs
kuekhaoyang 1179148031 fix: avoid false-positive WebView transpile guard failures
Keep chrome69 downleveling for Android 9 WebViews, but only hard-fail on
logical assignment after transpile. Regex/polyfill feature detects and
minified ternaries can contain `??`/`?.` character sequences that are not
optional chaining or nullish coalescing operators.
2026-07-25 14:48:28 +08:00

94 lines
2.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
import { promises as fs } from 'node:fs';
import path from 'node:path';
import { transform } from 'esbuild';
// Android 9 / Amlogic TV WebViews are often Chrome 6674.
// chrome83 still emits `??` (Chrome 80+), which white-screens those devices.
// chrome69 downlevels `??` / `?.` / logical assignment in application code.
const TARGET = 'chrome69';
// Hard-fail only on logical assignment: unambiguous and never appears in polyfill
// feature-detect regexes (e.g. `/()??/`) or minified ternaries (`E?.3:1`).
const UNSUPPORTED_LOGICAL_ASSIGNMENT = /(\?\?=|\|\|=|&&=)/;
async function pathExists(filePath) {
try {
await fs.access(filePath);
return true;
} catch {
return false;
}
}
async function collectJavaScriptFiles(rootDir) {
const entries = await fs.readdir(rootDir, { withFileTypes: true });
const files = [];
for (const entry of entries) {
const entryPath = path.join(rootDir, entry.name);
if (entry.isDirectory()) {
files.push(...await collectJavaScriptFiles(entryPath));
continue;
}
if (entry.isFile() && entry.name.endsWith('.js')) {
files.push(entryPath);
}
}
return files;
}
async function transpileFile(filePath) {
const source = await fs.readFile(filePath, 'utf8');
const result = await transform(source, {
target: TARGET,
loader: 'js',
minify: true,
legalComments: 'none',
});
await fs.writeFile(filePath, result.code);
if (UNSUPPORTED_LOGICAL_ASSIGNMENT.test(result.code)) {
throw new Error(`${filePath} still contains logical assignment syntax after ${TARGET} transpilation.`);
}
}
async function main() {
const roots = process.argv.slice(2);
const assetRoots = roots.length > 0 ? roots : ['.next/static', '.vercel/output/static/_next/static'];
let processedFiles = 0;
let existingRoots = 0;
for (const root of assetRoots) {
const rootDir = path.resolve(process.cwd(), root);
if (!await pathExists(rootDir)) {
continue;
}
existingRoots += 1;
const files = await collectJavaScriptFiles(rootDir);
for (const file of files) {
await transpileFile(file);
processedFiles += 1;
}
}
if (existingRoots === 0) {
console.log(`No client asset directories found for ${TARGET} transpilation.`);
return;
}
console.log(`Transpiled ${processedFiles} client JavaScript asset(s) for ${TARGET}.`);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});