Vercel Labs 发布 27.4KB 语言无关的 WebGPU 语法高亮工具 gpu-lexer

Hacker News 热门(buzzing.cc 中文翻译)·2026-09-09 21:13·28分钟前·bpierre
AI 导读

Vercel Labs 发布实验性语法高亮工具 gpu-lexer,用 27.4KB 的 WebGPU 模型对任意语言源码做 token 标注,无需按语言选择语法。在 5.56M 字符输入上高亮耗时 402ms,快于 Prism.js 和 Shiki;在留出文件上与 Shiki 的标注一致率为 88.02%,Top-25 加权一致率 90.35%,作者强调这是实验而非语法等价的高亮器。

Hacker News 热门(buzzing.cc 中文翻译)
61AI 编辑部评分,满分 100

Vercel Labs 发布 27.4KB 语言无关的 WebGPU 语法高亮工具 gpu-lexer

2026-09-09 21:13· 28分钟前· bpierre
AI 导读

Vercel Labs 发布实验性语法高亮工具 gpu-lexer,用 27.4KB 的 WebGPU 模型对任意语言源码做 token 标注,无需按语言选择语法。在 5.56M 字符输入上高亮耗时 402ms,快于 Prism.js 和 Shiki;在留出文件上与 Shiki 的标注一致率为 88.02%,Top-25 加权一致率 90.35%,作者强调这是实验而非语法等价的高亮器。

27.4KB language-agnostic1WebGPU syntax highlighter

Shu DingatVercel Labs

import { parse } from 'gpu-lexer'

const spans = await parse('source code')
// {
//   type: 'plain' | 'comment' | 'string' | 'number' | 'keyword' | 'type' | 'function' | 'constant' | 'operator'
//   start: number
//   end: number
// }[]

gpu-lexer splits source code into simple parts—words, whitespace, newlines, and symbols. Then a tiny WebGPU model combines local and whole-file context to label each part. It is designed for any language: instead of choosing a grammar, it guesses each part's type from the surrounding source, even when it never saw that language or syntax during training. Adjacent labels become the syntax spans returned to your code.

This is an experiment, not a grammar-equivalent highlighter. On files kept out of training,11.98% of the current model's token labels differ from Shiki. This measures agreement with Shiki—not objective correctness—and unseen languages or real-world code may differ more often.

Highlight 10× three.min.jswarmed browser time · lower is better

0s 8.00s 16.0s 24.0s 32.0s

gpu-lexer 402.0ms

Sugar High 836.2ms

Prism.js 1.16s

Highlight.js 1.29s

Starry Night 11.0s

Shiki 29.6s

One browser run after one warm-up on September 9, 2026. The input was 10 concatenated copies ofthree.min.js(5.56M characters). MacBook Pro, Apple M4 Pro, 20-core GPU, 24GB, macOS 26.6.2, Chrome 152. Each engine ran in a dedicated worker; DOM rendering was excluded. gpu-lexer and Shiki returned token data, Starry Night returned a HAST tree, while Sugar High, Prism.js, and Highlight.js returned highlighted HTML. Sugar High 2.3.1, Prism.js 1.30.0, Highlight.js 11.12.0, Starry Night 3.11.0, and Shiki 4.4.3.

Loaded library sizeruntime + selected language coverage · lower is better

0KB 390.6KB 781.3KB 1.14MB 1.53MB

Sugar High (major 6 web languages)5.4KB

Prism.js (major 6 web languages)8.6KB

Sugar High (all 29 languages)8.8KB

Highlight.js (major 6 web languages)14.9KB

gpu-lexer (one model)27.4KB

Prism.js (all 297 languages)162.1KB

Starry Night (major 6 web languages)185.3KB

Shiki (major 6 web languages)213.9KB

Highlight.js (all 193 languages)240.4KB

Shiki (all 242 grammars)991.5KB

Starry Night (all 710 grammars)1.46MB

Minified and Brotli-compressed browser bundles measured on September 9, 2026. Major web includes javascript, typescript, css, html, json, and markdown. gpu-lexer uses the same bundle for every language. Starry Night totals include its Oniguruma WASM payload.

Top-25 weighted agreementpopularity-weighted agreement with Shiki · higher is better

0%25.00%50.00%75.00%100%

Shiki 100%

gpu-lexer 90.35%

Prism.js 86.93%

Highlight.js 84.31%

Starry Night 81.89%

Sugar High 75.93%

Shiki is the 100% normalization reference. Each library's token names are mapped to the same nine classes: plain, comment, string, number, keyword, type, function, constant, and operator. Scores compare non-whitespace source parts across 1,103 held-out files in theGitHub Innovation Graphtop 25 for 2026-Q1, weighted by each language's pusher count. Unsupported languages score zero; corpus size does not affect the weights.

[ live demos ]

75 languages

react.development.js 20KB (capped)

/**

  • @license React
  • react.development.js
  • Copyright (c) Meta Platforms, Inc. and affiliates.
  • This source code is licensed under the MIT license found in the
  • LICENSE file in the root directory of this source tree. */

"use strict"; "production" !== process.env.NODE_ENV && (function () { function defineDeprecationWarning(methodName, info) { Object.defineProperty(Component.prototype, methodName, { get: function () { console.warn( "%s(...) is deprecated in plain JavaScript React classes. %s", info[0], info[1] ); } }); } function getIteratorFn(maybeIterable) { if (null === maybeIterable || "object" !== typeof maybeIterable) return null; maybeIterable = (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || maybeIterable["@@iterator"]; return "function" === typeof maybeIterable ? maybeIterable : null; } function warnNoop(publicInstance, callerName) { publicInstance = ((publicInstance = publicInstance.constructor) && (publicInstance.displayName || publicInstance.name)) || "ReactClass"; var warningKey = publicInstance + "." + callerName; didWarnStateUpdateForUnmountedComponent[warningKey] || (console.error( "Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to this.state directly or define a state = {}; class property with the desired state in the %s component.", callerName, publicInstance ), (didWarnStateUpdateForUnmountedComponent[warningKey] = !0)); } function Component(props, context, updater) { this.props = props; this.context = context; this.refs = emptyObject; this.updater = updater || ReactNoopUpdateQueue; } function ComponentDummy() {} function PureComponent(props, context, updater) { this.props = props; this.context = context; this.refs = emptyObject; this.updater = updater || ReactNoopUpdateQueue; } function noop() {} function testStringCoercion(value) { return "" + value; } function checkKeyStringCoercion(value) { try { testStringCoercion(value); var JSCompiler_inline_result = !1; } catch (e) { JSCompiler_inline_result = !0; } if (JSCompiler_inline_result) { JSCompiler_inline_result = console; var JSCompiler_temp_const = JSCompiler_inline_result.error; var JSCompiler_inline_result$jscomp$0 = ("function" === typeof Symbol && Symbol.toStringTag && value[Symbol.toStringTag]) || value.constructor.name || "Object"; JSCompiler_temp_const.call( JSCompiler_inline_result, "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.", JSCompiler_inline_result$jscomp$0 ); return testStringCoercion(value); } } function getComponentNameFromType(type) { if (null == type) return null; if ("function" === typeof type) return type.$$typeof === REACT_CLIENT_REFERENCE ? null : type.displayName || type.name || null; if ("string" === typeof type) return type; switch (type) { case REACT_FRAGMENT_TYPE: return "Fragment"; case REACT_PROFILER_TYPE: return "Profiler"; case REACT_STRICT_MODE_TYPE: return "StrictMode"; case REACT_SUSPENSE_TYPE: return "Suspense"; case REACT_SUSPENSE_LIST_TYPE: return "SuspenseList"; case REACT_ACTIVITY_TYPE: return "Activity"; } if ("object" === typeof type) switch ( ("number" === typeof type.tag && console.error( "Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue." ), type.$$typeof) ) { case REACT_PORTAL_TYPE: return "Portal"; case REACT_CONTEXT_TYPE: return type.displayName || "Context"; case REACT_CONSUMER_TYPE: return (type._context.displayName || "Context") + ".Consumer"; case REACT_FORWARD_REF_TYPE: var innerType = type.render; type = type.displayName; type || ((type = innerType.displayName || innerType.name || ""), (type = "" !== type ? "ForwardRef(" + type + ")" : "ForwardRef")); return type; case REACT_MEMO_TYPE: return ( (innerType = type.displayName || null), null !== innerType ? innerType : getComponentNameFromType(type.type) || "Memo" ); case REACT_LAZY_TYPE: innerType = type._payload; type = type._init; try { return getComponentNameFromType(type(innerType)); } catch (x) {} } return null; } function getTaskName(type) { if (type === REACT_FRAGMENT_TYPE) return "<>"; if ( "object" === typeof type && null !== type && type.$$typeof === REACT_LAZY_TYPE ) return "<...>"; try { var name = getComponentNameFromType(type); return name ? "<" + name + ">" : "<...>"; } catch (x) { return "<...>"; } } function getOwner() { var dispatcher = ReactSharedInternals.A; return null === dispatcher ? null : dispatcher.getOwner(); } function UnknownOwner() { return Error("react-stack-top-frame"); } function hasValidKey(config) { if (hasOwnProperty.call(config, "key")) { var getter = Object.getOwnPropertyDescriptor(config, "key").get; if (getter && getter.isReactWarning) return !1; } return void 0 !== config.key; } function defineKeyPropWarningGetter(props, displayName) { function warnAboutAccessingKey() { specialPropKeyWarningShown || ((specialPropKeyWarningShown = !0), console.error( "%s: key is not a prop. Trying to access it will result in undefined being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)", displayName )); } warnAboutAccessingKey.isReactWarning = !0; Object.defineProperty(props, "key", { get: warnAboutAccessingKey, configurable: !0 }); } function elementRefGetterWithDeprecationWarning() { var componentName = getComponentNameFromType(this.type); didWarnAboutElementRef[componentName] || ((didWarnAboutElementRef[componentName] = !0), console.error( "Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release." )); componentName = this.props.ref; return void 0 !== componentName ? componentName : null; } function ReactElement(type, key, props, owner, debugStack, debugTask) { var refProp = props.ref; type = { $$typeof: REACT_ELEMENT_TYPE, type: type, key: key, props: props, _owner: owner }; null !== (void 0 !== refProp ? refProp : null) ? Object.defineProperty(type, "ref", { enumerable: !1, get: elementRefGetterWithDeprecationWarning }) : Object.defineProperty(type, "ref", { enumerable: !1, value: null }); type._store = {}; Object.defineProperty(type._store, "validated", { configurable: !1, enumerable: !1, writable: !0, value: 0 }); Object.defineProperty(type, "_debugInfo", { configurable: !1, enumerable: !1, writable: !0, value: null }); Object.defineProperty(type, "_debugStack", { configurable: !1, enumerable: !1, writable: !0, value: debugStack }); Object.defineProperty(type, "_debugTask", { configurable: !1, enumerable: !1, writable: !0, value: debugTask }); Object.freeze && (Object.freeze(type.props), Object.freeze(type)); return type; } function cloneAndReplaceKey(oldElement, newKey) { newKey = ReactElement( oldElement.type, newKey, oldElement.props, oldElement._owner, oldElement._debugStack, oldElement._debugTask ); oldElement._store && (newKey._store.validated = oldElement._store.validated); return newKey; } function validateChildKeys(node) { isValidElement(node) ? node._store && (node._store.validated = 1) : "object" === typeof node && null !== node && node.$$typeof === REACT_LAZY_TYPE && ("fulfilled" === node._payload.status ? isValidElement(node._payload.value) && node._payload.value._store && (node._payload.value._store.validated = 1) : node._store && (node._store.validated = 1)); } function isValidElement(object) { return ( "object" === typeof object && null !== object && object.$$typeof === REACT_ELEMENT_TYPE ); } function escape(key) { var escaperLookup = { "=": "=0", ":": "=2" }; return ( "$" + key.replace(/[=:]/g, function (match) { return escaperLookup[match]; }) ); } function getElementKey(element, index) { return "object" === typeof element && null !== element && null != element.key ? (checkKeyStringCoercion(element.key), escape("" + element.key)) : index.toString(36); } function resolveThenable(thenable) { switch (thenable.status) { case "fulfilled": return thenable.value; case "rejected": throw thenable.reason; default: switch ( ("string" === typeof thenable.status ? thenable.then(noop, noop) : ((thenable.status = "pending"), thenable.then( function (fulfilledValue) { "pending" === thenable.status && ((thenable.status = "fulfilled"), (thenable.value = fulfilledValue)); }, function (error) { "pending" === thenable.status && ((thenable.status = "rejected"), (thenable.reason = error)); } )), thenable.status) ) { case "fulfilled": return thenable.value; case "rejected": throw thenable.reason; } } throw thenable; } function mapIntoArray(children, array, escapedPrefix, nameSoFar, callback) { var type = typeof children; if ("undefined" === type || "boolean" === type) children = null; var invokeCallback = !1; if (null === children) invokeCallback = !0; else switch (type) { case "bigint": case "string": case "number": invokeCallback = !0; break; case "object": switch (children.$$typeof) { case REACT_ELEMENT_TYPE: case REACT_PORTAL_TYPE: invokeCallback = !0; break; case REACT_LAZY_TYPE: return ( (invokeCallback = children._init), mapIntoArray( invokeCallback(children._payload), array, escapedPrefix, nameSoFar, callback ) ); } } if (invokeCallback) { invokeCallback = children; callback = callback(invokeCallback); var childKey = "" === nameSoFar ? "." + getElementKey(invokeCallback, 0) : nameSoFar; isArrayImpl(callback) ? ((escapedPrefix = ""), null != childKey && (escapedPrefix = childKey.replace(userProvidedKeyEscapeRegex, "$&/") + "/"), mapIntoArray(callback, array, escapedPrefix, "", function (c) { return c; })) : null != callback && (isValidElement(callback) && (null != callback.key && ((invokeCallback && invokeCallback.key === callback.key) || checkKeyStringCoercion(callback.key)), (escapedPrefix = cloneAndReplaceKey( callback, escapedPrefix + (null == callback.key || (invokeCallback && invokeCallback.key === callback.key) ? "" : ("" + callback.key).replace( userProvidedKeyEscapeRegex, "$&/" ) + "/") + childKey )), "" !== nameSoFar && null != invokeCallback && isValidElement(invokeCallback) && null == invokeCallback.key && invokeCallback._store && !invokeCallback._store.validated && (escapedPrefix._store.validated = 2), (callback = escapedPrefix)), array.push(callback)); return 1; } invokeCallback = 0; childKey = "" === nameSoFar ? "." : nameSoFar + ":"; if (isArrayImpl(children)) for (var i = 0; i < children.length; i++) (nameSoFar = children[i]), (type = childKey + getElementKey(nameSoFar, i)), (invokeCallback += mapIntoArray( nameSoFar, array, escapedPrefix, type, callback )); else if (((i = getIteratorFn(children)), "function" === typeof i)) for ( i === children.entries && (didWarnAboutMaps || console.warn( "Using Maps as children is not supported. Use an array of keyed ReactElements instead." ), (didWarnAboutMaps = !0)), children = i.call(children), i = 0; !(nameSoFar = children.next()).done;

    )
      (nameSoFar = nameSoFar.value),
        (type = childKey + getElementKey(nameSoFar, i++)),
        (invokeCallback += mapIntoArray(
          nameSoFar,
          array,
          escapedPrefix,
          type,
          callback
        ));
  else if ("object" === type) {
    if ("function" === typeof children.then)
      return mapIntoArray(
        resolveThenable(children),
        array,
        escapedPrefix,
        nameSoFar,
        callback
      );
    array = String(children);
    throw Error(
      "Objects are not valid as a React child (found: " +
        ("[object Object]" === array
          ? "object with keys {" + Object.keys(children).join(", ") + "}"
          : array) +
        "). If you meant to render a collection of children, use an array instead."
    );
  }
  return invokeCallback;
}
function mapChildren(children, func, context) {
  if (null == children) return children;
  var result = [],
    count = 0;
  mapIntoArray(children, result, "", "", function (child) {
    return func.call(context, child, count++);
  });
  return result;
}
function lazyInitializer(payload) {
  if (-1 === payload._status) {
    var ioInfo = payload._ioInfo;
    null != ioInfo && (ioInfo.start = ioInfo.end = performance.now());
    ioInfo = payload._result;
    var thenable = ioInfo();
    thenable.then(
      function (moduleObject) {
        if (0 === payload._status || -1 === payload._status) {
          payload._status = 1;
          payload._result = moduleObject;
          var _ioInfo = payload._ioInfo;
          null != _ioInfo && (_ioInfo.end = performance.now());
          void 0 === thenable.status &&
            ((thenable.status = "fulfilled"),
            (thenable.value = moduleObject));
        }
      },
      function (error) {
        if (0 === payload._status || -1 === payload._status) {
          payload._status = 2;
          payload._result = error;
          var _ioInfo2 = payload._ioInfo;
          null != _ioInfo2 && (_ioInfo2.end = performance.now());
          void 0 === thenable.status &&
            ((thenable.status = "rejected"), (thenable.reason = error));
        }
      }
    );
    ioInfo = payload._ioInfo;
    if (null != ioInfo) {
      ioInfo.value = thenable;
      var displayName = thenable.displayName;
      "string" === typeof displayName && (ioInfo.name = displayName);
    }
    -1 === payload._status &&
      ((payload._status = 0), (payload._result = thenable));
  }
  if (1 === payload._status)
    return (
      (ioInfo = payload._result),
      void 0 === ioInfo &&
        console.error(
          "lazy: Expected the result of a dynamic import() call. Instead received: %s\n\nYour code should look like: \n  const MyComponent = lazy(() => import('./MyComponent'))\n\nDid you accidentally put curly braces around the import?",
          ioInfo
        ),
      "default" in ioInfo ||
        console.error(
          "lazy: Expected the result of a dynamic import() call. Instead received: %s\n\nYour code should look like: \n  const MyComponent = lazy(() => import('./MyComponent'))",
          ioInfo
        ),
      ioInfo.default
    );
  throw payload._result;
}
function resolveDispatcher() {
  var dispatcher = ReactSharedInternals.H;
  null === dispatcher &&
    console.error(
      "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem."
    );
  return dispatcher;
}
function releaseAsyncTransition() {
  ReactSharedInternals.asyncTransitions--;
}
function enqueueTask(task) {
  if (null === enqueueTaskImpl)
    try {
      var requireString = ("require" + Math.random()).slice(0, 7);
      enqueueTaskImpl = (module && module[requireString]).call(
        module,
        "timers"
      ).setImmediate;
    } catch (_err) {
      enqueueTaskImpl = function (callback) {
        !1 === didWarnAboutMessageChannel &&
          ((didWarnAboutMessageChannel = !0),
          "undefined" === typeof MessageChannel &&
            console.error(
              "This browser does not have a MessageChannel implementation, so enqueuing tasks via await act(async () => ...) will fail. Please file an issue at https://github.com/facebook/react/issues if you encounter this warning."
            ));
        var channel = new MessageChannel();
        channel.port1.onmessage = callback;
        channel.port2.postMessage(void 0);
      };
    

[...redacted for DOM render perf...]

https://unpkg.com/react@19.2.8/cjs/react.development.js

来源:Hacker News 热门(buzzing.cc 中文翻译)· gpu-lexer.vercel.app