oxc-project

Stars and mentions

Last 30 days, Oct 4 – Nov 2

GitHub stars1,579
mentions62
04896144192Oct 4Oct 18Nov 2
UTC days · repositories oxc-project owns5 repositories

Package downloads

Cumulative recorded downloads · since 2025-10-19

crates.io—
npm132.2M
033.1M66.1M99.2M132.2MOct 4Oct 18Nov 2
Oct 27crates.io: 0/6 packages observed · npm: 1/6 packages observed

Across 12 known packages in repositories oxc-project owns. Cumulative totals include recorded downloads before the selected range. Missing observations leave gaps; totals may be incomplete.

Top repositories

oxc-project’s repositories ranked by new stars, as on trending.

Loading

Contributes to

Repositories outside oxc-project’s account where oxc-project opened or reviewed pull requests in the past 365 days.

Who noticed oxc-project

Everyone who starred or forked oxc-project’s repositories since the archive began in 2011.

Notable accounts

Ordered by the stars their own repositories have received.

Biggest fans

Accounts that starred the most of these repositories.

Breakout weeks

Each repository’s best week of new stars, with the release published around it.

Mentions

62posts
Nov 31 post
  1. 今まさにAI slopして型パズルのためのクライアントサイドオンリーのアプリを作ってるんだけど、@\tsrs/wasmを使っています。 #TSKaigi #TSKaigiSendai github.com/oxc-project/tsrs/blob/main/npm/tsrs-wa…

    4 likes · 373 views
  2. JSX が JavaScript になるまで React のコンポーネントには、こんなコードを書きます。 return <h1 className="title">Hello, {name}!</h1>; 見た目はほとんど HTML です。でも、よく見ると HTML ではありません。React の JSX では、属性は class ではなく className ですし、{name} のように JavaScript の式がそのまま埋め込まれています。かといって、JavaScript にも return の後ろにタグを書く構文はありません。 では、ブラウザはこのタグを HTML として読んでいるのでしょうか。それとも JavaScript として読んでいるのでしょうか。 答えはどちらでもありません。ブラウザに届く時点で、このタグはもう残っていないからです。筆者も「ビルドのときに何かに変換されている」ことは知っていました。ただ、何に変換されて、ブラウザが最終的に何を受け取っているのかは説明できませんでした。この記事では、変換の途中でできるもの(中間生成物)を 1 つずつ取り出しながら、.jsx に書いたタグが JavaScript になり、実行されて何を返すのかまでを追いかけます。 この記事の前提 環境: React 19.3.1 / react-dom 19.3.1 / Node.js v26.12.1 / macOS ブラウザでの確認: Vite 8.3.5(@vitejs/plugin-react 6.1.2)/ Google Chrome 156.0.8078.80 変換ツール: Babel(@babel/core 8.0.9・@babel/preset-react 8.0.1・@babel/parser 8.0.8)を主に使い、比較用に TypeScript 7.0.2 の tsc / SWC(@swc/core 1.16.20)/ esbuild 0.28.2 / Oxc(oxc-transform 0.156.0)も使います。TSX のコラムでは、ほかに @babel/preset-typescript 8.0.7・@babel/plugin-syntax-typescript 8.0.3・@types/react 19.3.0 を使います 対象: React の標準の変換方式(automatic runtime)。断りがない限り、開発用の出力(development)はオフにした結果を載せています 題材: 小さなコンポーネントを書いた App.jsx が中心です。TypeScript(.tsx)の場合に何が変わるかは、末尾のコラムで扱います 範囲外: 変換後のオブジェクトが Fiber になり DOM に反映される過程(reconcile)、Hooks の実装、Server Components 記事中のログ・エラーメッセージ・出力は、すべて筆者が上記環境で実際に採取したものです。AST のダンプと 5 つのツールの比較は、それぞれのツールを Node.js から呼ぶ小さなスクリプトによるものです 全体像 パーサー — JSX を構文として読める。ソースを AST(構文木)にし、タグを JSXElement などのノードとして表す。各変換ツールが内蔵している(Babel なら @babel/parser) 変換 — AST の JSX のノードを関数呼び出し(_jsx(...))に書き換え、呼び出し先の import を差し込む。Babel・SWC・esbuild・Oxc・tsc などが担う ランタイム(react/jsx-runtime) — 変換後の _jsx(...) の呼び出し先。React Element と呼ばれるただのオブジェクトを返す レンダラー(react-dom) — React Element を受け取り、ブラウザでは DOM を組み立てる(サーバーでは HTML 文字列にもできる)。この記事では中身には踏み込まない ブラウザが受け取っているのは、タグが関数呼び出しに置き換わった普通の JavaScript です。 その JavaScript を実行したあと、react-dom が DOM を組み立てます。 どの関数をどの形で呼ぶかは、JSX の構文自体には決まっていません。React の automatic runtime では、呼ぶのは react/jsx-runtime の jsx(type, props, key) で、この形は React が定めた約束です。変換ツールは、呼び出し先の設定(importSource など)で指定された先に向けて、この約束どおりに書き換えます。そのため、どの変換ツールを使っても、ほぼ同じ JavaScript になります。 課題 — React を書いていて浮かぶ疑問 冒頭の疑問ともう 1 つ、次の 2 つに答えます。 ブラウザは JSX のタグを HTML として読んでいるのか、JavaScript として読んでいるのか JavaScript はスクリプト言語で、書いたファイルをそのまま渡せば動くはずなのに、なぜ React のプロジェクトはデプロイの前にビルドが要るのか 題材は、Fragment(<>)・属性・埋め込みの式・イベントハンドラ・key が一通り入った小さなコンポーネントです。 // App.jsx import { useState } from "react"; export function App({ name }) { const [count, setCount] = useState(0); return ( <> <h1 className="title">Hello, {name}!</h1> <button onClick={() => setCount(count + 1)}> count is {count} </button> {[1, 2].map((n) => <li key={n}>{n}</li>)} </> ); } 試したこと — 中間生成物を段階ごとに取り出す 段階 0: JavaScript のエンジンは JSX を読めない まず、変換をせずにそのまま実行してみます。JSX を含むファイルを .mjs として Node.js に渡しました。 $ node stage0/hello.mjs const el = <h1>hi</h1>; ^ SyntaxError: Unexpected token '<' タグの 1 文字目 < で構文エラーです。拡張子を .jsx にした場合は、プロジェクトの設定で結果が変わりました。package.json が "type": "module" なら構文を読む前に ERR_UNKNOWN_FILE_EXTENSION で弾かれ、CommonJS なら .js として読まれて同じ SyntaxError になります。 変換をしない静的なサーバーから、次の HTML を Chrome で開きました。 <script type="module"> const el = <h1>hi</h1>; </script> コンソールには、Node.js と同じエラーが出ました。 SyntaxError: Unexpected token '<' JSX は ECMAScript(JavaScript の標準仕様)には入っていない構文拡張です。JSX 自体の仕様の草案(react/jsx、旧 facebook/jsx)も、エンジンやブラウザが実装することは想定していないと冒頭で断っていて、何に変換されるかも定めていません。つまり、ブラウザは JSX を HTML としても JavaScript としても読めません。JSX は、ブラウザに届く前に必ず誰かが JavaScript に変換している構文です。1 つ目の疑問への答えの半分がこれです。 2 つ目の疑問「なぜビルドが要るのか」の答えの中心も、ここにあります。ブラウザに渡す前に JSX を JavaScript へ変換する工程が要り、それを担っているのがビルドです。開発中に同様の変換をしているのは開発サーバーで、その様子は段階 2 の最後で見ます。 段階 1: パーサー — タグは JSX 専用のノードになる 最初の仕事は、JSX を読めるパーサーで AST を作ることです。Babel のパーサー(@babel/parser に jsx プラグインを付けたもの)で、return (...) の中身をダンプしました。長いので <h1> と <button> の部分を抜きます。 JSXFragment JSXOpeningFragment JSXText "\n " JSXElement JSXOpeningElement JSXIdentifier "h1" JSXAttribute JSXIdentifier "className" StringLiteral "title" JSXText "Hello, " JSXExpressionContainer Identifier "name" JSXText "!" JSXClosingElement JSXIdentifier "h1" JSXText "\n " JSXElement JSXOpeningElement JSXIdentifier "button" JSXAttribute JSXIdentifier "onClick" JSXExpressionContainer ArrowFunctionExpression (略) JSXText "\n count is " JSXExpressionContainer Identifier "count" JSXText "\n " JSXClosingElement JSXIdentifier "button" (以下 map の JSXExpressionContainer) 普通の JavaScript の AST には無い、JSX で始まるノードが並んでいます。タグ名の h1 も、JavaScript の識別子を表す Identifier ではなく、JSXIdentifier という別の種類のノードです。大文字・小文字・ドット付きのタグを並べたファイルでも確かめました。 // Main.jsx import { App } from "./App.jsx"; export const page = <App name="World" />; export const tag = <app name="World" />; export const member = <ui.Button />; --- page JSXElement JSXOpeningElement JSXIdentifier "App" JSXAttribute JSXIdentifier "name" StringLiteral "World" --- tag JSXElement JSXOpeningElement JSXIdentifier "app" (略) --- member JSXElement JSXOpeningElement JSXMemberExpression JSXIdentifier "ui" JSXIdentifier "Button" Babel のパーサーでは、大文字の App も小文字の app も同じ JSXIdentifier でした。この時点ではまだ「HTML の要素か、自作のコンポーネントか」を区別していません(Oxc のように、パースの時点で区別するパーサーもあります)。 段階 2: 変換 — JSX が関数呼び出しになる App.jsx を Babel(@babel/preset-react、automatic runtime)で変換し、dist-jsx/App.js に書き出しました。 import { useState } from "react"; import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime"; export function App({ name }) { const [count, setCount] = useState(0); return /#PURE/_jsxs(_Fragment, { children: [/#PURE/_jsxs("h1", { className: "title", children: ["Hello, ", name, "!"] }), /#PURE/_jsxs("button", { onClick: () => setCount(count + 1), children: ["count is ", count] }), [1, 2].map(n => /#PURE/_jsx("li", { children: n }, n))] }); } タグが _jsxs("h1", { className: "title", children: [...] }) という関数呼び出しに書き換わりました。 2 行目の import は、ソースには書いていません。呼び出す関数(react/jsx-runtime の jsx / jsxs)がどこから来るかを書かないと動かないので、変換ツールが自分で差し込んだものです。_jsx は、その jsx を別名で import したものです。/#PURE/ は「戻り値を使っていなければ消してよい」というバンドラ向けの注釈(PURE 注釈)です。 出力には、ほかにも決まりがあります。 属性と子は 1 つのオブジェクト(props)にまとめられ、子は props.children に入る 改行を含む空白だけのテキストを除いて、ソースに書いた子が複数なら _jsxs、1 つ以下なら _jsx になる key は props から外れて第 3 引数になる(_jsx("li", { children: n }, n)。例外もありますが、ここでは扱いません) 大文字のタグは変数、小文字のタグは文字列 Babel のパーサーでは区別されていなかった大文字と小文字は、変換の段階で分かれます。Main.jsx の変換結果です。 import { App } from "./App.jsx"; import { jsx as _jsx } from "react/jsx-runtime"; export const page = /#PURE/_jsx(App, { name: "World" }); export const tag = /#PURE/_jsx("app", { name: "World" }); export const member = /#PURE/_jsx(ui.Button, {}); 大文字で始まる App は変数 App の参照に、小文字の app は文字列 "app" に、ドット付きの ui.Button はプロパティの参照になりました。コンポーネント名を大文字で始めなければいけないのは、このルールで HTML の要素名(文字列)と区別されるからです。 5 つのツールで変換して比べる 実際のプロジェクトで JSX を変換しているのは、Babel だけではありません。Next.js は既定で SWC を使い、Vite 8 では Vite 本体の Oxc が JSX を変換していて、@vitejs/plugin-react v6 は Babel への依存をなくしました。そこで、同じ App.jsx を Babel・SWC・esbuild・Oxc・tsc の 5 つで変換しました。設定は 3 つそろえています。automatic runtime、importSource は react、開発用の出力(development)はオフです。 生の出力は見た目がかなり違います。たとえば esbuild はこうです。 import { Fragment, jsx, jsxs } from "react/jsx-runtime"; import { useState } from "react"; function App({ name }) { const [count, setCount] = useState(0); return /* @PURE */ jsxs(Fragment, { children: [ /* @PURE */ jsxs("h1", { className: "title", children: [ "Hello, ", name, "!" ] }), /* @PURE */ jsxs("button", { onClick: () => setCount(count + 1), children: [ "count is ", count ] }), [1, 2].map((n) => /* @PURE */ jsx("li", { children: n }, n)) ] }); } export { App }; import の順番、_jsx か jsx かという名前、PURE 注釈の有無と書き方、整形、export の形がツールごとに違います。そこで import 文と PURE 注釈を消し、名前の先頭の _ と export の形をそろえ、整形し直してから比べるスクリプトを書きました。消した import 文も、import 元は 5 つとも react/jsx-runtime で、違うのは並び順と別名だけでした。 App: 1 distinct normalized output(s) [tsc, babel, swc, esbuild, oxc] function App({name}){const[count,setCount]=useState(0);return jsxs(Fragment,{children:[jsxs("h1",{className:"title",children:["Hello, ",name,"!"]}),jsxs("button",{onClick:()=>setCount(count+1),children:["count is ",count]}),[1,2].map(n=>jsx("li",{children:n},n))]})} 5 つの出力は、書き方の差を除くと完全に一致しました。Main.jsx でも同じで、5 つのツールすべてが大文字のタグを変数、小文字のタグを文字列に分けていました。ui はどこにも定義していませんが、どのツールもそのまま変換しています。変換ツールは、名前の正体を調べていません。 実装は 5 つともまったく別物で、言語も JavaScript(Babel)・Rust(SWC・Oxc)・Go(esbuild・tsc)とバラバラです。それでも出力がそろうのは、関数の形(jsx(type, props, key))と、そこへの渡し方(子は props.children に、key は第 3 引数に、子が複数なら jsxs)までが React の決めた約束で、どのツールもそれに合わせて書き換えているからです。変換ツールはその約束どおりに呼び出しを書けばよく、他のファイルを見る必要がありません。 なお、開発用の出力をオンにすると、同じ正規化でも 4 通りに分かれました。tsc・SWC・esbuild・Oxc はデバッグ用のソースの位置(ファイル名・行・列)を同じ値で渡しますが、ファイル名を変数に入れるか(tsc は const、Oxc は var)直接書くか(SWC・esbuild)が違い、Babel 8 は位置の情報そのものを渡しません。 ブラウザに届く JavaScript を確かめる この形のままブラウザに届くことを、実際のプロジェクトでも確かめました。同じ App.jsx を Vite 8 のプロジェクトに置き、vite build の出力から App の部分を抜き出しました。Vite 8 の変換は、先ほどの 5 つのうちの Oxc です。 return(0,p.jsxs)(p.Fragment,{children:[(0,p.jsxs)(h1,{className:title,children:[Hello, ,e,!]}),(0,p.jsxs)(button,{onClick:()=>n(t+1),children:[count is ,t]}),[1,2].map(e=>(0,p.jsx)(li,{children:e},e))]}) minify(圧縮)で変数名が縮み、文字列の引用符もバッククォートになっています。p はバンドルに取り込まれた react/jsx-runtime を指す変数で、(0,p.jsxs)(...) は this を渡さずに p.jsxs を呼ぶための、バンドラの書き方です。形は Babel の出力と同じ jsxs("h1", { className: "title", children: [...] }) で、出力の中に <h1 という文字列は 1 つもありませんでした。 開発サーバー(vite)でも確かめました。Chrome が App.jsx を要求すると、Content-Type: text/javascript の JavaScript が返ってきます。ブラウザはモジュールとして読み込むファイルの種類を拡張子ではなく Content-Type で判断するので、名前が .jsx のままでも JavaScript として実行します。中身は開発用の _jsxDEV(...)(react/jsx-dev-runtime)の呼び出しでしたが、タグが残っていない点は同じでした。あわせて、import { useState } from "react" も、/node_modules/.vite/deps/react.js?v=… からの import と const useState = …["useState"] という形に書き換わっていました。react の npm パッケージは CommonJS で配布されていてブラウザではそのまま動かないので、Vite が事前に ESM へ変換しておいたファイルです。 ブラウザに届いているのは、タグが消えた関数呼び出しの JavaScript でした。これが 1 つ目の疑問の残り半分の答えです。 段階 3: ランタイム — jsx() はただのオブジェクトを返す では、jsx() は何を返すのでしょうか。変換後の App.js と同じ呼び方で react/jsx-runtime の jsx / jsxs を呼び、戻り値を出力しました(jsx は本来アプリから直接呼ぶ関数ではなく、ここでは観察のために呼んでいます。NODE_ENV=production での結果です)。 --- jsxs("h1", ...) { '$$typeof': Symbol(react.transitional.element), type: 'h1', key: null, ref: null, props: { className: 'title', children: [ 'Hello, ', 'World', '!' ] } } 返ってきたのは、ただのオブジェクトでした。これが React Element です。type にはタグ名の文字列 'h1'、props には属性と子がそのまま入っています。$$typeof の値 Symbol(react.transitional.element) は、このオブジェクトが React Element であることを示す印です。段階 2 で JSX は関数呼び出しになりましたが、その関数がやっているのは「この形のオブジェクトを作る」ことだけです。DOM の要素はまだどこにも作られていません。 コンポーネントでも同じです。App を、呼び出された回数を数える関数 Counted で包んで jsx() に渡すと、type に関数そのものが入ったオブジェクトが返ります。 --- jsx(Counted, { name }) { '$$typeof': Symbol(react.transitional.element), type: [Function: Counted], key: null, ref: null, props: { name: 'World' } } type is the function itself: true | component called: 0 この時点で Counted は 1 回も呼ばれていませんでした。<App /> と書いても、App() が実行されるわけではありません。「App という関数を、この props で呼んでほしい」と書いたオブジェクトができるだけです。いつ呼ぶか(呼ばないか)はレンダラーが決めます。 結果 最後に、Vite の開発サーバーで開いた Chrome のページで、react-dom が組み立てた DOM を見ました。ページ上で document.getElementById("root").innerHTML を評価し、#root の中身を文字列にして取り出したものです。 <h1 class="title">Hello, World!</h1><button>count is 0</button><li>1</li><li>2</li> ここで初めて、画面の要素(DOM)が出てきました。ブラウザでは HTML の文字列を作って流し込んでいるのではなく、react-dom が React Element をもとに DOM を直接組み立てています。className は DOM では class 属性になっています。className は DOM の要素が持つプロパティ名(element.className)に合わせた名前で、class 属性として反映するのはレンダラーの仕事です。 ここまでをまとめると、次のとおりです。 JSX は ECMAScript の構文ではなく、Node.js も Chrome もタグの 1 文字目で SyntaxError を出した(段階 0) Babel のパーサーは、タグを JSXElement・JSXText などのノードにした。大文字のタグも小文字のタグも同じ JSXIdentifier だった(段階 1) JSX は _jsx / _jsxs の呼び出しになり、呼び出し先(react/jsx-runtime)の import が自動で差し込まれた。大文字のタグは変数、小文字のタグは文字列になり、key は props から外れて第 3 引数になった(段階 2) 設定をそろえた 5 つの変換ツールの出力は、書き方の差を除いて一致した(段階 2) Vite のビルド出力にも開発サーバーの応答にも、タグは残っていなかった(段階 2) jsx() は $$typeof・type・key・ref・props を持つただのオブジェクトを返し、コンポーネント関数はこの時点で呼ばれていなかった(段階 3) DOM を組み立てるのは react-dom で、className は class 属性になった 学び JSX の変換は、設定が分かればファイル 1 枚で完結する。 呼び出し先(react/jsx-runtime)と呼び出しの形(jsx(type, props, key))がファイルの外で決まっているので、変換ツールは他のファイルを見ずに書き換えられる。だから開発サーバーは、ブラウザに要求されたファイルだけをその場で変換して返せる 変換後の JSX を実行すると、「何を描画してほしいか」を書いたただのオブジェクトができる。 コンポーネントを呼ぶのも DOM を作るのも、そのオブジェクトを受け取ったレンダラーの仕事 課題に挙げた 2 つの疑問に答えると、こうなります。 「ブラウザは JSX を HTML として読んでいるのか、JavaScript として読んでいるのか」 — タグのままでは、HTML としても JavaScript としても読めません(段階 0)。タグはブラウザに届く前に関数呼び出しへ置き換わっていて、ブラウザはそれを普通の JavaScript として実行します。画面の要素(DOM)は、その実行の結果としてレンダラーが組み立てたものです。 「なぜスクリプト言語の JavaScript なのにビルドが要るのか」 — 書いたファイルが、ブラウザがそのまま実行できる形になっていないからです。その代表が JSX で、JavaScript ではありません。開発サーバーは JSX だけでなく、from "react" のような名前だけの import も、CommonJS で配布されている react を ESM に変換したファイルの URL に書き換えていました。開発中はこの書き換えを開発サーバーがその場でしてくれますが、静的ファイルを配るだけのデプロイ先には、それをしてくれる仕組みがありません。だから、デプロイ前のビルドで済ませておきます。 JSX の挙動で迷ったときは、DevTools の Network タブで届いた App.jsx を開くなどして、変換後の JavaScript を一度のぞいてみるところから始めていきたいですね。 コラム: TSX の場合 — tsx → jsx → js なのか、tsx → ts → js なのか ここまでは .jsx で見てきましたが、TypeScript と組み合わせて .tsx で書くプロジェクトも多くあります。.tsx には型と JSX の 2 つが入っているので、JavaScript になるまでに「型を消す」と「JSX を変換する」の 2 つの変換が要ります。題材の App.tsx は、App.jsx に型を 2 か所足しただけのものです。 type Props = { name: string }; export function App({ name }: Props) { // (以下 App.jsx と同じ) 結論から言うと、どちらの順でもできて、結果は同じでした。automatic runtime では、2 つの変換は互いに独立しているからです(classic runtime では、型を消すときに使われていない import を消す処理が import React を消してしまうことがあり、完全には独立していません)。 まず tsx → jsx → js です。tsc の jsx: preserve は、App.tsx から型を消し、JSX は残したまま App.jsx を出します。 // tsc --jsx preserve の出力(App.jsx) export function App({ name }) { const [count, setCount] = useState(0); return (<> <h1 className="title">Hello, {name}!</h1> (略) これを Babel で変換すれば JavaScript になります。 もう一方の順番の tsx → ts → js も作れます。Babel に TypeScript の構文プラグイン(@babel/plugin-syntax-typescript。構文を読むだけで、型は消さない)を付けて JSX の変換をかけると、型が残ったまま JSX が関数呼び出しになりました。 // Babel(preset-react + TypeScript の構文プラグイン)の出力。型はまだ残っている type Props = { name: string; }; export function App({ name }: Props) { const [count, setCount] = useState(0); return /#PURE/_jsxs(_Fragment, { (略) これを esbuild で型を消して JavaScript にしました。2 つの経路の最終出力を、本文と同じスクリプトで直接変換の結果と比べると、すべて一致しました(出力の見出しは読みやすく書き換えています)。 App: 1 distinct normalized output(s) [直接(tsc), 直接(babel), tsx→ts→js, tsx→jsx→js, 直接(oxc)] TypeScript 7 の実装(typescript-go の typescript/v7.0.2 タグの internal/compiler/emitter.go)で、tsc の変換器(tsc の中で 1 つの変換を受け持つ部品)を並べている getScriptTransformers を見ると、型を消す変換器が先で、JSX の変換器が後でした。 // transform TypeScript syntax { // (中略) // erase types tx = append(tx, tstransforms.NewTypeEraserTransformer(&opts)) // (中略) } if jsxTransformEnabled { tx = append(tx, jsxtransforms.NewJSXTransformer(&opts)) } つまり tsc は tsx → jsx → js の順で、jsx: preserve は、この並びから JSX の変換器だけを外した姿です。ただし中間のファイルはできず、どの変換器も前の変換器が返した AST を受け取り、次の AST を返していくだけです。他のツールも中間のファイルは作りませんが、作りはツールごとに違います。たとえば esbuild は型注釈をパースの時点で読み飛ばすので、そもそも型が AST に残りません。 .tsx で差が出るのは、変換の順番よりも、パーサーの読み方と型検査のほうです。tsc は型を検査するために、import を辿ってコンパイル対象のファイル一式(Program)を集め、名前の正体を解決し、型を計算します。 .tsx という拡張子は、TypeScript のパーサーの読み方を切り替える。.ts では型アサーションとして通る <string>v が、.tsx では TS17008: JSX element 'string' has no corresponding closing tag になった。.tsx でジェネリックなアロー関数を <T,>(x: T) => x とカンマ付きで書くのはこのため tsc --traceResolution で見ると、ソースのどこにも書いていない react/jsx-runtime が、react より先に解決されていた。JSX の型を引くため tsc は @types/react の JSX 名前空間で JSX を検査する。h1 は JSX.IntrinsicElements という interface のプロパティとして解決され、className は HTMLAttributes のプロパティだった。class と書くと TS2322 … Property 'class' does not exist … Did you mean 'className'? になる(それでも JavaScript は出力される) 所要時間は全体で約 0.18 秒で、そのうち Check(型検査の工程)が約 0.16 秒、JSX の変換を含む書き出し(Emit)は 0.001 秒だった。--noCheck を付けると全体で 0.020 秒になる。React を含まない 1 行の .ts と比べると、React の型定義(@types/react の 3 ファイルと csstype)が Program に加わった分、計算された型の数が約 2 倍になっていた。この題材は skipLibCheck を付けていないので、増えた分のほとんどは JSX ではなく型定義ファイル自体の検査だ 変換はファイル 1 枚で終わるのに、検査は呼び出し先の型定義まで Program を広げないとできません。.tsx の JSX は、この 2 つの仕事の重さの差がはっきり見える場所でした。 コラム: React 以外の JSX JSX は Preact・Hono・Vue・Solid でも書けます。構文と AST(段階 0・1)はどのフレームワークでも共通で、違いが出るのは「何の関数を呼ぶか」(段階 2)と「その関数が何を返すか」(段階 3)です。 ! 以下は各フレームワークのドキュメントに基づく整理で、この記事では検証していません。 フレームワーク 変換のしかた(呼び出し先) 返すもの React react/jsx-runtime React Element(ただのオブジェクト) Preact preact/jsx-runtime VNode Hono hono/jsx/jsx-runtime HTML 文字列にできるノード Vue 3 専用の Babel プラグインが生成する関数呼び出し VNode Solid 専用のコンパイラが生成する DOM 操作のコード 実際の DOM ノード(ブラウザ向けの出力) React・Preact・Hono は、jsx-runtime という同じ形の約束の上で返すものだけを差し替えているので、変換ツールの呼び出し先の設定(importSource)を変えるだけで切り替わります。Vue にも vue/jsx-runtime はありますが、公式が案内しているのは専用の Babel プラグインです。Solid はこの約束を使わず、JSX を、DOM を直接組み立てるコードにコンパイルします。 参考 JSX の仕様草案: react.github.io React「Writing Markup with JSX」(className の由来): react.dev React ブログ「Introducing the New JSX Transform」(automatic runtime): legacy.reactjs.org Next.js Compiler(SWC): nextjs.org @vitejs/plugin-react の CHANGELOG(v6 で Babel への依存を削除): github.com/vitejs/vite-plugin-react/blob/main/pac… Oxc: oxc-project/oxc esbuild の設計(型注釈の読み飛ばし): github.com/evanw/esbuild/blob/main/docs/architect… typescript-go internal/compiler/emitter.go(v7.0.2): github.com/microsoft/typescript-go/blob/typescrip… Preact: preactjs.com Hono の JSX: hono.dev Vue「Render Functions & JSX」: vuejs.org Solid の JSX コンパイラ(dom-expressions): ryansolid/dom-expressions

  3. Some good perf engineering and reminder to not use __proto__ 👀 oxc#27816

    33 likes · 2 reposts
  4. React Compiler 導入で画面が更新されなくなった話 〜既存SPAでの主要ライブラリとの衝突と解決の記録〜 ! 検証環境 React 19.2.8 / babel-plugin-react-compiler 1.0.0 Vite 8.1.5 @vitejs/plugin-react 6.0.4 @rolldown/plugin-babel 0.2.4 @babel/core 8.0.7 React Hook Form 7.82.0 TanStack Router 1.170.18 TanStack Table 8.21.3 Vitest 4.1.10 Oxlint 1.75.0 記事中のコード・挙動・リンクはすべて上記バージョンでのものです。公開時点では TanStack Router・Oxlint などに新しいバージョンが出ており、一部の挙動や設定は変わっています。該当箇所ではその旨を注記しています。 はじめに こんにちは☀️ 株式会社AI Shiftでフロントエンドエンジニアをしているさっちゃんです!(X:おさわ / 吉岡 爽) 今回は、プロダクトに React Compiler を導入した際に UI に発生した不具合と、その対処について書きます。 私達のプロダクトでは React を採用し、Vite と TanStack Router を用いて、SPA を構築しています。フォームには React Hook Form、一覧には TanStack Table を使っています。 React Compilerの導入にあたり、導入前の実装をCompilerのON/OFFで比較しました。その中で、React Compiler を有効にしてテストを実行したところ、いくつかの箇所で異常が検知されました。これをきっかけに実際の画面上で動作確認を行った結果、サイドバーが画面遷移に追従しないなど、ユーザーの操作が意図通りにUIへ反映されない不具合が発覚しました。 この記事では、実際の画面の操作へ影響していたこのサイドバーの問題を中心に、設定・切り分け・原因・対処を紹介します。 この記事について 想定読者:React Compiler の導入を検討している方 書くこと 既存の SPA に React Compiler を導入したときの設定 導入前の実装に Compiler を適用し、ON/OFFで挙動を比較した方法 TanStack Routerの不具合と、React Hook Form の挙動変化、その原因・対処 テストの失敗と、実際の画面への影響を分けて確認したこと 書かないこと React Compiler 導入による性能改善の計測結果 React Compiler の内部実装の詳細 SSR / React Server Components 環境での挙動 導入設定 まずは、今回の Vite 8 + Babel プラグイン環境で React Compiler を導入した際の設定を紹介します。 パッケージの追加 React Compiler を導入するため、以下のパッケージをインストールします。 pnpm add -D -E babel-plugin-react-compiler@1.0.0 @rolldown/plugin-babel@0.2.4 @babel/core@8.0.7 Vite Ver.8 ではバンドラに Rolldown、JS/TS や JSX の変換に Oxc が使われています。 また、 @vitejs/plugin-react v6 では内部の Babel 依存が排除されました。そのため、今回使用した v6.0.4 で、Babelプラグインとして提供される React Compiler を適用するために、@rolldown/plugin-babel を組み合わせました。 ! @vitejs/plugin-react 6.1.0 以降では、oxc-transform-react を用いて Babel なしで Compiler を有効化する実験的な機能も追加されています。 react({ compiler: true }) この記事では、より実績があり安定している Babel プラグイン版を対象とします。 参考:@vitejs/plugin-react 6.1.0 (2026-08-19) CHANGELOG.md また、React Compiler はバージョンアップによってメモ化の挙動が変わる可能性があるため、予期せぬ不具合を防ぐ目的で -E フラグを使い、exact バージョンでインストールしています。 vite.config.ts の実装 Compilerに関係する部分を抜き出すと、次のようになります。 import { defineConfig } from "vite"; import react, { reactCompilerPreset } from "@vitejs/plugin-react"; import babel from "@rolldown/plugin-babel"; const compilerPreset = reactCompilerPreset(); compilerPreset.rolldown.filter = { ...compilerPreset.rolldown.filter, id: { exclude: [/node_modules/, /.(test|spec).[jt]sx?$/] }, }; export default defineConfig({ plugins: [ react(), ...(process.env.REACT_COMPILER === "false" ? [] : [babel({ presets: [compilerPreset] })]), ], }); @vitejs/plugin-react が提供する reactCompilerPreset() をベースに、この設定に加えてLintも導入しました。 1. node_modules とテストファイルを変換対象から外す まず、node_modules 配下のライブラリは自分たちが管理しているコードではないため、変換対象から除外しました。 また、.test.* や .spec.* などのテストファイルも外しています。テストコード内で定義したモックやラッパーコンポーネントまで Compiler の対象になってしまうと、テストが失敗したときに、本体の変換による影響なのか、テスト側の変換による影響なのかを切り分けることが難しくなるためです。 2. 環境変数で無効化できるようにする なにか不具合が起きたとき、それが元のコードの問題か、Compiler による変換の影響かを切り分けやすくするために、REACT_COMPILER=false という環境変数を渡すことで、Compiler を無効化した状態で起動・ビルド・テストができるようにしました。 Vitest でも Compiler が適用されているか確認する 先ほどテストファイル(.test.ts など)自体は変換対象から除外しましたが、テストを実行できても、テスト対象のコードにCompilerが適用されていなければ、導入後の挙動を検証したことにはなりません。 reactCompilerPreset() は、Vite の Environment API において「クライアント向けのビルド・変換時」にのみ Babel(Compiler)を適用するように初期設定されています。 Vitest 4 では、jsdom 環境は実際には Node.js 上で実行されるため、モジュールの読み込み自体は SSR(サーバー)側の仕組みを使います。しかし、Vitest 4 が Vite のプラグインパイプライン(Environment API)を呼び出す際、jsdom のようなブラウザの動きを再現する環境では 「コンポーネントの変換(Transform)処理においては Client 環境向けのプラグイン設定を適用する」 という設計になっています (Vitest のソースコード)。 そのため、開発者が vite.config.ts で applyToEnvironment などのフックを上書きして「常に全環境でBabelを動かす」といった設定をしなくても、自動的にテスト用のコンポーネントに Compiler が適用されます。 念のため、コンポーネントの関数を文字列化して、Compiler が挿入するキャッシュ(const $ = ...c(10) のような記述)が含まれているかを直接確認してみました。 import { CommandPalette } from "@/components/ui/CommandPalette"; test("Compiler が適用されている", () => { expect(CommandPalette.toString()).toMatch(/const \$ = .*.c)(\d+)/); }); 設定 結果 初期設定のまま 適用される REACT_COMPILER=false 適用されない 初めは、jsdom 環境には自動適用されないのではと疑い、applyToEnvironmentHook が常に true を返すように設定を上書きしていました。 しかし検証の結果、上書きしなくても正しく適用されることがわかりました。 3. Lint で Rules of React を守る React Compiler が正しく動くには、コードが Rules of React に沿って書かれていることが前提です。 あなたのアプリケーションでコンパイラを導入できるかどうかは、コードベースの健全性と React のルールをどの程度遵守しているかに依存します。 出典:React Compiler:安全に使用できるか? Compiler は、最適化を安全に適用できないと判断したコードについて、対象の最適化をスキップすることがあります。 ルールに違反している可能性のあるコードに遭遇した場合、アプリケーションの動作を変更するリスクを冒すのではなく、最適化を安全にスキップします。 出典:React Compiler:コンパイラの動作を理解する これを防ぐため、Oxlint の react/react-compiler ルールを error レベルで有効にして CI 等で検知できるようにしました。 { "plugins": ["react"], "rules": { "react/react-compiler": "error" } } これで Rules of React への違反をある程度未然に防げます。ただし、Lint が通ったからといって Compiler 由来の不具合が完全にゼロになるわけではありません。この記事で紹介する不具合も、Lint では検出できずテストで発覚したものでした。 ! ここで設定している react/react-compiler は、Oxlint 1.78.0 までのルールです。 1.79.0 で purity・refs・immutability などの個別ルールに分割され、react/react-compiler は削除されました(Oxlint CHANGELOG 1.79.0、Oxc 公式ブログ)。 1.79.0 以降でこの設定を書くと、Rule 'react-compiler' not found in plugin 'react' で設定ファイルの読み込みに失敗します。代わりに次のように設定してください。 { "plugins": ["react"], "categories": { "correctness": "error" } } 検証方法 テストが失敗した際、それが本当にReact Compiler の変換による影響なのかを正確に切り分ける必要がありました。 そこで、Compiler 導入前のコードベースに、設定・依存・比較用のテストを持ち込み、Compiler の ON/OFF 以外の条件を完全にそろえた状態を作って検証を行いました。 以下の手順は、Vitest に unit プロジェクトが定義され、jsdom 環境と、先ほどの Vite プラグイン設定を利用する構成を前提にしています。今回の設定では、extends: true で親の Vite 設定を引き継いでいます。関係する部分を抜き出すと、次のようになります。 // vite.config.ts // pluginsなどは、前述のCompiler設定と同じ export default defineConfig({ plugins: [ // 前述のViteプラグイン設定 ], test: { projects: [ { extends: true, test: { name: "unit", environment: "jsdom", globals: true, include: ["src/**/*.{test,spec}.{ts,tsx}"], }, }, ], }, }); 手順 導入直前のコミットを別ディレクトリに展開する git worktree add ../before <導入直前のコミット> cd ../before Compiler の設定・依存と、比較に使うテストを、導入後のコミットから持ってくる git checkout <導入後のコミット> -- package.json pnpm-lock.yaml vite.config.ts <対象のテストファイル> pnpm install Compiler 無効 REACT_COMPILER=false pnpm vitest run --project unit <対象のテストファイル> Compiler 有効 pnpm vitest run --project unit <対象のテストファイル> Compiler の切り替えには、前の章で用意した環境変数 REACT_COMPILER を使いました。 結果 フォーム・ナビゲーション・共通 UI に関わる77件のテストで比べた結果です(導入時点の計測)。 実装 Compiler 結果 導入前 無効 77件成功 導入前 有効 71件成功・6件失敗 対応後 有効 77件成功 失敗した6件は、次の2種類に分かれました。 種類 件数 症状 TanStack Router を使ったサイドバー 2件 SPA内の遷移後、子ページを含むグループが開かない React Hook Form を使ったダイアログ 4件 キャンセル直後、終了アニメーション中の入力欄に編集値が残る これらの失敗がテスト環境特有のエラーなのか、実際のUIに影響するものなのかを確かめるため、ブラウザ上で実際に操作して挙動を確認しました。 結果として、どちらも Compiler によって実際に画面の挙動が変わってしまった状態でした。ただし、ユーザーへの影響は異なります。サイドバーは現在地のリンクが見えなくなる一方、ダイアログは終了アニメーション中だけ値が残り、再表示時には初期化されていました。 対応の概要 見つかった2つの問題には、それぞれ次のように対処しました。 問題 今回の対処 次のステップ サイドバーのグループが開かない(TanStack Router) useMatchRoute を、毎回新しい関数を返すラッパーフック経由で使う 修正済みの TanStack Router v1.170.27 以降へ上げ、ラッパーを外す キャンセル直後に入力値が残る(React Hook Form) 対象のダイアログに "use no memo" を付け、Compiler の変換対象から外す reset() に keepFieldsRef: true を指定し、"use no memo" を外す どちらも、導入時点では既存の挙動を確実に保つことを優先した一時的な対応です。 特にダイアログの "use no memo" は、Compiler の最適化をあきらめることで不具合を避けている状態です。本来は、Compiler の最適化を受けたまま直せる keepFieldsRef に移行を検討しています。 なお、サイドバー側の "use no memo" は数行のラッパーフックにだけ付けており、サイドバーのコンポーネント自体は引き続き Compiler で最適化されています。 壊れたもの:サイドバーの外から移るとグループが開かない 症状 サイドバーでは、関連する子ページのリンクを、開閉できる見出しの下にまとめています(以下、グループと呼びます)。 現在のページがグループ内の子ページであれば、そのグループを自動で開き、現在地がわかるようにしています。 しかし、サイドバー以外の導線から、ページ全体を再読み込みせずに子ページへ遷移すると、ページ本体は切り替わるのに、サイドバーのグループが開きませんでした。 例えば、アプリ概要から設定グループ内の子ページへ遷移すると、ページ本体は切り替わるのに、サイドバーの設定グループは閉じたままになっていました。 👇 再現用の簡易アプリで、ダッシュボードのカードから「通知」へ移動したときの動き Before(修正前):ページは切り替わるが、サイドバーの「設定」は閉じたまま After(修正後):「設定」が開き、パンくずも「通知」に更新される サイドバーは、以下のように useMatchRoute() でリンクがアクティブかどうかを判定し、その判定関数をグループのコンポーネントに渡していました。 function NavEntryItem({ entry, params }: Props) { const matchRoute = useMatchRoute(); const isActive = (link: NavLink) => matchRoute({ to: link.to, params }) !== false; return <NavGroupItem entry={entry} isActive={isActive} />; } function NavGroupItem({ entry, isActive }: GroupProps) { const hasActiveChild = entry.children.some(isActive); // hasActiveChild が true になったらグループを開く // ... } 原因 useMatchRoute が返す関数は、URL が変わっても同じ参照のままだった 今回使用していた TanStack Router v1.170.18 では、useMatchRoute() の実装は次のようになっていました。型やオプションの処理を省略しています。 ! この節に掲載する Matches.tsx と router.ts のコードは、TanStack Router の実装から、説明に必要な部分を抜粋・簡略化したものです。 ライセンス:MIT License 著作権表記:Copyright (c) 2021-present Tanner Linsley 引用元コミットの LICENSE 全文 実際のソースコードMatches.tsx の実装 export function useMatchRoute() { const router = useRouter() useStore(router.stores.matchRouteDeps, (d) => d) // 👇 router インスタンスだけを依存配列にしている return React.useCallback((opts) => router.matchRoute(/* options を渡す */), [router]) } ブラウザ側ではルーターの状態を購読しているので、URLが変わると、このフックを使うコンポーネントは再レンダーされます。 一方、返す関数の依存配列は [router] なので、同じ router インスタンスを使っている間、URLが変わっても関数の参照は変わりません。 しかし matchRoute は、引数だけで結果が決まるわけではなく、「現在の URL」を読み取って判定を行っています。 ソースコードを確認してみると、router.matchRoute() は、呼び出された時点の現在地をルーターの内部状態から読み取っていました。 実際のソースコード router.ts の実装 // 👇 呼ばれた瞬間に、ルーターから現在地を取得している const baseLocation = this.stores.resolvedLocation.get() || this.stores.location.get() const match = findSingleMatch(next.pathname, /* ... / baseLocation.pathname, / ... */) 同じ matchRoute({ to: "/settings" }) という呼び出しでも、現在の URL によって戻り値が変わります。一致した場合はルートパラメータのオブジェクト、不一致なら false です。そのため、次の式は、アプリ概要ページでは false、設定ページでは true になります。 matchRoute({ to: "/settings" }) !== false; この「参照は同じでも、内部状態によって結果が変わる」という性質が、今回のメモ化と衝突しました。 Compilerによって何がキャッシュされたのかを確認する 実際のコンポーネントを babel-plugin-react-compiler@1.0.0 で変換すると、isActive の生成に次のようなキャッシュが入っていました。 // 【1】matchRoute や params の参照が変わったかチェック if ($[0] !== matchRoute || $[1] !== params) { t1 = (link) => matchRoute({ to: link.to, params }) !== false; // 新しく関数を作る $[0] = matchRoute; $[1] = params; $[2] = t1; // 作った関数をキャッシュに保存 } else { // どちらも変わっていなければ、前回の関数(キャッシュ)を使い回す! t1 = $[2]; } const isActive = t1; // 【2】NavGroupItem に渡す props(entry や isActive)が変わったかチェック if ($[3] !== entry || $[4] !== isActive) { t2 = <NavGroupItem entry={entry} isActive={isActive} />; // 新しいJSX要素を作る // ... } ここで登場する変数は、それぞれ次のものを表しています。 matchRoute:useMatchRoute() が返す、指定した遷移先が現在の URL に一致するか判定する関数です。一致するとルートパラメータのオブジェクト、不一致なら false を返します。 params:遷移先の URL を組み立てるためのルートパラメータです。IDやslug、環境などが入ります。同じID・環境内で概要ページから設定ページへ移る場合、これらの値は変わりません。 entry:サイドバーに表示する項目の定義です。グループの場合は、「設定」のような見出しや、配下に表示する子リンクの情報を持っています。現在のページが変わっても、グループの定義自体は変わりません。 $:Compiler がコンポーネントのインスタンスごとに用意するキャッシュ用の配列です。$[0] には前回の matchRoute、$[1] には前回の params、$[2] には生成した判定関数を保存しています。 t1・t2:Compiler が生成した一時変数です。t1 には isActive として使う判定関数、t2 には <NavGroupItem ... /> という JSX 要素が入ります。 今回の実装では、entry はコンポーネントの外に定義した固定の項目一覧から渡しています。また、Compiler によって、親が作る項目一覧の JSX もキャッシュされていました。今回のページ遷移ではそのキャッシュが再利用されたため、JSX に含まれる params オブジェクトも作り直されませんでした。このため、子が URL の変更を受けて再レンダーされても、entry と params は前回と同じ参照のままでした。 この結果を読み解くと、以下のようになります。 URL が変わり、useMatchRoute() の購読によって親が再レンダーされる matchRoute と params の参照が変わらないため、Compiler によって isActive が再利用される entry と isActive の参照も変わらないため、子へ渡す JSX が再利用される この経路では NavGroupItem の再レンダーが省略され、hasActiveChild が再計算されない 子ページへ移っても、グループが閉じたままになる Compiler なしなら、毎回のレンダーで matchRoute(...) が呼び直されるため、この問題は表に出ていませんでした。 ! この問題は TanStack Router 側でも報告されており(#4499)、v1.170.27 で修正されました(#8015)。 「対応の概要」のとおり、今後は、バージョンを上げて対応することも検討しています。 対処 毎回新しい関数を返すラッパーを作る useMatchRoute を直接使わず、次のラッパーフックを経由するようにしました。 import { useMatchRoute } from "@tanstack/react-router"; export function useReactiveMatchRoute() { "use no memo"; const matchRoute = useMatchRoute(); const reactiveMatchRoute: typeof matchRoute = (options) => matchRoute(options); return reactiveMatchRoute; } やっていることは、matchRoute を実行するだけの関数をレンダーのたびに新しく作って返すことだけです。 "use no memo" ディレクティブをつけることで、このラッパーフック自体が Compiler に最適化されるのを防いでいます。 "use no memo" は、関数単位で Compiler の変換を止めるディレクティブです。 これにより、URL が変わって useMatchRoute の購読によって再レンダーが走るたびに、呼び出し元には必ず前回と違う参照を持った新しい関数が返るようになります。 呼び出しは以下のように変更しました。 function NavEntryItem({ entry, params }: Props) { const matchRoute = useReactiveMatchRoute(); const isActive = (link: NavLink) => matchRoute({ to: link.to, params }) !== false; return <NavGroupItem entry={entry} isActive={isActive} />; } URLが変わると、元の useMatchRoute() の購読によって再レンダーが発生します。その際、ラッパーからは新しい関数が返ります。 その結果、呼び出し側のコンポーネントでは Compiler のキャッシュ判定 ($[0] !== matchRoute) が正しく外れるようになり、isActive の再計算も、<NavGroupItem> の再描画も正常に行われるようになりました。 挙動が変わったもの:終了アニメーション中の入力リセット 症状 各種フォームのダイアログにおいて、値を入力してからキャンセルでダイアログを閉じるアニメーションの中で、入力値が残ってしまっていてテストが落ちていました。 再度ダイアログを開くと残っていなかったため、ユーザーへの影響は少ないと判断しましたが、こちらも原因を調査して対処しました。 function AccountCreateDialog({ isOpen, onClose }: Props) { const { register, reset } = useForm({ defaultValues: { name: "" } }); const close = () => { onClose(); reset({ name: "" }); // ← ここでリセットしている }; return ( <Dialog isOpen={isOpen}> <input {...register("name")} /> <button onClick={close}>キャンセル</button> </Dialog> ); } 原因 原因は、React Compiler のキャッシュ、React Hook Form の reset() の仕組み、React の ref コールバックの仕組みの3つが組み合わさったことでした 実際のダイアログコンポーネントを React Compiler で変換すると、register("name") の呼び出しは次のようにキャッシュされていました(出力コードの抜粋)。 if ($[25] !== register) { // register の参照が前回と違う場合(初回レンダーなど) t12 = register("name"); // 関数を実際に呼び出して結果を取得 $[25] = register; // 今回の register の参照をキャッシュに保存 $[26] = t12; // 呼び出した結果をキャッシュに保存 } else { // register の参照が変わっていない場合 t12 = $[26]; // 関数を呼び出さず、前回の結果を使い回す } $: 今回はインデックス 25 の枠に register 関数の参照を、26 の枠にその実行結果が保存されていました。 t12: register("name") の実行結果(onChange や ref などが含まれたオブジェクト)が代入され、最終的に JSX 側で <input {...t12} /> のように展開されます。 Compiler は register 関数の参照が前回と同じなら、関数を呼び出さずに前回の結果を使い回す という最適化を行ってくれます。 この最適化が、React Hook Form の2つの仕様とぶつかりました。 React Hook Form が持つ2つの仕様 register 関数は常に同じ参照だが、呼んだ結果は毎回新しい useForm が返す register 関数は、最初のレンダーで一度だけ作られ、その後は再レンダーされても同じ参照のままです。 一方、register("name") を呼んだ結果(戻り値)は、呼ぶたびに新しく作られます。戻り値に含まれる ref コールバック(ref に渡す関数)が、毎回新しい関数になるためです。 今回の reset() は登録済みフィールドの参照を破棄する 今回は保持オプションを指定していないため、フォームの値をリセットするとともに、React Hook Form が内部で保持するフィールドの参照も破棄されます。 Reset the entire form state, fields reference, and subscriptions. (出典:React Hook Form 公式ドキュメント - reset) React Hook Form は、「直後の再レンダーで再び register("name") が呼ばれ、入力欄が登録し直されること」 を前提に動いています。 keepFieldsRef: true を指定すると、今回のリセットでフィールド参照を保持できます。後ほど、この方法も紹介します。 なぜ画面に古い値が残るのか Compiler が register("name") の呼び出しをスキップする register("name") の引数 "name" は固定値であり、register 関数の参照も再レンダー間で変わりません。 Compiler は「同じ関数を同じ引数で呼ぶなら結果も同じはず」と判断し、2回目以降のレンダーで register("name") の実行をスキップして前回の戻り値(ref コールバック等を含むオブジェクト)をそのまま使い回します。 React が ref コールバックを呼び直さない 同じ入力 DOM が維持されている再レンダーでは、ref コールバックの参照も同じなら、React は ref コールバックを呼び直しません。今回、終了アニメーション中はこの条件に当てはまり、入力欄の再登録と値の書き込みが行われませんでした。 React Hook Form が画面を更新できない React Hook Form は、この ref コールバックが実行されるタイミングで入力欄を内部に再登録し、reset() 後の値を DOM へ書き込んでいます。ref が呼ばれないため、DOM への書き込みも再登録も行われません。 その結果、終了アニメーション中の入力欄には編集した値が残りました。一方、閉じ切った後は入力 DOM がアンマウントされます。再表示時には同じ ref コールバックでも呼び出されるため、初期値が反映されました。 対処 今回のPRでは、従来の「キャンセル直後に入力をリセットする」挙動を維持するため、対象ダイアログを Compiler の変換対象から外しました。 register() と reset() を組み合わせて使うダイアログは、コンポーネントの関数本体の先頭に "use no memo" を書くように対処しました。 function AccountCreateDialog({ isOpen, onClose }: Props) { "use no memo"; const { register, reset } = useForm({ defaultValues: { name: "" } }); // ... } "use no memo" を指定したコンポーネントは、その内部で生成される JSX や関数(子コンポーネントへ渡す props など)も Compiler のキャッシュ対象外となります。 局所的に最適化の恩恵は受けられなくなりますが、これ以外の独立したコンポーネントは引き続き Compiler で最適化されます。 あわせて、「閉じてもう一度開いたあとも、入力と検証が正しく動く」ことを確かめるテストを追加し、キャンセル直後に入力欄が空になっているかだけでなく、フィールドが登録し直されているかまで確認するようにしました。 今回はダイアログがアンマウントされるため再表示時には正常に戻っていましたが、仮にページに残り続けるフォームだった場合、reset() 以降は React Hook Form と DOM の紐付けが完全に切れてしまい、送信(submit)や値の取得ができなくなるという、より深刻な不具合に発展していた可能性があります。 本来望ましい対処:keepFieldsRef 「対応の概要」で触れたとおり、今回の "use no memo" は一時的な対応です。 今回の挙動変化は、次の流れで起きていました。 reset() がフィールドの参照を破棄する そのため、次のレンダーで register("name") を呼んで登録し直す必要がある ところが Compiler が register("name") の呼び出しをスキップするため、登録し直されない "use no memo" は、3. の Compiler の変換を止めて、登録し直しが起きるようにする 対処です。 一方、1. の破棄そのものをやめて、登録し直しを不要にする 方法もあります。それが reset() の keepFieldsRef オプションです(v7.60.0 以降)。 reset(defaultValues, { keepFieldsRef: true }); このオプションを付けると、reset() は入力欄の登録を残したまま、登録済みの入力欄に直接値を書き込みます。 今回失敗した4つのダイアログでは、対応する reset() に keepFieldsRef: true を指定すると、"use no memo" を外してもキャンセル直後の入力値がリセットされました。 対処 よい点 気になる点 "use no memo" コンポーネントの先頭に1行足すだけ。React Hook Form の挙動を変えない そのコンポーネントは Compiler の最適化を受けられない keepFieldsRef: true Compiler の最適化を受けたまま直せる 対象フォームでフィールド参照を保持する設定が必要。条件によって表示・非表示が切り替わる入力欄がある場合は、影響の確認が必要 ! React 公式ドキュメントでは、"use no memo" は一時的な回避策であり、恒久的な解決策ではないとされています 恒久的な解決策ではなく、一時的なデバッグツールとして使用することを意図しています。 (公式ドキュメント)。 keepFieldsRef への移行や、React Hook Form 側の対応状況を見ながら、将来的には外していくのが望ましいと考えています。 壊れなかったけど先に手を打ったもの テストが落ちたり実際に画面が壊れたりしたわけではありませんが、React Compiler 導入にあたって、事前に手を打った(コードを変更した)箇所もあります。 特に、React Compiler の互換性のないライブラリとして、互換性が現在確認されていないライブラリについては、先行事例(React Compilerについて調べてみた、React Compiler導入で得られた効果と気をつけたいポイント)も参考にしながら、バグを踏む前に対策を入れています。 TanStack Table には "use no memo" を指定 TanStack Table(@tanstack/react-table)は、Compiler との互換性に問題があるライブラリとして名前が挙がっています。 そのため、DataTable コンポーネントには "use no memo" ディレクティブを指定し、安全のために Compiler の変換対象から外しました。これにより、このコンポーネント内で定義するカラム定義や配下の子コンポーネントへの props も Compiler の最適化対象外となりますが、 予期せぬバグを防ぐため現時点では互換性を優先しています。 なお、検証時点の TanStack Table は v8 です。公開時点では v9 がリリースされていますが、v9 と Compiler の組み合わせは今回検証していません。 RHF の watch() を useWatch() に変更 React Hook Form の watch() メソッドも、Compiler との組み合わせで問題が起きやすいことが公式から指摘されています。 そのため、フォームの値を購読してUIを切り替えるような箇所は、フックである useWatch() を使用する形へすべて書き換えました。 手動の useMemo の削除 CommandPalette などのコンポーネントで過去に手動で書いていた useMemo は削除しました。 これはバグ対策というより、「今後のメモ化は Compiler に任せる」という方針に基づいたコードの整理です。 まとめ React Compiler を導入し、一部の手動メモ化を Compiler に任せる形へ整理しました。しかし今回の検証で見えてきたように、外部ライブラリとの組み合わせでは、過剰なキャッシュが原因でバグを引き起こすことがあります。 今回は、Compiler の ON/OFF で挙動を比較し、変換結果とライブラリの実装を確認することで、必要な互換性対応を判断できました。 また、テストが失敗した場合も、どのタイミングで挙動が変わり、ユーザーの操作にどう影響するのかまで確かめることが大切だと感じました。 この記事での調査の過程や回避策のアイデアが、これから React Compiler をプロダクトに導入しようとしている方の参考になれば幸いです! 最後に AI Shiftではエンジニアの採用に力を入れています! 少しでも興味を持っていただけましたら、カジュアル面談でお話しませんか? (オンライン・19時以降の面談も可能です!) 【面談フォームはこちら】

    1 like
  5. In the next version of Oxlint, raw AST transfer will get 5x faster for js plugins (if you are using Node.js 24+). oxc#27816

    41 likes · 11 reposts · 2,779 views
  6. Ускоряем self-hosted Convex в два раза: AOT-компиляция TypeScript-функций в Wasm Обзор Convex – это новый, но набирающий популярность фреймворк для реактивных веб-приложений, который позволяет писать транзакционные квери (queries) и мутации (mutations) на TypeScript с гарантиями консистентности. Вся статья ниже относится к self-hosted версии Convex: convex-backend, а точнее, к моей пропатченной версии оного, так как “официальная” версия не пригодна к работе в продакшене и вряд ли тестировалась на сколь-нибудь нагруженном кейсе. Моя версия работает на виртуальном сервере с 32 ядрами и 64Гб памяти и обрабатывает до 15 тысяч Convex-кверей и мутаций в минуту. Я навайбкодил convex-wasm-compiler, который компилирует Convex-квери и мутации в WebAssembly, и соответствующий патч для convex-backend, позволяющий выполнять скомпилированные в Wasm Convex-функции на файберах Wasmtime прямо в Tokio рантайме convex-backend. TLDR: квери и мутации в среднем работают в 2 раза быстрее, хвосты задержек сократились втрое. Объём памяти, который сервер удерживает под готовые к выполнению окружения (V8-контексты или Wasm-окружения), уменьшился на 80%. До этого для быстрого выполнения Convex-функций приходилось активно кешировать и переиспользовать V8-контексты. Без переиспользования каждая Convex-функция стартует в новом контексте: модули ещё не загружены, JIT не прогрет. Начинается загрузка модулей приложения, необходимых для выполнения функции, и интерпретация её JS-кода. Даже относительно простые Convex-функции в среднем выполняются за 100–150 мс. По мере роста приложения и размера модулей проблема усугубляется. Convex-компоненты помогают сдерживать бесконтрольный рост модулей, но сами добавляют столько накладных расходов и обвязки, что для многих приложений, на мой взгляд, от них больше вреда, чем пользы. Особенно для приложений, которые разрабатывает один человек или пара разработчиков: там нет вопросов разделения ответственности за подсистемы, стабильности API и так далее. Своё отношение к разработке на Convex в стиле «majestic monolith» и к подходу с большим количеством компонентов я описал в посте о своём приложении. Если выполнять Convex-функцию в уже прогретом V8-контексте, где все модули загружены, а код функции скомпилирован в машинный код через TurboFan, время выполнения часто сокращается очень заметно — вплоть до 10 раз. Например, со 100–150 мс до 10–15 мс, при условии, что строки базы данных, которые читает функция, уже закешированы в памяти. Так что переиспользование V8-контекстов было и остаётся необходимым для быстрых и эффективных Convex-приложений. Но у него есть две проблемы. Потребление памяти закешированными V8-контекстами Во-первых, чтобы больше 99% вызовов использовали уже готовые V8-контексты, каждому V8-изоляту в рантайме convex-backend нужно держать не один контекст. Нужен отдельный контекст для каждого модуля — точнее, группы инициализации модулей, — который convex-backend часто назначает на выполнение этому конкретному изоляту. В конфигурации self-hosted convex-backend для моего приложения сейчас используются TinyLFU-кеши размером до 6+1 контекстов (на момент публикации поста о моей конфигурации self-hosted Convex было 5+1). Всего кешируется до 400 контекстов, хотя даже на пике нагрузки одновременно выполняется гораздо меньше 400 Convex-функций. Главная причина такой неэффективности — V8-контексты привязаны к V8-изолятам, и использовать один контекст в разных изолятах нельзя. Каждый V8-контекст занимает около 35 МБ памяти, и эта цифра тоже растёт вместе с приложением: два месяца назад я писал, что в моём приложении один V8-контекст удерживал в среднем 30 МБ. В сумме эти контексты занимают около 14 ГБ памяти на моём сервере convex-backend. Волны инициализации V8-контекстов после деплоя Convex-приложения Вторая проблема переиспользования V8-контекстов в том, что при деплое Convex-приложения часть закешированных контекстов инвалидируется. Это может запустить по всему серверу волну загрузки и компиляции модулей, которая длится около минуты: сотни V8-контекстов приходится создавать и прогревать заново. V8-изоляты не делятся друг с другом оптимизированным машинным кодом. Даже если сериализованный байткод закеширован, инициализация модулей всё равно выполняется отдельно в каждом V8-контексте. Масштаб инвалидации зависит от того, какие модули изменились при деплое. Но если обновились именно ключевые модули с «горячими» Convex-функциями, на которые приходится значительная доля всей серверной нагрузки, большая часть V8-контекстов может пойти под снос и потребовать повторной инициализации. Ведь с каждым таким модулем связано множество V8-контекстов в TinyLFU-кешах разных V8-изолятов. Эта волна повторного прогрева V8-контекстов совпадает с другой волной работы, которую вызывает деплой Convex-приложения: кеш результатов кверей из обновлённых модулей инвалидируется, а квери, на которые у клиентов открыты реактивные подписки, выполняются заново. Это происходит, даже если данные в read set не менялись. То есть серверу приходится не только компилировать код и загружать модули, но ещё и выполнять больше кверей, чем в обычном режиме. На практике из-за этих волн работы после деплоя квери и мутации могут какое-то время выполняться медленнее, а при сильной перегрузке серверу приходится отклонять часть вызовов. Рабочие потоки Tokio рантайма Convex конкурируют с рабочими потоками V8-изолятов и фоновыми потоками V8 Это более общая проблема выполнения Convex-функций в V8-изолятах, не специфичная для переиспользования контекстов. convex-backend ограничивает число воркеров V8-изолятов, которые могут активно выполнять код, через переменную FUNRUN_ISOLATE_ACTIVE_THREADS. Под активным выполнением здесь понимается работа без блокировки на чтении или записи в базу данных и другом I/O. Эту переменную следует выставлять равной CPU-лимиту контейнера convex-backend или чуть ниже. При этом изолировать эти потоки от собственного Tokio рантайма convex-backend и фоновых потоков V8, как правило, не получится без существенного снижения максимальной пропускной способности сервера при длительной нагрузке. Число потоков ОС у Tokio рантайма задаётся переменной RUNTIME_WORKER_THREADS. Фоновые потоки движка V8 отвечают за компиляцию и сборку мусора в V8-контекстах; их число задаётся переменной V8_THREADS. В моей конфигурации сервера CPU-лимит convex-backend составляет 28.5 CPU, FUNRUN_ISOLATE_ACTIVE_THREADS=28, RUNTIME_WORKER_THREADS=28 и V8_THREADS=16. Кроме того, у меня есть несколько пулов выполнения Node, в каждом из которых по 1–2 активных потока. Получается, что теоретически в процессах контейнера с лимитом 28.5 CPU может быть как минимум 75 активных потоков ОС. Такой oversubscription — не катастрофа, но до оптимума далеко. За последнюю неделю, когда Convex-квери и мутации на моём сервере выполнялись в V8, в пятиминутном интервале с наибольшим контеншеном CPU pressure достигал 29%. Разумеется, это пришлось на время деплоя приложения. Практический эффект этого CPU pressure: когда сервер занят — из-за деплоя или просто роста нагрузки, — Convex-функции выполняются медленнее, чем при умеренной нагрузке. И это отдельный эффект, помимо замедления чтения и записи в базу данных, более частого вытеснения записей из кеша результатов кверей, кеша индексов и кеша V8-контекстов. Сама база под Convex, например MySQL или PostgreSQL, при росте транзакционной нагрузки тоже может испытывать повышенный CPU pressure, а её контейнер — попадать под троттлинг. Зачем компилировать TypeScript-функции Convex в Wasm Перенести выполнение горячих функций из V8 в WebAssembly-рантайм вроде Wasmtime, встроенный в Tokio рантайм Convex, — очевидный ответ на описанные проблемы. В начале 2026 года команда Convex объявила, что Wasm-рантайм есть в планах. В августе Wasm-рантайм добавили в репозиторий convex/convex-backend. Однако на следующий день его удалили, и с тех пор он не возвращался. В той реализации использовался интерпретатор QuickJS, скомпилированный в Wasm: сами Convex-функции интерпретировались внутри Wasm, а не компилировались в него. Поэтому реализация была очень медленной и не предназначалась для продакшена. Обычно предполагается — и руководство Convex озвучивало это на разных Q&A-сессиях начиная с августа, — что ради производительности WebAssembly-рантайма разработчики будут писать Convex-функции на компилируемом языке с Wasm-таргетом, прежде всего на Rust. Я начал разрабатывать компилятор обычных Convex-функций, написанных на TypeScript, в байткод WebAssembly с помощью Static Hermes — AOT-компилятора JavaScript с поддержкой Wasm-таргета — в конце июля. Тогда ещё не было известно, что команда Convex собирается ускорить работу над Wasm-рантаймом: до августа Jamie Turner говорил лишь, что тот, скорее всего, появится только в 2027 году. За весь проект, который начался в июле и занял почти три месяца, встраивание Wasmtime в convex-backend оказалось сравнительно небольшой частью работы — возможно, около 10% всех усилий. То есть само по себе добавление Wasm-рантайма в convex-backend — задача относительно простая, и это было мне более-менее понятно с самого начала. Правда, некоторые другие части задачи я сильно недооценил: возможно, я рассчитывал, что на Wasm-рантайм в convex-backend уйдёт 50% усилий. В итоге оказалось только 10%, а весь проект занял в пять раз больше времени, чем я ожидал. Так что вариант переписать части моего Convex-приложения на Rust я рассматривал уже тогда. Но не пошёл по этому пути по нескольким причинам: В приложении было около 350 тысяч строк продакшен-кода только в Convex, причём значительная часть логики была общей с другими частями системы, работавшими на Node.js. Вместе с ними объём продакшен-кода превышал полмиллиона строк. Переписать всё это казалось примерно такой же сложной задачей, как сделать компилятор существующих Convex-функций в WebAssembly. Оглядываясь назад, даже переписывание полумиллиона строк с TypeScript на Rust, вероятно, заняло бы меньше времени, чем трёхмесячная разработка компилятора. Но тогда я этого не предвидел. С другой стороны, у такого проекта наверняка были бы свои существенные риски, о которых я сейчас не знаю, потому что не пробовал. И он точно нарушил бы привычный темп выпуска фич. Меня беспокоило время компиляции Rust и то, насколько оно может замедлить цикл разработки. Эти опасения отчасти подтвердились: с тех пор я полностью написал одну часть приложения на Rust, используя добавленную мной в convex-backend функциональность native resident. Это не Convex action, кверя или мутация, а фоновый Rust-процесс, который деплоится вместе с Convex-приложением и сам вызывает Convex-квери и мутации через loopback. В этой части приложения всего 30 тысяч строк Rust, но каждый раз, когда её код меняется, я ощущаю всю боль медленной компиляции. Мне не хотелось придумывать API для работы с Convex на Rust — аналоги ctx.db.query(), insert(), defineSchema() и так далее, — которые потом вытеснят официальные API команды Convex. В целом я хотел сделать что-то, что могло бы дополнить будущие разработки Convex, а не разойтись с ними или конкурировать. Наконец, делать компилятор мне просто казалось интереснее, чем переписывать приложение на Rust! Устройство convex-wasm-compiler и Wasm-рантайма convex-backend Код Convex-приложения не меняется: это по-прежнему TypeScript с SDK convex-js. Компиляция TypeScript-кода Convex-приложения в Wasm convex-wasm-compiler управляет анализом исходников, сборкой JavaScript-бандлов и нативной компиляцией. С помощью tsrs он находит регистрации Convex-функций и связывает экспортируемые маршруты с исходным кодом, а с помощью esbuild разрешает зависимости и преобразует TypeScript-код приложения в JavaScript-бандлы. Написанный на Rust анализатор использует Oxc, чтобы проверить исходники и граф зависимостей на небезопасное сохранение состояния между запросами и определить, можно ли переиспользовать инициализированные модули. Результаты анализа определяют, что можно допустить к выполнению и как это упаковать; исполняемый код приложения берётся из JavaScript, который генерирует esbuild. Затем компилятор подготавливает этот JavaScript в виде модулей приложения, добавляет bridge к host-операциям Convex и вызывает (Static) Hermes. Здесь и далее «host» — это операции рантайма convex-backend, такие как чтение и запись в базу данных, а «guest» — выполнение функций приложения. Компилятор shermes генерирует C-код, который тулчейн Clang/LLVM из Emscripten компилирует вместе с Hermes рантаймом и нативным адаптером Convex. wasm-ld линкует эти компоненты, а Binaryen оптимизирует полученный Core WebAssembly. Прилинкованный Hermes рантайм обеспечивает внутри Wasm-guest JavaScript-объекты, строки, промисы, исключения и сборку мусора. Асинхронные JS-функции на файберах Wasmtime Static Hermes компилирует асинхронные JavaScript-функции в конечные автоматы, которые могут приостанавливаться и продолжать выполнение с опорой на промисы. Патч для Hermes переносит основную механику промисов в C++: состояние промиса хранится в объектах JSPromise, которыми управляет GC, а реализация Promise на C++ отвечает за resolve, reject и учёт continuations. Это сокращает количество операций с JavaScript-объектами и аллокаций колбэков при асинхронном выполнении. Некоторые высокоуровневые операции Promise по-прежнему используют внутреннюю JavaScript-реализацию Hermes. C+±адаптер Convex, скомпилированный в WebAssembly вместе с Hermes и приложением, содержит цикл, который доводит каждый вызов до завершения. Он вызывает хендлер, обрабатывает очередь микротасок Hermes, выполняя готовые continuations, ждёт чтения и записи в базу данных и других host-операций, а по мере поступления результатов делает resolve или reject соответствующих промисов. Если нужно дождаться асинхронной работы на стороне host, Wasmtime приостанавливает файбер вызова, освобождая рабочий поток Tokio для других задач. Когда результаты готовы, выполнение продолжается в том же файбере. Таким образом, экспортируемая точка входа Wasm возвращает итоговый статус вызова через обычный интерфейс «вызов — возврат»; JavaScript-промисы и continuations остаются внутри guest. Tokio рантайм Convex поллит call_async из Wasmtime, который выполняет точку входа guest в одном файбере Wasmtime. Проверки fuel и epoch обеспечивают соблюдение лимитов выполнения и дают CPU-bound коду внутри guest возможность делать yield. Компиляция Wasm в нативный код и деплой В этой схеме нативная компиляция происходит на машине разработчика или в CI. Компилятор Cranelift из Wasmtime переводит .wasm-модули — приложение, Hermes рантайм и адаптер Convex — в машинный код под целевую архитектуру сервера и конфигурацию Wasmtime. Wasmtime сохраняет этот код и метаданные для его загрузки в .cwasm-файлах. При деплое они отправляются на сервер вместе с переносимыми .wasm-файлами, обычным JavaScript-бандлом Convex и схемой. На сервере convex-backend проверяет, что скомпилированные файлы совместимы с его движком Wasmtime и соответствуют той версии JavaScript-приложения, которая сейчас деплоится. Сохранённые хеши содержимого не позволяют случайно совместить новый JavaScript со старой скомпилированной сборкой. convex-backend загружает скомпилированный код в память и подготавливает изолированные окружения для повторного использования, каждое со своим Hermes рантаймом и JavaScript-состоянием приложения. Инициализация модулей — выполнение кода верхнего уровня, который создаёт объекты модулей и регистрирует экспортируемые функции, — завершается для начального пула окружений ещё до того, как новая версия приложения начинает обслуживать квери и мутации. Позже пул может расти вслед за нагрузкой. Именно эта часть решает описанную выше проблему «Волны инициализации V8-контекстов после деплоя Convex-приложения», характерную для выполнения в V8. Wasm-окружения и управление памятью Wasm-рантайм экономит память по сравнению с V8 за счёт того, что изолированные окружения в пуле совместно используют скомпилированный код и инициализированную память приложения. Эти окружения похожи на V8-изоляты в рантайме Convex, но у них нет выделенных потоков ОС. Их количество ограничено общим бюджетом памяти и жёстким лимитом числа инстансов; число одновременно активных выполнений ограничивается отдельно, исходя из CPU. Каждое окружение управляется Wasmtime Store. В нём есть Hermes рантайм и собственное JavaScript-состояние, и в каждый момент оно обслуживает один вызов Convex-функции. Окружения с одинаковыми скомпилированными модулями совместно используют их машинный код. На Linux convex-backend также сохраняет инициализированную Wasm-память окружения, включая JavaScript-хип, в неизменяемый снапшот в файле. Это происходит после инициализации модулей приложения, но до выполнения в этом окружении первой квери или мутации. Другие окружения мапят этот снапшот с copy-on-write: неизменённые страницы используют общую физическую память, а при записи создаются приватные копии. Каждое окружение заново создаёт собственные таблицы функций и ссылки рантайма, а состояние конкретного вызова Convex-функции хранит отдельно. Перед переиспользованием окружения convex-backend проверяет, что конфигурация и другие зависимости, прочитанные при инициализации, всё ещё актуальны. В сборщик мусора Hermes, Hades, внесён патч, который сохраняет это совместное использование памяти. В данной Wasm-сборке Hades работает в одном потоке внутри guest-вызовов. Подготовленные области хипа исключены из последующих аллокаций и компактизации: это уменьшает количество записей в общую исходную память. При этом сохраняются обычные механизмы обхода графа объектов (tracing), очистки памяти от недостижимых объектов (sweeping) и финализации. В безопасных точках между вызовами сборка мусора и анализ состояния аллокатора находят пустые области nursery и заведомо свободные страницы с данными, чью приватную физическую память host может освободить. Бэкенд учитывает общую физическую память только один раз и резервирует память под приватное состояние и рост каждого окружения. Хуки Wasmtime отслеживают записи и рост памяти, поэтому общий бюджет Wasm-памяти соблюдается как при выполнении вызовов, так и при добавлении окружений в пул. Wasmtime также использует сборщик с отложенным подсчётом ссылок для объектов, которыми владеет сам движок, в том числе перехваченных Wasm-исключений. Это отдельный механизм, не связанный с Hades, который управляет JavaScript-объектами в линейной памяти. Вместе с ограничением числа сохраняемых инстансов и освобождением страниц эти механизмы позволяют переиспользовать инициализированные рантаймы после успешных вызовов, не удерживая бесконечно всю память, которую затрагивали предыдущие выполнения Convex-функций в этом окружении. Wasm vs. V8: результаты замеров производительности В целом среднее время выполнения кверей и мутаций в Wasm сократилось почти на 50% относительно V8: Рантайм Среднее p90 p99 Максимум V8 38.53 мс 62 мс 329 мс 7 463 мс Wasm 19.61 мс 34 мс 139 мс 2 242 мс В среднем каждое Wasm-окружение удерживает 12 МБ полностью приватной памяти, не разделяемой с другими окружениями. Это на 66% меньше, чем 35 МБ у V8-контекста. Кроме того, держать в памяти нужно гораздо меньше Wasm-окружений: 130 против примерно 400 V8-контекстов. Почему V8-контекстов нужно больше, чем одновременно выполняющихся вызовов, я объяснил выше в разделе «Потребление памяти закешированными V8-контекстами». В пятиминутном интервале с наибольшим контеншеном CPU pressure достигал 15%, когда основным рантаймом был Wasm, против 29% для V8. Даже эти 15%, вероятно, отчасти связаны с сохранившимся выполнением в V8. Как я расскажу ниже, я компилирую в Wasm не всё Convex-приложение, а лишь примерно 20% самых горячих модулей, на которые приходится 90% всей нагрузки. Это экономит время компиляции и уменьшает размер артефактов. Остальные 80% модулей по-прежнему выполняются в V8, поэтому для них всё ещё актуальны инвалидация и инициализация контекстов, работа фоновых потоков V8 и так далее. В следующих двух таблицах показано среднее относительное снижение метрик mean/p90/p99/max для отдельных кверей и мутаций в разных группах. Эти средние не взвешены по числу вызовов или суммарному времени выполнения каждой функции. Время выполнения целиком: Группа Среднее p90 p99 Максимум Все квери −57.6% −56.3% −65.3% −82.2% Квери: 20% с наибольшим числом host-операций −39.3% −37.6% −48.4% −82.2% Квери: 20% с наименьшим числом host-операций −69.0% −61.3% −78.0% −84.0% Все мутации −51.5% −33.7% −60.6% −75.1% Мутации: 20% с наибольшим числом host-операций −39.4% −43.6% −48.9% −70.5% Мутации: 20% с наименьшим числом host-операций −51.2% −55.7% −61.5% −70.6% «User» time — оценка времени, которое функции провели непосредственно в guest-рантайме, без ожидания чтения и записи в базу данных и других асинхронных host-операций: Группа Среднее p90 p99 Максимум Все квери −70.6% −66.9% −76.1% −79.8% Квери: 20% с наибольшим числом host-операций −43.5% −41.0% −56.6% −89.0% Квери: 20% с наименьшим числом host-операций −89.5% −82.9% −86.6% −69.8% Все мутации −67.7% −46.5% −72.5% −59.9% Мутации: 20% с наибольшим числом host-операций −41.0% −41.2% −47.7% −39.0% Мутации: 20% с наименьшим числом host-операций −76.9% −78.6% −82.2% −55.0% «20% с наибольшим числом host-операций» и «20% с наименьшим числом host-операций» — это функции, которые в среднем выполняют больше или меньше асинхронных операций, например чтений и записей в базу данных, по сравнению с остальными. Например, функция с единственным ctx.db.get(id) делает одну асинхронную операцию и попадёт в группу «20% с наименьшим числом». А функция, которая в среднем выполняет сотни операций ctx.db, ctx.scheduler и так далее, — в группу «20% с наибольшим числом». Из таблиц видно, что относительное преимущество Wasm перед V8 обычно уменьшается для функций, которые делают очень много асинхронных операций. Возможно, это указывает на слабое место в обработке JS Promise внутри файбера Wasmtime, описанной выше в разделе «Асинхронные JS-функции на файберах Wasmtime». И это несмотря на то, что оптимизации этой части уже уделено много внимания и я не знаю — ладно-ладно, GPT-Astra не знает, — как ускорить её ещё. Другая возможная причина: частые yield из файберов Wasmtime и переключения потока на другие задачи Tokio приводят к тому, что Convex-вызов чаще мигрирует между ядрами CPU, а значит, чаще получает промахи L1-кеша или TLB. А возможно, дело в чём-то ещё. Причина пока не установлена. Преимущество по «user» time тоже не универсально. Есть одна Convex-мутация, у которой среднее user time в Wasm-рантайме на 14% выше, чем в V8, хотя по полному времени выполнения она всё равно быстрее в Wasm. Эта мутация в цикле выполняет численные операции над Float64Array размером более 100 тысяч элементов. Возможно, в V8 для этого есть интринсики или векторизация, которых пока не хватает в пайплайне Hermes → Wasm. Операционные аспекты AOT-компиляции в Wasm Теневое выполнение для постоянного тестирования Я добавил в convex-backend целую сложную подсистему для дифференциального тестирования и теневого выполнения (shadow execution) Convex-функций в рантаймах V8 и Wasm. Она поддерживает основное (primary) и теневое выполнение — в каждой роли может быть как V8, так и Wasm. Заданная доля вызовов, например 5%, случайным образом отбирается для теневого выполнения, после чего система проверяет, что результаты совпадают. Теневые вызовы не блокируют основные. Теневое выполнение работает и для кверей, и для мутаций. В случае мутаций записывается трейс вызовов, меняющих состояние, таких как db.insert(), но сами строки в базе, конечно, не перезаписываются второй раз. Поменять местами основной и теневой рантаймы можно без повторного деплоя приложения. Эта система позволила мне уверенно переключить продакшен на Wasm и найти несколько багов в convex-wasm-compiler. Правда, большинство багов оказалось в самой подсистеме теневого выполнения, сравнения и проверки трейсов. Даже после переключения основного выполнения на Wasm я продолжаю выполнять 5% вызовов в V8 в теневом режиме, чтобы замечать расхождения, если они появятся в будущем. Выборочная компиляция в Wasm И компилятор, и convex-backend поддерживают выборочную компиляцию: в Wasm компилируется и выполняется только часть модулей. Это помогает сократить время компиляции и объём данных, передаваемых при деплое. В своём приложении я выбираю лишь около 20% модулей, на которые приходится более 90% всех вызовов кверей и мутаций. Однако ни объём передачи, ни время компиляции не уменьшаются впятеро: из-за транзитивных зависимостей компилировать и передавать всё равно приходится около 70% всех модулей приложения. Так что, возможно, выигрыш не так уж велик. Время компиляции и объём передачи Выбранные 20% модулей моего Convex-приложения — это 57 модулей и 631 Convex-функция для компиляции в Wasm: 145 кверей и 486 мутаций. Всего компилируется 528 отдельных JS-модулей: 57 выбранных плюс их зависимости. Для этого набора холодная компиляция — когда нужно перекомпилировать большую часть кода или весь код, например после очистки кеша компиляции, — с 16 воркерами AOT-компиляции и лимитом памяти 12 ГБ занимает около 6 минут. Тёплая компиляция, когда часть модулей изменилась, но большинство уже есть в кеше, занимает около 2 минут. До идеала далеко, и я продолжаю над этим работать. Когда я начинал проект, я не ожидал, что именно скорость компиляции, инкрементальность и кеширование окажутся главными инженерными проблемами. Из примерно трёх месяцев работы над проектом AI-агенты суммарно потратили около трёх недель календарного времени исключительно на это направление. При деплое с таким набором скомпилированных модулей на мой self-hosted сервер Convex передаётся около 50 МБ сжатых артефактов. Без Wasm — около 15 МБ, то есть Wasm примерно втрое увеличивает объём данных при деплое. Без выборочной компиляции он, вероятно, был бы примерно в пять раз больше, чем при деплое одного JS-бандла. Эта статья — перевод из моего блога про работу с Convex в продакшене.

  7. oxc-project/tsrs this is huge. I'm so excited about it! Congrats @boshen.github.io and OXC team!

    3 likes
  8. Go製TypeScript 7の公開から約3か月後、なぜRust製の別実装が相次いだのか はじめに 2026 年 7 月 8 日、Go で実装された TypeScript 7.0 が正式にリリースされました。公式発表では従来の TypeScript 6 と比べてフルビルドが概ね 8〜12 倍速くなったと報告されています。 そこから約 3 か月後の 10 月、Go 版をもとにした Rust 製の別実装の動きが目立つようになりました1。10 月 10 日には Bun 1.4.3 が bun check を公開し、20 日には Cloudflare と VoidZero が tsrs への協力体制 を発表しています。 tsc-rs も含め、Rust に移植するプロジェクトが複数進んでいます。公式の Go 実装も引き続き開発されており、Rust 版は別プロジェクトです。 TypeScript チームは Rust も検討したうえで Go を選んでいます。それなのに、今度は Rust への移植がいくつも進んでいるのが気になったため、これまでの経緯と各実装の特徴を調べてみました。 この記事では TypeScript 5 から Go 移植までを振り返り、各実装の特徴を見ながら、Rust 製の別実装が相次いだ背景を考えてみます。公開ベンチマークや、Rust 以外の方法で高速化する処理系も紹介します。 ※情報は 2026 年 10 月 27 日時点のものです。ベンチマークは開発元や測定者が公開した結果を引用しており、自分の環境で測定したものではありません。 型チェックとトランスパイルについて TypeScript の型注釈の除去や構文の変換によって JavaScript を生成するのがトランスパイルです。一方、代入や関数呼び出しが型のルールに合っているかを調べるのが型チェックです。 const count: number = "3"; このコードは型注釈を取り除けば JavaScript として実行できますが、型チェックではエラーになります。 esbuild は TypeScript を変換できますが、型チェックは行いません。公式ドキュメント でも、型チェックには別途 tsc --noEmit を使うよう説明されています。SWC や Oxc も TypeScript の変換機能を提供していますが、今回の中心は型チェック自体を高速化する処理系です。 TypeScript 5 から Go 移植まで TypeScript は 2012 年 10 月に公開 され、長く TypeScript で書かれたコンパイラを JavaScript にして動かしてきました。Go に移植する前にも、既存実装の高速化は続いています。 日付 出来事 コンパイラの変化 2025 年 3 月 11 日 Go への移植を発表 ネイティブコードと並列処理による高速化を目指す 2025 年 5 月 22 日 Native Preview 公開 npm から Go 版を試せるようになる 2026 年 3 月 23 日 TypeScript 6.0 公開 JavaScript ベースの最後のメジャーリリースとする方針 2026 年 7 月 8 日 TypeScript 7.0 公開 Go 製コンパイラを正式に提供 TypeScript 5.0 では、内部オブジェクトの構造をそろえて JavaScript エンジンが処理しやすくするなどの改善が行われました。7.0 ではネイティブコードで動かし、複数の CPU コアも利用するようになった、という流れです。 ちなみに、tsc は公式コンパイラのコマンド名で、7.0 では Go 製の実行ファイルを起動します。tsgo はプレビュー時のコマンド名であり、Go 実装を指す名前としても使われます。この記事でも、従来の JavaScript 実装と区別するときに使っています。 なぜ Go が選ばれたのか 既存の挙動を保って移植したかった 公式の Why Go? では、言語選定の最大の条件として既存実装との互換性を挙げています。型チェックの結果に加えて、コードの構造を似せることも重視していました。 旧実装と新実装を並行して保守するには、片方の変更をもう片方に移しやすい方が便利です。Go は既存のコーディングパターンに近く、メモリ配置を制御しながら、不要なメモリを回収する GC も使えます。 TypeScript の内部では、構文を表す AST、名前と宣言を結ぶ Symbol、型情報などが相互に参照します。構文の親子関係は木構造ですが、実装には子から親へ戻る参照もあり、参照をたどると循環します。こうした参照関係を保ちやすいことが、Go を選ぶ理由になっていました。 Rust への移植で難しかったこと Anders Hejlsberg は インタビュー で、Rust も試したものの、循環するデータ構造を多用する既存実装の移植には適さなかったと説明しています。 自分は GC を前提にした参照や後からの書き換えを、従来の構造を保って Rust に移す作業の難しさを説明している、と理解しました。Rust で循環参照を扱う方法は、この後の tsrs でも使われています。 Rust で書くなら、参照の表現やメモリを解放する単位などを別途設計できます。ただし、その分だけ移植の作業も増えます。互換性を保ちつつ少ない変更で高速化したい、という目的では Go が適していたということですね。 このあたりの歴史や構造は、TSKaigi 2026 の 制約と時代から読み解く TypeScript コンパイラ設計史 でも詳しく解説されています。 その後の TypeScript 処理系 2026 年 10 月時点の主な処理系を、ざっくり整理してみました。 処理系 実装と由来 主な特徴 tsc / tsgo Go 製の公式実装 互換性を比較する基準 tsrs Go 版を Rust に移植 メモリ配置の最適化、WebAssembly 対応 tsc-rs Go 版を Rust に移植した別プロジェクト AI による移植、Effect 向けの診断機能 bun check Go 版を移植し、Rust 製の Bun に統合 実行・テスト・ビルド前に型チェック tsz Rust 製の TypeScript 互換実装 Checker と Solver を分ける設計 tsc-ts Go 版を TypeScript に移植 scriptc でネイティブコードにコンパイル 移植元を図にすると、以下のようになります。tsz は設計を組み直した互換実装なので、同じ方式の移植としては結んでいません。 tsrs 2026 年 10 月 20 日、Cloudflare と VoidZero は、Owner.com の Max Schwenk 氏とともに tsrs に取り組むと発表しました。Oxc のツールチェーンの一部として開発し、TypeScript チームとも協力する方針です。 移植ガイド によると、tsrs は Go 版のアルゴリズムや関数の分割、処理順序を保つ方針です。一方、メモリ管理には独自の実装を使っています。 循環参照するオブジェクトは、メモリをまとめて管理するアリーナに確保します。オブジェクト同士は P<T> という型で参照します。 型チェック用のスレッド内だけで使うデータの更新には、Cell や RefCell などの内部可変性を使います。複数のスレッドで共有する AST などには独自の OwnedCell / FrozenCell を使い、原則として型チェック前に更新を終えます。遅延初期化が必要な共有データは、ロックなどで同期します。 こうするとオブジェクト間の参照関係と、メモリを所有・解放する単位を分けられます。親子が互いを参照していても、個々のノードが相手のメモリを所有する必要はありません。 Unix 向けの既定構成では ポインター圧縮 を使い、予約したアドレス範囲内の位置を 32 ビットのハンドルで表します。大量のノードや型が持つ参照を小さくすることで、メモリ使用量を減らす設計です。通常のポインターを使う設定もあります。 この実装には unsafe も含まれます。いつデータを解放し、どのスレッドで更新できるかは実装側で確認する必要があり、監査やチェック方法は Rust 実装上のルール にも文書化されています。 以前の Rust 移植で難しかった部分に対して、こうした設計を用意しているわけですね。個人的には言語を置き換えるだけでなく、メモリの扱いまで変えているところが面白いと感じました。 なお、互換性についてのドキュメント では、完全な互換性を安定版の目標としています。通常モードと高速化用の fast モードも区別され、後者では型チェックの順序などの変更に伴うエラーの差が明記されています。 tsc-rs Theo Browne 氏の ts-rust は npm では tsc-rs という名前で提供されています。こちらも Go 版を Rust に移植し、コンパイラや言語サーバーを対象にした実験的なリリースです。 特徴的なのは、開発者自身が LLM による移植の実験として説明していることです。README には移植の試行やモデルを変えた経緯も書かれています。 ちなみに冒頭で紹介した 10 月 20 日の発表では、tsrs と tsc-rs を単一のパッケージに統合するため協力していることにも触れています。別々の実装として増え続ける、という状況でもなさそうです。 bun check Bun 1.4.3 は 2026 年 10 月 10 日に bun check を公開しました。Go 版の移植を組み込み、tsconfig.json を読んで型チェックします。Bun 本体も 1.4 で Zig から Rust への移行を発表しています。 型チェックのドキュメント にあるように、bun run --check、bun test --check、bun build --check と普段の開発コマンドに組み込めるのが特徴です。型エラーがあれば実行やテストの前に止められます。 ただし、bun check は JavaScript や .d.ts の出力、言語サーバーを提供しません。エディターは別の TypeScript を使うため、診断結果をそろえるには、Bun が対応するバージョンを確認してエディター側も合わせます。 tsz tsz は、型チェック、JavaScript の生成、言語サービスを扱う Rust 製の互換実装です。アーキテクチャの説明 では、Checker と Solver を分ける設計を紹介しています。 Checker はソースコードのどこを調べ、どの位置にエラーを報告するかを扱います。Solver は型推論や、ある型の値を別の型に代入できるかの判定を担当します。同じ構造の型を共有し、TypeId で参照する設計も説明されています。 Go 版の関数との対応を重視する tsrs と比べると、型を判定する処理をどう分けるかに違いがあります。ただし、既存処理の整理は続いており、すべての処理が完全に分離されているわけではありません。公式との互換性についての課題 も公開されています。 tsc-ts Rust 以外の言語による別実装として、tsc-ts も紹介します。Go 製 TypeScript 7.0.2 を TypeScript に移植した実験的なコンパイラで、そのコードを scriptc でコンパイルし、ネイティブ実行ファイルとして提供します。 TypeScript に戻したのに速くなる、というのが少し不思議に見えますが、従来とは実行方法が違います。JavaScript にして動かす代わりに、コンパイラ自身を機械語にしています。 scriptc は型情報を使って値の表現を決め、LLVM でコードを生成します。コンパイルできる範囲には制限があり、未対応の処理は報告されます。 なぜこの時期に別実装が相次いだのか tsrs や tsc-rs には、Go 版という移植元と公開テストがあります。言語の挙動やアルゴリズムを一から設計するのとは出発点が違い、元の実装と比較しながら開発できます。こうした蓄積も後発の移植を支えているのではないかと考えています。 移植に使う手段も変わっています。tsc-rs は LLM による移植の実験で、先ほどの tsrs の発表でも AI が大規模な移植を進められるようになったことを背景に挙げています。ただし、Rust 側のメモリ管理の設計や、元と同じエラーを出すかの確認は残ります。 さらに、各実装が目指す使い方も異なります。tsrs は速度に加えて、メモリ使用量や WebAssembly(Wasm)での実行を重視しています。bun check は実行・テスト・ビルドと型チェックをまとめています。こうした用途に合わせてメモリ管理や組み込み方を変えることも、別実装を作る動機になっていると感じました。 公開ベンチマークを見てみる 公開されている測定結果をいくつか載せます。 測定環境や対象コードが異なるので、別々の表の秒数を比べて順位は付けられません。処理系による違いに加えて、同じ処理系でも対象コードによって差が出る点を見ていただければと思います。 tsgo・tsrs・bun check の比較 tsrs の 公開ベンチマーク から、型チェックを並列に行うワーカー数を 4 にそろえた測定を抜粋しました。これは 0.19.0 beta より前に行われた測定の記録です。 対象 tsgo tsrs bun check VS Code 10.94 秒 2.21 秒 4.48 秒 Playwright 1.23 秒 0.24 秒 0.50 秒 16 vCPU / 63 GB RAM の AMD EPYC / Linux で、--noEmit による型チェックを測っています。tsgo は 7.0.2、tsrs はコミット d57703ab5f07 の PGO(事前に集めた実行プロファイルを使う最適化)適用ビルド、Bun は 1.4.4-canary.1+5f5799ed1 です。中央値を使っていますが、測定回数は tsgo が 3 回、ほかは 10 回です。 この結果では tsrs が速いものの、移植元は 7.1 の開発版(b85298b6)で、tsgo の 7.0.2 とはバージョンが違います。VS Code ではエラー数にも差があり、公開資料では対応する Go の開発版と照らして説明しています。速度と互換性は分けて見る必要がありそうです。 tsc-rs の比較 tsc-rs の開発元も実際のアプリを使った 測定結果 を公開しています。入力コードや各回の記録は、測定データ から確認できます。 対象 tsgo tsc-rs tsc-rs --fast VS Code 9.57 秒 4.81 秒 2.64 秒 Sentry 13.49 秒 5.30 秒 2.97 秒 Playwright 0.82 秒 0.41 秒 0.33 秒 測定日は 2026 年 10 月 13 日で、16 AMD EPYC vCPU / Linux、ウォームアップ 1 回後の 5 回の中央値です。--noEmit --incremental false を使い、並列数は各ツールのデフォルトのままです。 tsc-rs は 0.6.0 の release PGO ビルドで、BOLT は使っていません。比較する Go 版は移植元と同じ 7.1.0-dev.20261008.1 です。この測定では、通常モードと fast モードの両方で Go 版と診断結果が一致したと報告されています。互換性の確認はこの測定対象の範囲です。 tsz は対象によって結果が変わる tsz の 公開結果 では、速いケースと遅いケースの両方が見られます。 対象 tsgo tsz RxJS 129 ミリ秒 51 ミリ秒 ts-essentials 100 ミリ秒 109 ミリ秒 これは 2026 年 10 月 25 日 04:55 UTC 生成の一覧ページに掲載された値です。tsz はコミット 0b4641a、PGO なしの release ビルドです。GitHub Actions の Linux 上で、Intel Xeon Platinum 8370C、4 CPU / 15.6 GiB RAM という条件の測定です。 同じ一覧には、Zod では tsz の型チェックに Go 版の約 19.4 倍の時間がかかることや、型チェックが完了しなかったケースも記載されています。なお、一覧ページだけでは Go 版の厳密なコミットや測定回数を確認できませんでした。一覧と個別ページの表示値にも差があるため、ここでは一覧に掲載された結果の紹介にとどめます。 tsc-ts の公開された測定例 tsc-ts については、enyst 氏が手順と記録を公開しているベンチマーク がありました。以下は GitHub Actions 上の結果です。 対象 従来の tsc tsgo tsc-ts Canvas 29.071 秒 5.452 秒 3.770 秒 SDK の TypeScript クライアント 2.253 秒 0.319 秒 0.334 秒 SmolPaws server 2.647 秒 0.898 秒 0.546 秒 測定日は 2026 年 10 月 17〜18 日で、Ubuntu 24.04 / x86-64、4 論理 CPU のランナー上の結果です。--noEmit の新規プロセスを起動し、ウォームアップ後に 5 回ずつ交互に測った中央値を使っています。各プロジェクトは別ジョブで、並列数は各ツールのデフォルトのままです。 tsc-ts は 0.0.2、Go 版は @typescript/native-preview@7.0.0-dev.20260707.2 という正式公開前のプレビューです。従来の tsc は Canvas と SDK が 6.0.3、server が 5.9.3 です。Canvas では baseUrl を削除し、paths に相当する指定を追加した共通設定を 3 ツールで使っています。互換性の確認は、意図的に追加した少数の型エラーに対するものです。 Canvas と server では tsc-ts が速く、SDK では Go 版が少し速い結果でした。比較対象の Go 版が古いため、現在の公式実装にも同じ差があるとは言えませんが、TypeScript 製のコンパイラをネイティブで動かす例として興味深いです。 「何倍速い」の前提も確認したい 公式実装も改善を続けています。10 月 20 日公開の TypeScript 7.1 Beta では、4 ワーカー、--noEmit の条件で、7.0 から 1.2〜1.9 倍の高速化が報告されています。 先ほどの tsrs の発表でも、一部の最適化が公式実装に取り込まれたと説明されています。Rust と Go の実装が別々に速くなるだけでなく、改善を共有しているのも面白いところです。 おわりに 今回調べてみて、Go 版や公開テストを利用でき、AI で移植を進める手段も増えたことが、別実装を作りやすくしているのではないかと感じました。後発の実装は公式の成果を使いながら、用途に合わせてメモリ管理や実行方法を工夫しています。 エディターとの連携や CI の高速化、ブラウザー内での実行など、用途によって選ぶ処理系も変わっていくのではないかと思います。 一方で、公式の変更を追って互換性を保ち続ける作業は残ります。個人的には速度だけでなく、各実装がどのように変更を取り込み、協力・統合していくのかも引き続き追っていきたいと思います。 脚注 「約 3 か月後」は、7.0 の正式公開から、10 月に型チェック機能の公開や協力体制の発表が続いた時期までの間隔です。各プロジェクトの開発開始日や、移植にかかった期間を示すものではありません。 ↩︎

  9. 53万行のプルリクに対してレビュアーが「目をつぶってマージすればええんか?(意訳)」と返していて草 feat: tsrslint by camc314 · Pull Request #624 · oxc-project/tsrs tsrs#624

    4 likes · 205 views
  10. YouTube · · YouTube description · Bitwise AI · oxc-project/tsrs

    Copilot Rewrote Its Own Engine in Rust: 832,000 Lines Copilot rewrote its own engine in Rust: GitHub ported the Copilot agent runtime to 832,378 lines of Rust, mostly by one developer steering agents. Then agents rewrote the TypeScript type checker too, and that one, tsrs, you can try today. Stephen Toub ported the engine behind Copilot CLI, the Copilot app and the SDK from TypeScript one pull request at a time over about 14.5 weeks (May 12 to Aug 21, 2026), with 468,689 lines of Rust tests as the safety net; GitHub estimates the job would have taken "a whole team of developers a year or two" before agents. GitHub's speed numbers come from its C# SDK benchmark with model calls stubbed: one turn went from 5.25 s to 1.33 s, 4x faster by default, and the 18x (292 ms) is only with the engine loaded in-process, which is opt-in; GitHub says other changes landed in the same months, so take them "with some grains of salt". tsrs, the Rust port of the TypeScript compiler written by agents per its creator Max Schwenk and now incubated in Oxc by Cloudflare and VoidZero, is "up to 8x faster" than TypeScript 7.0 with ~70% less memory in Cloudflare's early benchmarks at the same number of worker threads, and the maintainers' own per-project figures vary widely. It is experimental: npm release 0.18.0 (published Oct 19) does not include the fix for issue #725, where errors can appear or disappear between runs (fixed Oct 24), so compare its error counts against your usual check; every number here is the makers' own, and I did not measure either rewrite. TIMESTAMPS 0:00 - Copilot rewrote its own engine in Rust 0:22 - Where your agent waits 0:45 - One developer, a lot of agents 1:26 - What GitHub measured: 4x default, 18x opt-in 2:03 - tsrs: the TypeScript checker is next 2:33 - What Cloudflare says: up to 8x 2:59 - Try tsrs on your repo 3:24 - Reality check: new bugs 3:46 - Verdict: try tsrs if, skip if LINKS & RESOURCES - GitHub, Migrating the Copilot runtime to Rust: github.blog - Cloudflare, tsrs announcement: blog.cloudflare.com - Max Schwenk, how tsrs was built: building.owner.com - tsrs repository and README: oxc-project/tsrs - tsrs benchmark results: github.com/oxc-project/tsrs/blob/main/bench/RESUL… - tsrs issue #725: tsrs#725 - tsrs on npm: registry.npmjs.org - TypeScript 7.0 announcement: devblogs.microsoft.com - Photo: Stephen Toub (GitHub profile avatar, author photo on the cited post), license unknown, github.blog MORE ON THIS CHANNEL - 2,000 AI Agents Rewrote a Coding Agent in Rust: youtu.be - Claude Rewrote 1 Million Lines of Bun in 11 Days: youtu.be - Rust Cut React's Compiler From 14.3s to 0.81s: youtu.be TAGS #GitHubCopilot #Rust #TypeScript #AICodingAgents [ar] Copilot تعيد كتابة محركها بلغة Rust: 832,000 سطر برمجي أعاد Copilot كتابة محركه الخاص بلغة Rust: قام GitHub بنقل بيئة تشغيل وكيل Copilot إلى 832,378 سطرًا من Rust، معظمها من قِبل مطور واحد يُشرف على الوكلاء. ثم أعاد الوكلاء كتابة مدقق أنواع TypeScript أيضًا، ويمكنك تجربته اليوم. قام ستيفن توب بنقل المحرك الذي يدعم واجهة سطر أوامر Copilot، وتطبيق Copilot، وSDK من TypeScript، طلب سحب تلو الآخر على مدار 14.5 أسبوعًا تقريبًا (من 12 مايو إلى 21 أغسطس 2026)، مع 468,689 سطرًا من اختبارات Rust كإجراء احترازي؛ ويُقدّر GitHub أن هذه المهمة كانت ستستغرق "عامًا أو عامين من قِبل فريق كامل من المطورين" قبل أن يصبح الوكلاء جاهزين. تستند أرقام سرعة GitHub إلى معيار أداء C# SDK مع تعطيل استدعاءات النماذج: انخفضت مدة تنفيذ دورة واحدة من 5.25 ثانية إلى 1.33 ثانية، أي أسرع بأربع مرات افتراضيًا، أما الزيادة بمقدار 18 ضعفًا (292 مللي ثانية) فتتحقق فقط عند تحميل المحرك داخل العملية، وهو خيار اختياري. تشير GitHub إلى أن تغييرات أخرى طُبقت في نفس الأشهر، لذا يجب أخذ هذه الأرقام بحذر. أما tsrs، وهو منفذ Rust لمترجم TypeScript الذي كتبه وكلاء وفقًا لمنشئه ماكس شوينك، والذي يتم تطويره حاليًا في Oxc بواسطة Cloudflare وVoidZero، فهو أسرع بثمانية أضعاف من TypeScript 7.0 مع استهلاك ذاكرة أقل بنسبة 70% تقريبًا في معايير الأداء الأولية لـ Cloudflare عند نفس عدد سلاسل العمل، وتختلف أرقام المطورين لكل مشروع على حدة بشكل كبير. هذه نسخة تجريبية: إصدار npm 0.18.0 (المنشور في 19 أكتوبر) لا يتضمن إصلاح المشكلة رقم 725، حيث قد تظهر الأخطاء أو تختفي بين عمليات التشغيل (تم إصلاحها في 24 أكتوبر)، لذا قارن عدد الأخطاء فيه مع فحصك المعتاد؛ جميع الأرقام المذكورة هنا هي أرقام المطورين أنفسهم، ولم أقم بقياس أي من النسختين. الطوابع الزمنية 0:00 - أعاد Copilot كتابة محركه الخاص بلغة Rust 0:22 - أين ينتظر وكيلك 0:45 - مطور واحد، العديد من الوكلاء 1:26 - قياسات GitHub: 4 أضعاف افتراضيًا، 18 ضعفًا اختياريًا 2:03 - tsrs: مدقق TypeScript هو الخطوة التالية 2:33 - ما تقوله Cloudflare: يصل إلى 8 أضعاف 2:59 - جرّب tsrs على مستودعك 3:24 - نظرة واقعية: أخطاء جديدة 3:46 - الخلاصة: جرّب tsrs إذا، وتجاوزه إذا الروابط والموارد - GitHub، ترحيل وقت تشغيل Copilot إلى Rust: github.blog - Cloudflare، إعلان tsrs: blog.cloudflare.com - ماكس شوينك، كيف تم بناء tsrs: building.owner.com - مستودع tsrs وملف README: oxc-project/tsrs - نتائج اختبار أداء tsrs: github.com/oxc-project/tsrs/blob/main/bench/RESUL… - مشكلة tsrs رقم 725: tsrs#725 - tsrs على npm: registry.npmjs.org - إعلان TypeScript 7.0: devblogs.microsoft.com - الصورة: ستيفن توب (صورة الملف الشخصي على GitHub، صورة المؤلف في المنشور المذكور)، الترخيص غير معروف. github.blog المزيد على هذه القناة - 2000 وكيل ذكاء اصطناعي أعادوا كتابة وكيل برمجة بلغة Rust: youtu.be - كلود أعاد كتابة مليون سطر برمجي في 11 يومًا: youtu.be - Rust قلل وقت مُصرّف React من 14.3 ثانية إلى 0.81 ثانية: youtu.be الوسوم #GitHubCopilot #Rust #TypeScript #AICodingAgents [bn] Copilot তার নিজস্ব ইঞ্জিন Rust-এ নতুন করে লিখেছে: ৮,৩২,০০০ লাইন কোপাইলট তার নিজস্ব ইঞ্জিনটি রাস্ট (Rust) ভাষায় নতুন করে লিখেছে: গিটহাব কোপাইলট এজেন্ট রানটাইমটিকে ৮৩২,৩৭৮ লাইনের রাস্ট কোডে পোর্ট করেছে, যার বেশিরভাগটাই এজেন্টদের পরিচালনাকারী একজন ডেভেলপারের দ্বারা সম্পন্ন হয়েছে। এরপর এজেন্টরা টাইপস্ক্রিপ্ট টাইপ চেকারটিও নতুন করে লিখেছে, এবং সেটি, tsrs, আপনি আজই ব্যবহার করে দেখতে পারেন। স্টিফেন টুব প্রায় ১৪.৫ সপ্তাহ ধরে (১২ই মে থেকে ২১শে আগস্ট, ২০২৬) একবারে একটি করে পুল রিকোয়েস্টের মাধ্যমে কোপাইলট CLI, কোপাইলট অ্যাপ এবং SDK-এর পেছনের ইঞ্জিনটি টাইপস্ক্রিপ্ট থেকে পোর্ট করেছেন, এবং এর সাথে সুরক্ষাকবচ হিসেবে ৪৬৮,৬৮৯ লাইনের রাস্ট টেস্ট ব্যবহার করেছেন; গিটহাবের অনুমান অনুযায়ী, এজেন্টদের আসার আগে এই কাজটি করতে "ডেভেলপারদের একটি পুরো দলের এক বা দুই বছর" সময় লাগত। গিটহাবের স্পিডের পরিসংখ্যান এসেছে এর C# SDK বেঞ্চমার্ক থেকে, যেখানে মডেল কলগুলো স্টাব করা হয়েছে: একটি টার্নের সময় ৫.২৫ সেকেন্ড থেকে কমে ১.৩৩ সেকেন্ড হয়েছে, যা ডিফল্টভাবে ৪ গুণ দ্রুততর, এবং এই ১৮ গুণ (২৯২ মিলিসেকেন্ড) পার্থক্যটি শুধুমাত্র তখনই দেখা যায় যখন ইঞ্জিনটি ইন-প্রসেস লোড করা থাকে, যা ঐচ্ছিক; গিটহাবের মতে, একই মাসগুলোতে অন্যান্য পরিবর্তনও আনা হয়েছে, তাই এই পরিসংখ্যানগুলোকে "কিছুটা সন্দেহের চোখে" গ্রহণ করা উচিত। tsrs, যা এর নির্মাতা ম্যাক্স শোয়েঙ্কের মতে এজেন্টদের দ্বারা লিখিত টাইপস্ক্রিপ্ট কম্পাইলারের রাস্ট পোর্ট এবং বর্তমানে ক্লাউডফ্লেয়ার ও ভয়েডজিরোর তত্ত্বাবধানে Oxc-তে ইনকিউবেটেড, ক্লাউডফ্লেয়ারের প্রাথমিক বেঞ্চমার্কে একই সংখ্যক ওয়ার্কার থ্রেডে প্রায় ৭০% কম মেমরি ব্যবহার করে টাইপস্ক্রিপ্ট ৭.০-এর চেয়ে "৮ গুণ পর্যন্ত দ্রুততর", এবং মেইনটেইনারদের নিজস্ব প্রজেক্ট-ভিত্তিক পরিসংখ্যানের মধ্যে ব্যাপক ভিন্নতা দেখা যায়। এটি পরীক্ষামূলক: npm রিলিজ 0.18.0 (১৯ অক্টোবর প্রকাশিত)-এ ইস্যু #725-এর সমাধানটি অন্তর্ভুক্ত নেই, যেখানে রানগুলোর মধ্যে ত্রুটি দেখা দিতে বা অদৃশ্য হয়ে যেতে পারত (২৪ অক্টোবর সমাধান করা হয়েছে), তাই এর ত্রুটির সংখ্যা আপনার নিয়মিত যাচাইয়ের সাথে তুলনা করুন; এখানকার প্রতিটি সংখ্যা নির্মাতাদের নিজস্ব, এবং আমি কোনো পুনর্লিখন পরিমাপ করিনি। টাইমস্ট্যাম্প ০:০০ - কোপাইলট তার নিজস্ব ইঞ্জিন রাস্ট-এ নতুন করে লিখেছে ০:২২ - আপনার এজেন্ট কোথায় অপেক্ষা করে ০:৪৫ - একজন ডেভেলপার, অনেক এজেন্ট ১:২৬ - গিটহাব যা পরিমাপ করেছে: ডিফল্টের চেয়ে ৪ গুণ, অপ্ট-ইন-এর চেয়ে ১৮ গুণ ২:০৩ - টিএসআরএস: পরবর্তী টাইপস্ক্রিপ্ট চেকার ২:৩৩ - ক্লাউডফ্লেয়ার যা বলছে: ৮ গুণ পর্যন্ত ২:৫৯ - আপনার রিপো-তে টিএসআরএস ব্যবহার করে দেখুন ৩:২৪ - বাস্তবতার যাচাই: নতুন বাগ ৩:৪৬ - সিদ্ধান্ত: টিএসআরএস ব্যবহার করে দেখুন, যদি প্রয়োজন হয় তবে এড়িয়ে যান লিঙ্ক ও রিসোর্স - গিটহাব, কোপাইলট রানটাইম রাস্ট-এ মাইগ্রেট করা: github.blog - ক্লাউডফ্লেয়ার, টিএসআরএস ঘোষণা: blog.cloudflare.com - ম্যাক্স শ্বেঙ্ক, যেভাবে tsrs তৈরি করা হয়েছিল: building.owner.com - tsrs রিপোজিটরি এবং README: oxc-project/tsrs - tsrs বেঞ্চমার্ক ফলাফল: github.com/oxc-project/tsrs/blob/main/bench/RESUL… - tsrs ইস্যু #৭২৫: tsrs#725 - npm-এ tsrs: registry.npmjs.org - TypeScript ৭.০ ঘোষণা: devblogs.microsoft.com - ছবি: স্টিফেন টুব (গিটহাব প্রোফাইল অ্যাভাটার, উল্লিখিত পোস্টে লেখকের ছবি), লাইসেন্স অজানা, github.blog এই বিষয়ে আরও চ্যানেল - ২,০০০ এআই এজেন্ট রাস্ট (Rust) ব্যবহার করে একটি কোডিং এজেন্ট নতুন করে লিখেছে: youtu.be - ক্লদ (Claude) ১১ দিনে ১০ লক্ষ লাইনের ‘বান’ (Bun) নতুন করে লিখেছে: youtu.be - রাস্ট (Rust) রিয়্যাক্ট (React)-এর কম্পাইলারের সময় ১৪.৩ সেকেন্ড থেকে কমিয়ে ০.৮১ সেকেন্ড করেছে: youtu.be ট্যাগ #GitHubCopilot #Rust #TypeScript #AICodingAgents [de-DE] Copilot hat seine eigene Engine in Rust neu geschrieben: 832.000 Zeilen Copilot hat seine Engine in Rust neu geschrieben: GitHub portierte die Copilot-Agent-Laufzeitumgebung auf 832.378 Zeilen Rust, größtenteils von einem Entwickler, der die Agenten steuerte. Anschließend schrieben die Agenten auch den TypeScript-Typchecker neu, und diesen, tsrs, können Sie heute testen. Stephen Toub portierte die Engine hinter der Copilot-CLI, der Copilot-App und dem SDK über einen Zeitraum von etwa 14,5 Wochen (12. Mai bis 21. August 2026) schrittweise von TypeScript, indem er Pull Requests für Pull Request bearbeitete. Als Sicherheitsnetz dienten 468.689 Zeilen Rust-Tests. GitHub schätzt, dass ein ganzes Entwicklerteam vor der Einführung der Agenten für diese Aufgabe „ein bis zwei Jahre“ gebraucht hätte. Die Geschwindigkeitsangaben von GitHub stammen aus dem C#-SDK-Benchmark mit simulierten Modellaufrufen: Ein Durchlauf verkürzte sich von 5,25 s auf 1,33 s, was einer standardmäßigen vierfachen Beschleunigung entspricht. Die 18-fache Beschleunigung (292 ms) wird nur erreicht, wenn die Engine im Prozess geladen ist (optional). GitHub weist darauf hin, dass in denselben Monaten weitere Änderungen vorgenommen wurden, daher sollten diese Angaben mit Vorsicht betrachtet werden. tsrs, die Rust-Portierung des TypeScript-Compilers, die von Agenten gemäß ihrem Entwickler Max Schwenk geschrieben und nun von Cloudflare und VoidZero im Oxc-Inkubator betreut wird, ist in frühen Benchmarks von Cloudflare bei gleicher Anzahl an Worker-Threads bis zu achtmal schneller als TypeScript 7.0 und benötigt dabei rund 70 % weniger Speicher. Die Angaben der einzelnen Projekte der Entwickler variieren jedoch stark. Es handelt sich um eine experimentelle Version: Die npm-Version 0.18.0 (veröffentlicht am 19. Oktober) enthält noch nicht die Behebung für Problem #725, bei dem Fehler zwischen den Ausführungen auftreten oder verschwinden konnten (behoben am 24. Oktober). Vergleichen Sie daher die Fehleranzahl mit Ihrer üblichen Überprüfung. Alle hier angegebenen Zahlen stammen von den Entwicklern, und ich habe die Fehleranzahl bei keiner der Überarbeitungen gemessen. ZEITSTEMPEL 0:00 – Copilot hat seine eigene Engine in Rust neu geschrieben 0:22 – Wo Ihr Agent wartet 0:45 – Ein Entwickler, viele Agenten 1:26 – GitHubs Messung: 4-fache Standardleistung, 18-fache optionale Leistung 2:03 – tsrs: Der TypeScript-Checker ist der nächste Schritt 2:33 – Cloudflares Aussage: Bis zu 8-fache Leistung 2:59 – Testen Sie tsrs in Ihrem Repository 3:24 – Realitätscheck: Neue Fehler 3:46 – Fazit: tsrs testen, ansonsten überspringen LINKS & RESSOURCEN - GitHub, Migration der Copilot-Laufzeitumgebung nach Rust: github.blog - Cloudflare, tsrs-Ankündigung: blog.cloudflare.com - Max Schwenk, wie tsrs wurde erstellt: building.owner.com - tsrs-Repository und README: oxc-project/tsrs - tsrs-Benchmark-Ergebnisse: github.com/oxc-project/tsrs/blob/main/bench/RESUL… - tsrs-Problem #725: tsrs#725 - tsrs auf npm: registry.npmjs.org - Ankündigung von TypeScript 7.0: devblogs.microsoft.com - Foto: Stephen Toub (GitHub-Profilbild, Autorenfoto im zitierten Beitrag), Lizenz unbekannt github.blog MEHR AUF DIESEM KANAL - 2.000 KI-Agenten haben einen Programmieragenten in Rust neu geschrieben: youtu.be - Claude hat 1 Million Zeilen von Bun in 11 Tagen neu geschrieben: youtu.be - Rust hat den React-Compiler von 14,3 Sekunden auf 0,81 Sekunden verkürzt: youtu.be TAGS #GitHubCopilot #Rust #TypeScript #AICodingAgents [es-US] Copilot reescribió su propio motor en Rust: 832,000 líneas Copilot reescribió su propio motor en Rust: GitHub migró el entorno de ejecución del agente de Copilot a 832.378 líneas de Rust, principalmente por un desarrollador que gestionaba los agentes. Posteriormente, los agentes también reescribieron el verificador de tipos de TypeScript, que ya puedes probar. Stephen Toub migró el motor de la CLI de Copilot, la aplicación Copilot y el SDK desde TypeScript, mediante solicitudes de extracción, durante aproximadamente 14,5 semanas (del 12 de mayo al 21 de agosto de 2026), con 468.689 líneas de pruebas en Rust como medida de seguridad. GitHub estima que este trabajo habría requerido "un equipo completo de desarrolladores durante uno o dos años" antes de la llegada de los agentes. Las cifras de velocidad de GitHub provienen de su prueba de rendimiento del SDK de C# con llamadas al modelo simuladas: una vuelta pasó de 5,25 s a 1,33 s, 4 veces más rápido por defecto, y el 18x (292 ms) es solo con el motor cargado en el proceso, que es opcional; GitHub dice que otros cambios se implementaron en los mismos meses, así que tómelos "con un poco de sal". tsrs, el puerto de Rust del compilador de TypeScript escrito por agentes según su creador Max Schwenk y ahora incubado en Oxc por Cloudflare y VoidZero, es "hasta 8 veces más rápido" que TypeScript 7.0 con ~70% menos de memoria en las primeras pruebas de rendimiento de Cloudflare con el mismo número de subprocesos de trabajo, y las cifras por proyecto de los propios mantenedores varían ampliamente. Es experimental: la versión 0.18.0 de npm (publicada el 19 de octubre) no incluye la solución para el problema n.° 725, donde los errores pueden aparecer o desaparecer entre ejecuciones (solucionado el 24 de octubre). Por lo tanto, compare el número de errores con su método habitual; todas las cifras que aparecen aquí son proporcionadas por los desarrolladores y no he realizado ninguna medición en ninguna de las reescrituras. MARCAS DE TIEMPO 0:00 - Copilot reescribió su propio motor en Rust 0:22 - Dónde espera tu agente 0:45 - Un desarrollador, muchos agentes 1:26 - Lo que midió GitHub: 4 veces por defecto, 18 veces con activación voluntaria 2:03 - tsrs: el verificador de TypeScript es el siguiente 2:33 - Lo que dice Cloudflare: hasta 8 veces más rápido 2:59 - Prueba tsrs en tu repositorio 3:24 - Prueba de realidad: nuevos errores 3:46 - Veredicto: prueba tsrs si, omítelo si no ENLACES Y RECURSOS - GitHub, Migración del entorno de ejecución de Copilot a Rust: github.blog - Cloudflare, anuncio de tsrs: blog.cloudflare.com - Max Schwenk, cómo se construyó tsrs: building.owner.com - Repositorio y README de tsrs: oxc-project/tsrs - Resultados de la prueba de rendimiento de tsrs: github.com/oxc-project/tsrs/blob/main/bench/RESUL… - Problema n.° 725 de tsrs: tsrs#725 - tsrs en npm: registry.npmjs.org - Anuncio de TypeScript 7.0: devblogs.microsoft.com - Foto: Stephen Toub (avatar del perfil de GitHub, foto del autor en la publicación citada), licencia desconocida. github.blog MÁS EN ESTE CANAL - 2000 agentes de IA reescribieron un agente de codificación en Rust: youtu.be - Claude reescribió 1 millón de líneas de Bun en 11 días: youtu.be - Rust redujo el tiempo de compilación de React de 14,3 s a 0,81 s: youtu.be ETIQUETAS #GitHubCopilot #Rust #TypeScript #AICodingAgents [fr-FR] Copilot a réécrit son propre moteur en Rust : 832 000 lignes Copilot a réécrit son propre moteur en Rust : GitHub a porté l'environnement d'exécution de l'agent Copilot vers 832 378 lignes de Rust, principalement grâce au travail d'un seul développeur. Les agents ont ensuite réécrit le vérificateur de types TypeScript, tsrs, que vous pouvez tester dès aujourd'hui. Stephen Toub a porté le moteur de l'interface de ligne de commande Copilot, l'application Copilot et le SDK depuis TypeScript, une requête d'extraction à la fois, sur une période d'environ 14,5 semaines (du 12 mai au 21 août 2026), avec 468 689 lignes de tests Rust comme filet de sécurité. GitHub estime que ce travail aurait nécessité « une équipe complète de développeurs pendant un an ou deux » avant l'arrivée des agents. Les chiffres de vitesse de GitHub proviennent de son benchmark du SDK C# avec les appels de modèle simulés : un tour est passé de 5,25 s à 1,33 s, soit 4 fois plus rapide par défaut, et le gain de 18x (292 ms) n'est obtenu qu'avec le moteur chargé en interne, une option à activer. GitHub précise que d'autres modifications ont été apportées durant les mêmes mois ; il convient donc d'interpréter ces chiffres avec prudence. tsrs, le portage Rust du compilateur TypeScript écrit par agents selon son créateur Max Schwenk et désormais incubé chez Oxc par Cloudflare et VoidZero, est « jusqu'à 8 fois plus rapide » que TypeScript 7.0 avec environ 70 % de mémoire en moins d'après les premiers benchmarks de Cloudflare, pour un même nombre de threads de travail. Les chiffres fournis par les mainteneurs varient considérablement d'un projet à l'autre. Il s'agit d'une version expérimentale : la version 0.18.0 de npm (publiée le 19 octobre) ne corrige pas le problème n° 725, où des erreurs pouvaient apparaître ou disparaître entre les exécutions (corrigé le 24 octobre). Comparez donc le nombre d'erreurs affiché avec votre méthode de vérification habituelle ; les chiffres indiqués ici sont ceux des développeurs et je n'ai effectué aucune mesure avec les deux réécritures. HORODATAGE 0:00 - Copilot a réécrit son moteur en Rust 0:22 - Où votre agent attend 0:45 - Un développeur, de nombreux agents 1:26 - Mesures GitHub : x4 par défaut, x18 avec option d'activation 2:03 - tsrs : le vérificateur TypeScript arrive bientôt 2:33 - Avis de Cloudflare : jusqu'à x8 2:59 - Testez tsrs sur votre dépôt 3:24 - Constat : nouveaux bugs 3:46 - Verdict : essayez tsrs si nécessaire, ignorez-le sinon LIENS ET RESSOURCES - GitHub, Migration du runtime Copilot vers Rust : github.blog - Cloudflare, Annonce tsrs : blog.cloudflare.com - Max Schwenk, comment tsrs a été construit : building.owner.com - Dépôt et fichier README de tsrs : oxc-project/tsrs - Résultats des tests de performance de tsrs : github.com/oxc-project/tsrs/blob/main/bench/RESUL… - Problème n° 725 concernant tsrs : tsrs#725 - tsrs sur npm : registry.npmjs.org - Annonce de TypeScript 7.0 : devblogs.microsoft.com - Photo : Stephen Toub (avatar de profil GitHub, photo de l’auteur dans l’article cité), licence inconnue github.blog PLUS DE VIDÉOS SUR CETTE CHAÎNE - 2 000 agents IA ont réécrit un agent de codage en Rust : youtu.be - Claude a réécrit 1 million de lignes de Bun en 11 jours : youtu.be - Rust a réduit le temps de compilation de React de 14,3 s à 0,81 s : youtu.be TAGS #GitHubCopilot #Rust #TypeScript #AICodingAgents [hi] Copilot ने Rust में अपना इंजन फिर से लिखा: 8,32,000 लाइन्स कोपायलट ने अपने इंजन को रस्ट में फिर से लिखा: गिटहब ने कोपायलट एजेंट रनटाइम को 832,378 लाइनों के रस्ट कोड में पोर्ट किया, जिसमें से अधिकांश काम एक ही डेवलपर ने एजेंटों को निर्देशित करते हुए किया। फिर एजेंटों ने टाइपस्क्रिप्ट टाइप चेकर को भी फिर से लिखा, और आप आज ही उसका उपयोग कर सकते हैं (tsrs)। स्टीफन टौब ने कोपायलट सीएलआई, कोपायलट ऐप और एसडीके के इंजन को टाइपस्क्रिप्ट से पोर्ट किया, जिसमें एक-एक पुल रिक्वेस्ट के माध्यम से लगभग 14.5 सप्ताह (12 मई से 21 अगस्त, 2026) का समय लगा, और सुरक्षा कवच के रूप में 468,689 लाइनों के रस्ट टेस्ट का उपयोग किया गया; गिटहब का अनुमान है कि एजेंटों के आने से पहले इस काम में "डेवलपर्स की एक पूरी टीम को एक या दो साल" लग जाते। GitHub के गति संबंधी आंकड़े इसके C# SDK बेंचमार्क से प्राप्त हुए हैं, जिसमें मॉडल कॉल को स्टब किया गया है: एक टर्न का समय 5.25 सेकंड से घटकर 1.33 सेकंड हो गया, जो डिफ़ॉल्ट रूप से 4 गुना तेज़ है, और 18 गुना (292 मिलीसेकंड) की गति केवल तब प्राप्त होती है जब इंजन को इन-प्रोसेस लोड किया जाता है, जो वैकल्पिक है; GitHub का कहना है कि अन्य परिवर्तन भी उसी महीने में लागू किए गए थे, इसलिए इन आंकड़ों को पूरी तरह से विश्वसनीय न मानें। tsrs, जो कि इसके निर्माता मैक्स श्वेंक द्वारा एजेंटों के माध्यम से लिखा गया TypeScript कंपाइलर का Rust पोर्ट है और अब Cloudflare और VoidZero द्वारा Oxc में विकसित किया जा रहा है, Cloudflare के शुरुआती बेंचमार्क में समान संख्या में वर्कर थ्रेड्स पर TypeScript 7.0 की तुलना में लगभग 70% कम मेमोरी के साथ "8 गुना तक तेज़" है, और मेंटेनर्स के अपने प्रति-प्रोजेक्ट आंकड़े काफी भिन्न हैं। यह प्रायोगिक है: npm रिलीज़ 0.18.0 (19 अक्टूबर को प्रकाशित) में समस्या #725 का समाधान शामिल नहीं है, जिसमें त्रुटियाँ रन के बीच प्रकट या गायब हो सकती हैं (24 अक्टूबर को ठीक किया गया), इसलिए इसकी त्रुटि गणना की तुलना अपनी सामान्य जाँच से करें; यहाँ दी गई प्रत्येक संख्या निर्माताओं की स्वयं की है, और मैंने किसी भी पुनर्लेखन को नहीं मापा है। समय-सारणी 0:00 - कोपायलट ने अपने इंजन को रस्ट में फिर से लिखा 0:22 - आपका एजेंट कहाँ प्रतीक्षा करता है 0:45 - एक डेवलपर, कई एजेंट 1:26 - GitHub ने क्या मापा: डिफ़ॉल्ट से 4 गुना, ऑप्ट-इन से 18 गुना 2:03 - tsrs: टाइपस्क्रिप्ट चेकर अगला कदम है 2:33 - क्लाउडफ्लेयर क्या कहता है: 8 गुना तक 2:59 - अपने रिपॉजिटरी पर tsrs आज़माएँ 3:24 - वास्तविकता की जाँच: नए बग 3:46 - निष्कर्ष: यदि आवश्यक हो तो tsrs आज़माएँ, अन्यथा छोड़ दें लिंक और संसाधन - GitHub, कोपायलट रनटाइम को रस्ट में माइग्रेट करना: github.blog - क्लाउडफ्लेयर, tsrs घोषणा: blog.cloudflare.com - मैक्स श्वेन्क, tsrs कैसे बनाया गया: building.owner.com - tsrs रिपॉजिटरी और README: oxc-project/tsrs - tsrs बेंचमार्क परिणाम: github.com/oxc-project/tsrs/blob/main/bench/RESUL… - tsrs समस्या #725: tsrs#725 - npm पर tsrs: registry.npmjs.org - TypeScript 7.0 की घोषणा: devblogs.microsoft.com - फोटो: स्टीफन टौब (GitHub प्रोफ़ाइल अवतार, उद्धृत पोस्ट पर लेखक की फोटो), लाइसेंस अज्ञात। github.blog इस चैनल पर और देखें - 2,000 AI एजेंटों ने रस्ट में एक कोडिंग एजेंट को फिर से लिखा: youtu.be - क्लाउड ने 11 दिनों में 10 लाख लाइनें लिखीं: youtu.be - रस्ट ने रिएक्ट के कंपाइलर का समय 14.3 सेकंड से घटाकर 0.81 सेकंड कर दिया: youtu.be टैग #GitHubCopilot #Rust #TypeScript #AICodingAgents [id] Copilot Menulis Ulang Mesinnya dengan Rust: 832.000 Baris Kode Copilot menulis ulang mesinnya sendiri dalam Rust: GitHub memindahkan runtime agen Copilot ke 832.378 baris kode Rust, sebagian besar oleh satu pengembang yang mengarahkan agen. Kemudian agen juga menulis ulang pemeriksa tipe TypeScript, dan yang satu itu, tsrs, dapat Anda coba hari ini. Stephen Toub memindahkan mesin di balik Copilot CLI, aplikasi Copilot, dan SDK dari TypeScript satu permintaan pull pada satu waktu selama sekitar 14,5 minggu (12 Mei hingga 21 Agustus 2026), dengan 468.689 baris pengujian Rust sebagai jaring pengaman; GitHub memperkirakan pekerjaan itu akan membutuhkan "seluruh tim pengembang selama satu atau dua tahun" sebelum agen. Angka kecepatan GitHub berasal dari benchmark SDK C# mereka dengan panggilan model yang di-stub: satu putaran turun dari 5,25 detik menjadi 1,33 detik, 4x lebih cepat secara default, dan 18x (292 ms) hanya terjadi ketika mesin dimuat dalam proses, yang bersifat opsional; GitHub mengatakan perubahan lain juga terjadi pada bulan yang sama, jadi anggaplah angka-angka tersebut "dengan sedikit keraguan". tsrs, port Rust dari kompiler TypeScript yang ditulis oleh agen sesuai dengan penciptanya Max Schwenk dan sekarang diinkubasi di Oxc oleh Cloudflare dan VoidZero, "hingga 8x lebih cepat" daripada TypeScript 7.0 dengan memori ~70% lebih sedikit dalam benchmark awal Cloudflare pada jumlah thread pekerja yang sama, dan angka per proyek dari para pengelola sangat bervariasi. Ini bersifat eksperimental: rilis npm 0.18.0 (diterbitkan 19 Oktober) tidak menyertakan perbaikan untuk masalah #725, di mana kesalahan dapat muncul atau hilang di antara eksekusi (diperbaiki 24 Oktober), jadi bandingkan jumlah kesalahannya dengan pemeriksaan Anda yang biasa; setiap angka di sini adalah milik pembuatnya sendiri, dan saya tidak mengukur penulisan ulang mana pun. CAP WAKTU 0:00 - Copilot menulis ulang mesinnya sendiri dalam Rust 0:22 - Di mana agen Anda menunggu 0:45 - Satu pengembang, banyak agen 1:26 - Apa yang diukur GitHub: 4x default, 18x opt-in 2:03 - tsrs: pemeriksa TypeScript selanjutnya 2:33 - Apa kata Cloudflare: hingga 8x 2:59 - Coba tsrs di repositori Anda 3:24 - Pengecekan realitas: bug baru 3:46 - Putusan: coba tsrs jika, lewati jika TAUTAN & SUMBER DAYA - GitHub, Migrasi runtime Copilot ke Rust: github.blog - Cloudflare, pengumuman tsrs: blog.cloudflare.com - Max Schwenk, bagaimana tsrs dibangun: building.owner.com - Repositori tsrs dan README: oxc-project/tsrs - Hasil benchmark tsrs: github.com/oxc-project/tsrs/blob/main/bench/RESUL… - Masalah tsrs #725: tsrs#725 - tsrs di npm: registry.npmjs.org - Pengumuman TypeScript 7.0: devblogs.microsoft.com - Foto: Stephen Toub (avatar profil GitHub, foto penulis pada postingan yang dikutip), lisensi tidak diketahui, github.blog LEBIH LANJUT DI SALURAN INI - 2.000 Agen AI Menulis Ulang Agen Pemrograman dalam Rust: youtu.be - Claude Menulis Ulang 1 Juta Baris Bun dalam 11 Hari: youtu.be - Rust Memangkas Kompilator React dari 14,3 detik menjadi 0,81 detik: youtu.be TAGS #GitHubCopilot #Rust #TypeScript #AICodingAgents [it] Copilot ha riscritto il suo motore in Rust: 832.000 righe di codice Copilot ha riscritto il proprio motore in Rust: GitHub ha portato il runtime degli agenti di Copilot su 832.378 righe di codice Rust, principalmente grazie al lavoro di un singolo sviluppatore. Successivamente, gli agenti hanno riscritto anche il type checker di TypeScript, che, tsrs, è disponibile per la prova immediata. Stephen Toub ha portato il motore alla base di Copilot CLI, dell'app Copilot e dell'SDK da TypeScript, una pull request alla volta, in circa 14,5 settimane (dal 12 maggio al 21 agosto 2026), con 468.689 righe di test in Rust a garanzia della sicurezza; GitHub stima che, prima degli agenti, un intero team di sviluppatori avrebbe impiegato uno o due anni per completare il lavoro. I dati sulla velocità di GitHub provengono dal benchmark dell'SDK C# con le chiamate al modello simulate: un'operazione è passata da 5,25 s a 1,33 s, 4 volte più veloce di default, e il 18x (292 ms) si riferisce solo al caricamento del motore in-process, che è opzionale; GitHub afferma che altre modifiche sono state implementate negli stessi mesi, quindi è bene prenderle "con le pinze". tsrs, la versione Rust del compilatore TypeScript scritta da agenti secondo il suo creatore Max Schwenk e ora incubata in Oxc da Cloudflare e VoidZero, è "fino a 8 volte più veloce" di TypeScript 7.0 con circa il 70% di memoria in meno nei primi benchmark di Cloudflare con lo stesso numero di thread di lavoro, e le cifre per progetto fornite dagli stessi manutentori variano notevolmente. Si tratta di una versione sperimentale: la release 0.18.0 di npm (pubblicata il 19 ottobre) non include la correzione per il problema n. 725, in cui gli errori potevano comparire o scomparire tra un'esecuzione e l'altra (risolto il 24 ottobre). Pertanto, confrontate il numero di errori riportato con il vostro controllo abituale; tutti i dati qui riportati sono forniti dagli sviluppatori e non ho effettuato misurazioni con nessuna delle due versioni. INDICE DEI CONTENUTI 0:00 - Copilot ha riscritto il proprio motore in Rust 0:22 - Dove attende il tuo agente 0:45 - Un solo sviluppatore, molti agenti 1:26 - Cosa ha misurato GitHub: 4 volte di default, 18 volte opt-in 2:03 - tsrs: il checker TypeScript è il prossimo 2:33 - Cosa dice Cloudflare: fino a 8 volte 2:59 - Prova tsrs sul tuo repository 3:24 - Verifica della realtà: nuovi bug 3:46 - Verdetto: prova tsrs se necessario, altrimenti no LINK E RISORSE - GitHub, Migrazione del runtime di Copilot a Rust: github.blog - Cloudflare, annuncio di tsrs: blog.cloudflare.com - Max Schwenk, come è stato creato tsrs: building.owner.com - Repository e README di tsrs: oxc-project/tsrs - Risultati del benchmark di tsrs: github.com/oxc-project/tsrs/blob/main/bench/RESUL… - Problema n. 725 di tsrs: tsrs#725 - tsrs su npm: registry.npmjs.org - Annuncio di TypeScript 7.0: devblogs.microsoft.com - Foto: Stephen Toub (avatar del profilo GitHub, foto dell'autore nel post citato), licenza sconosciuta. Italiano: github.blog ALTRI CONTENUTI SU QUESTO CANALE - 2.000 agenti AI hanno riscritto un agente di programmazione in Rust: youtu.be - Claude ha riscritto 1 milione di righe di codice di Bun in 11 giorni: youtu.be - Rust ha ridotto il tempo di compilazione di React da 14,3 secondi a 0,81 secondi: youtu.be TAG #GitHubCopilot #Rust #TypeScript #AICodingAgents [iw] Copilot שכתב את המנוע שלו ב-Rust: 832,000 שורות קוד Copilot כתב מחדש את המנוע שלו ב-Rust: GitHub העביר את זמן הריצה של סוכן Copilot ל-832,378 שורות של Rust, בעיקר על ידי מפתח אחד שמנהל סוכנים. לאחר מכן סוכנים כתבו מחדש גם את בודק הסוגים של TypeScript, ואת זה, tsrs, אתם יכולים לנסות היום. סטיבן טוב העביר את המנוע מאחורי Copilot CLI, את אפליקציית Copilot ואת ה-SDK מ-TypeScript בקשת משיכה אחת בכל פעם במשך כ-14.5 שבועות (12 במאי עד 21 באוגוסט, 2026), עם 468,689 שורות של בדיקות Rust כרשת ביטחון; GitHub מעריך שהמשימה הייתה דורשת "לצוות שלם של מפתחים שנה או שנתיים" לפני סוכנים. נתוני המהירות של GitHub מגיעים ממבחן הביצועים של SDK ב-C# עם קריאות מודל שנמחקו: סיבוב אחד עבר מ-5.25 שניות ל-1.33 שניות, פי 4 מהר יותר כברירת מחדל, ו-18x (292 אלפיות שנייה) הוא רק כאשר המנוע טעון בתהליך, שהוא opt-in; גיטהאב אומר ששינויים אחרים נחתו באותם חודשים, אז קחו אותם "עם קצת מלח". tsrs, פורט ה-Rust של מהדר TypeScript שנכתב על ידי סוכנים לפי יוצרו מקס שוונק וכעת מודגם ב-Oxc על ידי Cloudflare ו-VoidZero, הוא "מהיר עד פי 8" מ-TypeScript 7.0 עם כ-70% פחות זיכרון במבחני הביצועים המוקדמים של Cloudflare באותו מספר של הליכי עבודה, והנתונים של המתחזקים עצמם לכל פרויקט משתנים מאוד. זהו ניסיוני: גרסה 0.18.0 של npm (פורסמה ב-19 באוקטובר) אינה כוללת את התיקון לבעיה #725, שבה שגיאות יכולות להופיע או להיעלם בין ריצות (תוקנה ב-24 באוקטובר), אז השוו את ספירת השגיאות שלה לבדיקה הרגילה שלכם; כל מספר כאן הוא של היוצרים, ולא מדדתי אף אחד מהכתיבות מחדש. חותמות זמן 0:00 - Copilot כתב מחדש את המנוע שלו ב-Rust 0:22 - היכן שהסוכן שלך מחכה 0:45 - מפתח אחד, הרבה סוכנים 1:26 - מה GitHub מדד: פי 4 ברירת מחדל, פי 18 הצטרפות 2:03 - tsrs: בודק TypeScript הבא בתור 2:33 - מה Cloudflare אומר: עד פי 8 2:59 - נסה tsrs במאגר שלך 3:24 - בדיקת מציאות: באגים חדשים 3:46 - פסק דין: נסה tsrs if, דלג על if קישורים ומשאבים - GitHub, העברת זמן הריצה של Copilot ל-Rust: github.blog - Cloudflare, הכרזה על tsrs: blog.cloudflare.com - מקס שוונק, איך tsrs נבנה: building.owner.com - מאגר tsrs וקובץ README: oxc-project/tsrs - תוצאות בדיקת benchmark של tsrs: github.com/oxc-project/tsrs/blob/main/bench/RESUL… - גיליון tsrs #725: tsrs#725 - tsrs ב-npm: registry.npmjs.org - הכרזה על TypeScript 7.0: devblogs.microsoft.com - צילום: סטיבן טוב (דמות בפרופיל GitHub, תמונת המחבר בפוסט המצוטט), רישיון לא ידוע, github.blog עוד על כך ערוץ - 2,000 סוכני בינה מלאכותית כתבו מחדש סוכן קידוד ב-Rust: youtu.be - קלוד כתב מחדש מיליון שורות של Bun ב-11 ימים: youtu.be - Rust קיצץ את המהדר של React מ-14.3 שניות ל-0.81 שניות: youtu.be תגיות #GitHubCopilot #Rust #TypeScript #AICodingAgents [ja] CopilotのエンジンがRustで書き換えられた:83万2000行のコード Copilotは独自のエンジンをRustで書き直しました。GitHubはCopilotエージェントランタイムを832,378行のRustコードに移植しましたが、そのほとんどは一人の開発者がエージェントを操ることで実現しました。その後、エージェントはTypeScriptの型チェッカーも書き直し、その「tsrs」は現在利用可能です。 Stephen Toub氏は、Copilot CLI、Copilotアプリ、SDKのエンジンをTypeScriptから移植しました。移植作業は、約14.5週間(2026年5月12日から8月21日)にわたり、プルリクエストを一つずつ積み重ねて行われました。安全策として468,689行のRustテストが用いられました。GitHubは、エージェントが登場する前であれば、この作業には「開発者チーム全体で1~2年」かかっただろうと推定しています。 GitHub の速度数値は、モデル呼び出しをスタブ化した C# SDK ベンチマークから得られたものです。1 回の処理は 5.25 秒から 1.33 秒に短縮され、デフォルトでは 4 倍高速化されています。18 倍 (292 ms) は、オプトインのプロセス内エンジンロード時のみの高速化です。GitHub は、同じ月に他の変更も行われたため、「多少割り引いて考える」必要があると述べています。tsrs は、作成者の Max Schwenk 氏によるとエージェントによって書かれた TypeScript コンパイラの Rust ポートで、現在は Cloudflare と VoidZero によって Oxc でインキュベートされていますが、Cloudflare の初期ベンチマークでは、同じ数のワーカー スレッドで TypeScript 7.0 より最大 8 倍高速で、メモリ使用量は約 70% 少なく、メンテナーのプロジェクトごとの数値は大きく異なります。これは実験的な機能です。npmリリース0.18.0(10月19日公開)には、実行ごとにエラーが発生したり消えたりする問題(10月24日修正済み)の修正は含まれていません。そのため、エラー数を通常のチェック結果と比較してください。ここに記載されている数値はすべて開発者によるものであり、私はどちらの書き換えも計測していません。 タイムスタンプ 0:00 - Copilotが独自のエンジンをRustで書き直しました 0:22 - エージェントの待機場所 0:45 - 1人の開発者、多数のエージェント 1:26 - GitHubの測定結果:デフォルト4倍、オプトイン18倍 2:03 - tsrs:TypeScriptチェッカーが次期バージョン 2:33 - Cloudflareの見解:最大8倍 2:59 - リポジトリでtsrsを試してみましょう 3:24 - 現実検証:新たなバグ 3:46 - 結論:tsrsを試すべき場合、試すべきでない場合 リンクとリソース - GitHub、CopilotランタイムのRustへの移行:github.blog - Cloudflare、tsrsの発表: blog.cloudflare.com - Max Schwenk氏によるtsrsの構築方法:building.owner.com - tsrsリポジトリとREADME:oxc-project/tsrs - tsrsベンチマーク結果:github.com/oxc-project/tsrs/blob/main/bench/RESUL… - tsrsイシュー#725:tsrs#725 - npm上のtsrs:registry.npmjs.org - TypeScript 7.0の発表:devblogs.microsoft.com - 写真:Stephen Toub氏(GitHubプロフィールのアバター、引用記事の著者写真)、ライセンス不明github.blog このチャンネルのその他の動画 - 2,000個のAIエージェントがコーディングエージェントをRustで書き直しました:youtu.be - Claudeが11日間で100万行のBunを書き直しました:youtu.be - RustでReactコンパイラの実行時間を14.3秒から0.81秒に短縮しました:youtu.be タグ #GitHubCopilot #Rust #TypeScript #AICodingAgents [ko] Copilot이 엔진을 Rust로 재작성하다: 832,000줄의 코드 Copilot은 자체 엔진을 Rust로 재작성했습니다. GitHub는 Copilot 에이전트 런타임을 832,378줄의 Rust 코드로 포팅했는데, 대부분 한 명의 개발자가 에이전트를 관리하며 진행했습니다. 에이전트들은 TypeScript 타입 체커도 Rust로 재작성했고, 이 체커는 오늘 바로 사용해 볼 수 있습니다. Stephen Toub는 Copilot CLI, Copilot 앱, SDK의 엔진을 TypeScript에서 Rust로 포팅하는 작업을 약 14.5주(2026년 5월 12일~8월 21일)에 걸쳐 풀 리퀘스트를 하나씩 제출하며 진행했고, 468,689줄의 Rust 테스트 코드를 안전망으로 활용했습니다. GitHub는 에이전트가 없었다면 이 작업에 "개발자 팀 전체가 1~2년은 걸렸을 것"이라고 추정합니다. GitHub의 속도 수치는 모델 호출이 스텁 처리된 C# SDK 벤치마크에서 나온 것입니다. 한 번의 턴 처리 시간이 5.25초에서 1.33초로 단축되어 기본적으로 4배 빨라졌으며, 18배(292ms) 단축은 엔진을 인프로세스로 로드했을 때만 나타나는 결과입니다. 인프로세스 로드는 선택 사항입니다. GitHub는 같은 달에 다른 변경 사항도 적용되었으므로 이 수치는 "어느 정도 참고용"이라고 밝혔습니다. Max Schwenk가 개발한 TypeScript 컴파일러의 Rust 포트인 tsrs는 현재 Cloudflare와 VoidZero가 Oxc에서 인큐베이팅하고 있으며, Cloudflare의 초기 벤치마크에서 동일한 워커 스레드 수에서 TypeScript 7.0보다 "최대 8배" 빠르고 메모리 사용량은 약 70% 적었습니다. 프로젝트별 성능 수치는 개발자마다 크게 다릅니다. 이 기능은 실험적입니다. npm 릴리스 0.18.0(10월 19일 게시)에는 실행 간 오류가 발생하거나 사라지는 문제 #725에 대한 수정 사항(10월 24일 수정됨)이 포함되어 있지 않으므로, 평소 검사 방식과 오류 발생 횟수를 비교해 보시기 바랍니다. 여기에 제시된 모든 수치는 개발자가 제공한 것이며, 저는 재작성 과정에서 직접 측정하지 않았습니다. 타임스탬프 0:00 - Copilot, 자체 엔진을 Rust로 재작성 0:22 - 에이전트 대기 위치 0:45 - 개발자 한 명, 에이전트 수 1:26 - GitHub 측정 결과: 기본 4배, 선택 사용 시 18배 2:03 - tsrs: TypeScript 검사기 출시 예정 2:33 - Cloudflare 발표: 최대 8배 2:59 - 리포지토리에서 tsrs 사용해 보기 3:24 - 현실 점검: 새로운 버그 발견 3:46 - 결론: tsrs 사용 권장, 권장하지 않음 링크 및 자료 - GitHub, Copilot 런타임을 Rust로 마이그레이션: github.blog - Cloudflare, tsrs 발표: blog.cloudflare.com - Max Schwenk, tsrs 개발 과정: building.owner.com - tsrs 저장소 및 README: oxc-project/tsrs - tsrs 벤치마크 결과: github.com/oxc-project/tsrs/blob/main/bench/RESUL… - tsrs 이슈 #725: tsrs#725 - npm의 tsrs: registry.npmjs.org - TypeScript 7.0 발표: devblogs.microsoft.com - 사진: Stephen Toub (GitHub 프로필 아바타, 인용된 게시물의 작성자 사진), 라이선스 미상 github.blog 이 채널의 다른 영상들 - 2,000개의 AI 에이전트가 Rust로 코딩 에이전트를 재작성했습니다: youtu.be - Claude가 11일 만에 Bun의 백만 줄 코드를 재작성했습니다: youtu.be - Rust로 React 컴파일러 실행 시간을 14.3초에서 0.81초로 단축했습니다: youtu.be 태그 #GitHubCopilot #Rust #TypeScript #AICodingAgents [ml] Copilot സ്വന്തം എൻജിൻ Rust-ൽ പുനർനിർമ്മിച്ചു: 832,000 വരികൾ കോപൈലറ്റ് റസ്റ്റിൽ സ്വന്തം എഞ്ചിൻ വീണ്ടും എഴുതി: GitHub കോപൈലറ്റ് ഏജന്റ് റൺടൈം 832,378 ലൈനുകളിലേക്ക് റസ്റ്റിലേക്ക് പോർട്ട് ചെയ്തു, കൂടുതലും ഒരു ഡെവലപ്പർ സ്റ്റിയറിംഗ് ഏജന്റുകൾ. പിന്നീട് ഏജന്റുമാർ ടൈപ്പ്സ്ക്രിപ്റ്റ് ടൈപ്പ് ചെക്കറും വീണ്ടും എഴുതി, അത്, ടിഎസ്ആർഎസ്, നിങ്ങൾക്ക് ഇന്ന് തന്നെ ശ്രമിക്കാം. ഏകദേശം 14.5 ആഴ്ചകൾ (മെയ് 12 മുതൽ ഓഗസ്റ്റ് 21, 2026 വരെ) ടൈപ്പ്സ്ക്രിപ്റ്റ് വൺ പുൾ റിക്വസ്റ്റിൽ നിന്ന് കോപൈലറ്റ് സിഎൽഐ, കോപൈലറ്റ് ആപ്പ്, എസ്ഡികെ എന്നിവയ്ക്ക് പിന്നിൽ എഞ്ചിൻ സ്റ്റീഫൻ ടൗബ് പോർട്ട് ചെയ്തു, സുരക്ഷാ വലയായി 468,689 ലൈൻ റസ്റ്റ് ടെസ്റ്റുകൾ നടത്തി; ഏജന്റുമാർക്ക് മുമ്പ് "ഒരു വർഷം അല്ലെങ്കിൽ രണ്ട് വർഷം മുഴുവൻ ഡെവലപ്പർമാരുടെ ഒരു ടീം" ഈ ജോലിക്ക് എടുക്കുമായിരുന്നുവെന്ന് GitHub കണക്കാക്കുന്നു. GitHub-ന്റെ സ്പീഡ് നമ്പറുകൾ അതിന്റെ C# SDK ബെഞ്ച്മാർക്കിൽ നിന്നാണ് വരുന്നത്, മോഡൽ കോളുകൾ സ്റ്റബ് ചെയ്‌തിരിക്കുന്നു: ഒരു ടേൺ 5.25 സെക്കൻഡിൽ നിന്ന് 1.33 സെക്കൻഡിലേക്ക് പോയി, സ്ഥിരസ്ഥിതിയായി 4 മടങ്ങ് വേഗത, 18x (292 ms) എഞ്ചിൻ പ്രോസസ്സിൽ ലോഡ് ചെയ്‌തിരിക്കുമ്പോൾ മാത്രമേ ഉള്ളൂ, അത് ഓപ്റ്റ്-ഇൻ ആണ്; മറ്റ് മാറ്റങ്ങൾ അതേ മാസങ്ങളിൽ വന്നതായി GitHub പറയുന്നു, അതിനാൽ അവയെ "കുറച്ച് തരികൾ ഉപ്പ് ഉപയോഗിച്ച്" എടുക്കുക. ടിഎസ്ആർഎസ്, ടൈപ്പ്സ്ക്രിപ്റ്റ് കംപൈലറിന്റെ റസ്റ്റ് പോർട്ട്, അതിന്റെ സ്രഷ്ടാവായ മാക്സ് ഷ്വെങ്ക് പ്രകാരം ഏജന്റുമാർ എഴുതിയതും ഇപ്പോൾ ക്ലൗഡ്ഫ്ലെയറും വോയിഡ്സീറോയും ഓക്‌സിയിൽ ഇൻകുബേറ്റ് ചെയ്‌തതുമാണ്, ടൈപ്പ്സ്ക്രിപ്റ്റ് 7.0 നേക്കാൾ "8 മടങ്ങ് വരെ വേഗതയുള്ളതാണ്", അതേ എണ്ണം വർക്കർ ത്രെഡുകളിൽ ക്ലൗഡ്ഫ്ലെയറിന്റെ ആദ്യകാല ബെഞ്ച്മാർക്കുകളിൽ ഏകദേശം 70% കുറവ് മെമ്മറിയുണ്ട്, കൂടാതെ പരിപാലകരുടെ സ്വന്തം ഓരോ പ്രോജക്റ്റിനും കണക്കുകൾ വ്യാപകമായി വ്യത്യാസപ്പെടുന്നു. ഇത് പരീക്ഷണാത്മകമാണ്: npm റിലീസ് 0.18.0 (ഒക്ടോബർ 19 ന് പ്രസിദ്ധീകരിച്ചത്) ലക്കം #725 നുള്ള പരിഹാരം ഉൾപ്പെടുത്തിയിട്ടില്ല, അവിടെ പിശകുകൾ റണ്ണുകൾക്കിടയിൽ പ്രത്യക്ഷപ്പെടുകയോ അപ്രത്യക്ഷമാകുകയോ ചെയ്യാം (ഒക്ടോബർ 24 ന് പരിഹരിച്ചു), അതിനാൽ നിങ്ങളുടെ പതിവ് പരിശോധനയുമായി അതിന്റെ പിശക് എണ്ണങ്ങൾ താരതമ്യം ചെയ്യുക; ഇവിടെയുള്ള ഓരോ സംഖ്യയും നിർമ്മാതാക്കളുടേതാണ്, ഞാൻ രണ്ടും വീണ്ടും എഴുതിയതായി കണക്കാക്കിയിട്ടില്ല. TIMESTAMPS 0:00 - കോപൈലറ്റ് റസ്റ്റിൽ സ്വന്തം എഞ്ചിൻ വീണ്ടും എഴുതി 0:22 - നിങ്ങളുടെ ഏജന്റ് കാത്തിരിക്കുന്നിടത്ത് 0:45 - ഒരു ഡെവലപ്പർ, ധാരാളം ഏജന്റുമാർ 1:26 - GitHub അളന്നത്: 4x ഡിഫോൾട്ട്, 18x ഓപ്റ്റ്-ഇൻ 2:03 - tsrs: അടുത്തത് ടൈപ്പ്സ്ക്രിപ്റ്റ് ചെക്കറാണ് 2:33 - ക്ലൗഡ്ഫ്ലെയർ പറയുന്നത്: 8x വരെ 2:59 - നിങ്ങളുടെ റിപ്പോയിൽ tsrs പരീക്ഷിക്കുക 3:24 - റിയാലിറ്റി പരിശോധന: പുതിയ ബഗുകൾ 3:46 - വിധി: tsrs if പരീക്ഷിക്കുക, is ഒഴിവാക്കുക ലിങ്കുകളും റിസോഴ്‌സുകളും - GitHub, കോപൈലറ്റ് റൺടൈം റസ്റ്റിലേക്ക് മൈഗ്രേറ്റ് ചെയ്യുന്നു: github.blog - ക്ലൗഡ്ഫ്ലെയർ, ടിഎസ്ആർഎസ് പ്രഖ്യാപനം: blog.cloudflare.com - മാക്സ് ഷ്വെങ്ക്, tsrs എങ്ങനെയാണ് നിർമ്മിച്ചത്: building.owner.com - tsrs റിപ്പോസിറ്ററിയും README-യും: oxc-project/tsrs - tsrs ബെഞ്ച്മാർക്ക് ഫലങ്ങൾ: github.com/oxc-project/tsrs/blob/main/bench/RESUL… - tsrs ലക്കം #725: tsrs#725 - npm-ലെ tsrs: registry.npmjs.org - ടൈപ്പ്സ്ക്രിപ്റ്റ് 7.0 പ്രഖ്യാപനം: devblogs.microsoft.com - ഫോട്ടോ: സ്റ്റീഫൻ ടൗബ് (GitHub പ്രൊഫൈൽ അവതാർ, ഉദ്ധരിച്ച പോസ്റ്റിലെ രചയിതാവിന്റെ ഫോട്ടോ), ലൈസൻസ് അജ്ഞാതം, github.blog ഈ ചാനലിൽ കൂടുതൽ - 2,000 AI ഏജന്റുമാർ റസ്റ്റിൽ ഒരു കോഡിംഗ് ഏജന്റിനെ പുനരെഴുതി: youtu.be - ക്ലോഡ് 11 ദിവസത്തിനുള്ളിൽ 1 ദശലക്ഷം ബൺ വരികൾ പുനരെഴുതി: youtu.be - റസ്റ്റ് കട്ട് റിയാക്റ്റിന്റെ കംപൈലർ 14.3 സെക്കൻഡിൽ നിന്ന് 0.81 സെക്കൻഡിലേക്ക്: youtu.be ടാഗുകൾ #GitHubCopilot #Rust #TypeScript #AICodingAgents [nl-NL] Copilot herschreef eigen engine in Rust: 832.000 regels code Copilot heeft zijn eigen engine herschreven in Rust: GitHub heeft de runtime van de Copilot-agent geporteerd naar 832.378 regels Rust-code, grotendeels door één ontwikkelaar die de agents aanstuurde. Vervolgens hebben de agents ook de TypeScript-typechecker herschreven, en die kun je vandaag nog uitproberen. Stephen Toub heeft de engine achter de Copilot CLI, de Copilot-app en de SDK geporteerd van TypeScript, één pull request per keer, gedurende ongeveer 14,5 weken (12 mei tot 21 augustus 2026), met 468.689 regels Rust-tests als vangnet; GitHub schat dat het werk "een heel team van ontwikkelaars een jaar of twee" zou hebben gekost voordat de agents er waren. De snelheidscijfers van GitHub zijn afkomstig van hun C# SDK-benchmark met gesimuleerde modelaanroepen: één beurt ging van 5,25 s naar 1,33 s, standaard 4x sneller, en de 18x (292 ms) is alleen met de engine in-process geladen, wat optioneel is; GitHub zegt dat er in dezelfde maanden ook andere wijzigingen zijn doorgevoerd, dus neem ze "met een korreltje zout". tsrs, de Rust-port van de TypeScript-compiler geschreven door agents volgens de maker Max Schwenk en nu geïncubeerd in Oxc door Cloudflare en VoidZero, is "tot 8x sneller" dan TypeScript 7.0 met ~70% minder geheugen in de eerste benchmarks van Cloudflare bij hetzelfde aantal worker threads, en de eigen cijfers per project van de beheerders lopen sterk uiteen. Het is experimenteel: npm release 0.18.0 (gepubliceerd op 19 oktober) bevat niet de oplossing voor probleem #725, waarbij fouten tussen uitvoeringen kunnen verschijnen of verdwijnen (opgelost op 24 oktober). Vergelijk daarom het aantal fouten met uw gebruikelijke controle; alle getallen hier zijn afkomstig van de makers zelf, en ik heb geen van beide herschrijvingen gemeten. TIJDSTEMPELS 0:00 - Copilot heeft zijn eigen engine herschreven in Rust 0:22 - Waar je agent wacht 0:45 - Eén ontwikkelaar, veel agents 1:26 - Wat GitHub heeft gemeten: 4x standaard, 18x opt-in 2:03 - tsrs: de TypeScript-checker is de volgende stap 2:33 - Wat Cloudflare zegt: tot 8x 2:59 - Probeer tsrs op je repository 3:24 - Realiteitscheck: nieuwe bugs 3:46 - Oordeel: probeer tsrs als, sla over als LINKS & BRONNEN - GitHub, De Copilot-runtime migreren naar Rust: github.blog - Cloudflare, aankondiging van tsrs: blog.cloudflare.com - Max Schwenk, hoe tsrs is gebouwd: building.owner.com - tsrs-repository en README: oxc-project/tsrs - tsrs-benchmarkresultaten: github.com/oxc-project/tsrs/blob/main/bench/RESUL… - tsrs-probleem #725: tsrs#725 - tsrs op npm: registry.npmjs.org - Aankondiging TypeScript 7.0: devblogs.microsoft.com - Foto: Stephen Toub (GitHub-profielavatar, auteursfoto in het genoemde bericht), licentie onbekend github.blog MEER OP DIT KANAAL - 2000 AI-agenten herschreven een codeeragent in Rust: youtu.be - Claude herschreef 1 miljoen regels Bun in 11 dagen: youtu.be - Rust verkortte de compilertijd van React van 14,3s naar 0,81s: youtu.be TAGS #GitHubCopilot #Rust #TypeScript #AICodingAgents [pa] Copilot ਨੇ ਆਪਣਾ ਇੰਜਣ Rust ਵਿੱਚ ਮੁੜ ਲਿਖਿਆ: 832,000 ਲਾਈਨਾਂ ਕੋਪਾਇਲਟ ਨੇ ਰਸਟ ਵਿੱਚ ਆਪਣਾ ਇੰਜਣ ਦੁਬਾਰਾ ਲਿਖਿਆ: GitHub ਨੇ Copilot ਏਜੰਟ ਰਨਟਾਈਮ ਨੂੰ Rust ਦੀਆਂ 832,378 ਲਾਈਨਾਂ 'ਤੇ ਪੋਰਟ ਕੀਤਾ, ਜ਼ਿਆਦਾਤਰ ਇੱਕ ਡਿਵੈਲਪਰ ਸਟੀਅਰਿੰਗ ਏਜੰਟ ਦੁਆਰਾ। ਫਿਰ ਏਜੰਟਾਂ ਨੇ TypeScript ਟਾਈਪ ਚੈਕਰ ਨੂੰ ਵੀ ਦੁਬਾਰਾ ਲਿਖਿਆ, ਅਤੇ ਉਹ, tsrs, ਤੁਸੀਂ ਅੱਜ ਹੀ ਕੋਸ਼ਿਸ਼ ਕਰ ਸਕਦੇ ਹੋ। ਸਟੀਫਨ ਟੌਬ ਨੇ Copilot CLI, Copilot ਐਪ ਅਤੇ SDK ਦੇ ਪਿੱਛੇ ਇੰਜਣ ਨੂੰ TypeScript ਤੋਂ ਇੱਕ ਪੁੱਲ ਬੇਨਤੀ ਦੇ ਪਿੱਛੇ ਲਗਭਗ 14.5 ਹਫ਼ਤਿਆਂ (12 ਮਈ ਤੋਂ 21 ਅਗਸਤ, 2026) ਵਿੱਚ ਪੋਰਟ ਕੀਤਾ, ਸੁਰੱਖਿਆ ਜਾਲ ਦੇ ਤੌਰ 'ਤੇ Rust ਟੈਸਟਾਂ ਦੀਆਂ 468,689 ਲਾਈਨਾਂ ਦੇ ਨਾਲ; GitHub ਦਾ ਅੰਦਾਜ਼ਾ ਹੈ ਕਿ ਏਜੰਟਾਂ ਤੋਂ ਪਹਿਲਾਂ ਕੰਮ ਵਿੱਚ "ਡਿਵੈਲਪਰਾਂ ਦੀ ਇੱਕ ਪੂਰੀ ਟੀਮ ਨੂੰ ਇੱਕ ਜਾਂ ਦੋ ਸਾਲ" ਲੱਗ ਗਏ ਹੋਣਗੇ। GitHub ਦੇ ਸਪੀਡ ਨੰਬਰ ਇਸਦੇ C# SDK ਬੈਂਚਮਾਰਕ ਤੋਂ ਆਉਂਦੇ ਹਨ ਜਿਸ ਵਿੱਚ ਮਾਡਲ ਕਾਲਾਂ ਸਟੱਬਡ ਹੁੰਦੀਆਂ ਹਨ: ਇੱਕ ਵਾਰੀ 5.25 ਸਕਿੰਟ ਤੋਂ 1.33 ਸਕਿੰਟ ਤੱਕ ਗਈ, ਡਿਫੌਲਟ ਤੌਰ 'ਤੇ 4 ਗੁਣਾ ਤੇਜ਼, ਅਤੇ 18x (292 ms) ਸਿਰਫ ਇੰਜਣ ਲੋਡ ਇਨ-ਪ੍ਰੋਸੈਸ ਦੇ ਨਾਲ ਹੈ, ਜੋ ਕਿ ਔਪਟ-ਇਨ ਹੈ; GitHub ਕਹਿੰਦਾ ਹੈ ਕਿ ਹੋਰ ਬਦਲਾਅ ਉਸੇ ਮਹੀਨਿਆਂ ਵਿੱਚ ਆਏ, ਇਸ ਲਈ ਉਹਨਾਂ ਨੂੰ "ਕੁਝ ਲੂਣ ਦੇ ਦਾਣਿਆਂ ਨਾਲ" ਲਓ। tsrs, ਟਾਈਪਸਕ੍ਰਿਪਟ ਕੰਪਾਈਲਰ ਦਾ ਰਸਟ ਪੋਰਟ ਜੋ ਇਸਦੇ ਸਿਰਜਣਹਾਰ ਮੈਕਸ ਸ਼ਵੇਂਕ ਦੇ ਅਨੁਸਾਰ ਏਜੰਟਾਂ ਦੁਆਰਾ ਲਿਖਿਆ ਗਿਆ ਹੈ ਅਤੇ ਹੁਣ ਕਲਾਉਡਫਲੇਅਰ ਅਤੇ ਵੋਇਡਜ਼ੀਰੋ ਦੁਆਰਾ Oxc ਵਿੱਚ ਇਨਕਿਊਬੇਟ ਕੀਤਾ ਗਿਆ ਹੈ, ਟਾਈਪਸਕ੍ਰਿਪਟ 7.0 ਨਾਲੋਂ "8 ਗੁਣਾ ਤੇਜ਼" ਹੈ ਜਿਸ ਵਿੱਚ ਕਲਾਉਡਫਲੇਅਰ ਦੇ ਸ਼ੁਰੂਆਤੀ ਬੈਂਚਮਾਰਕਾਂ ਵਿੱਚ ਵਰਕਰ ਥ੍ਰੈੱਡਾਂ ਦੀ ਇੱਕੋ ਸੰਖਿਆ 'ਤੇ ~70% ਘੱਟ ਮੈਮੋਰੀ ਹੈ, ਅਤੇ ਰੱਖ-ਰਖਾਅ ਕਰਨ ਵਾਲਿਆਂ ਦੇ ਆਪਣੇ ਪ੍ਰਤੀ-ਪ੍ਰੋਜੈਕਟ ਅੰਕੜੇ ਵਿਆਪਕ ਤੌਰ 'ਤੇ ਵੱਖ-ਵੱਖ ਹੁੰਦੇ ਹਨ। ਇਹ ਪ੍ਰਯੋਗਾਤਮਕ ਹੈ: npm ਰੀਲੀਜ਼ 0.18.0 (ਪ੍ਰਕਾਸ਼ਿਤ 19 ਅਕਤੂਬਰ) ਵਿੱਚ ਮੁੱਦਾ #725 ਲਈ ਫਿਕਸ ਸ਼ਾਮਲ ਨਹੀਂ ਹੈ, ਜਿੱਥੇ ਗਲਤੀਆਂ ਰਨ ਦੇ ਵਿਚਕਾਰ ਦਿਖਾਈ ਦੇ ਸਕਦੀਆਂ ਹਨ ਜਾਂ ਅਲੋਪ ਹੋ ਸਕਦੀਆਂ ਹਨ (24 ਅਕਤੂਬਰ ਨੂੰ ਸਥਿਰ), ਇਸ ਲਈ ਇਸਦੀ ਗਲਤੀ ਗਿਣਤੀ ਦੀ ਤੁਲਨਾ ਆਪਣੀ ਆਮ ਜਾਂਚ ਨਾਲ ਕਰੋ; ਇੱਥੇ ਹਰ ਨੰਬਰ ਨਿਰਮਾਤਾਵਾਂ ਦਾ ਆਪਣਾ ਹੈ, ਅਤੇ ਮੈਂ ਦੁਬਾਰਾ ਲਿਖਣ ਨੂੰ ਨਹੀਂ ਮਾਪਿਆ। TIMESTAMPS 0:00 - Rust ਵਿੱਚ ਕੋਪਾਇਲਟ ਨੇ ਆਪਣਾ ਇੰਜਣ ਦੁਬਾਰਾ ਲਿਖਿਆ 0:22 - ਜਿੱਥੇ ਤੁਹਾਡਾ ਏਜੰਟ ਉਡੀਕ ਕਰਦਾ ਹੈ 0:45 - ਇੱਕ ਡਿਵੈਲਪਰ, ਬਹੁਤ ਸਾਰੇ ਏਜੰਟ 1:26 - GitHub ਨੇ ਕੀ ਮਾਪਿਆ: 4x ਡਿਫੌਲਟ, 18x ਔਪਟ-ਇਨ 2:03 - tsrs: TypeScript ਚੈਕਰ ਅੱਗੇ ਹੈ 2:33 - Cloudflare ਕੀ ਕਹਿੰਦਾ ਹੈ: 8x ਤੱਕ 2:59 - ਆਪਣੇ ਰੈਪੋ 'ਤੇ tsrs ਅਜ਼ਮਾਓ 3:24 - ਅਸਲੀਅਤ ਜਾਂਚ: ਨਵੇਂ ਬੱਗ 3:46 - ਫੈਸਲਾ: tsrs ਅਜ਼ਮਾਓ ਜੇਕਰ, ਛੱਡੋ ਜੇਕਰ ਲਿੰਕ ਅਤੇ ਸਰੋਤ - GitHub, Copilot ਰਨਟਾਈਮ ਨੂੰ Rust ਵਿੱਚ ਮਾਈਗ੍ਰੇਟ ਕਰਨਾ: github.blog - Cloudflare, tsrs ਘੋਸ਼ਣਾ: blog.cloudflare.com - ਅਧਿਕਤਮ ਸ਼ਵੇਂਕ, tsrs ਕਿਵੇਂ ਬਣਾਇਆ ਗਿਆ ਸੀ: building.owner.com - tsrs ਰਿਪੋਜ਼ਟਰੀ ਅਤੇ README: oxc-project/tsrs - tsrs ਬੈਂਚਮਾਰਕ ਨਤੀਜੇ: github.com/oxc-project/tsrs/blob/main/bench/RESUL… - tsrs ਮੁੱਦਾ #725: tsrs#725 - npm 'ਤੇ tsrs: registry.npmjs.org - TypeScript 7.0 ਘੋਸ਼ਣਾ: devblogs.microsoft.com - ਫੋਟੋ: ਸਟੀਫਨ ਟੌਬ (GitHub ਪ੍ਰੋਫਾਈਲ ਅਵਤਾਰ, ਹਵਾਲਾ ਦਿੱਤੀ ਪੋਸਟ 'ਤੇ ਲੇਖਕ ਦੀ ਫੋਟੋ), ਲਾਇਸੈਂਸ ਅਣਜਾਣ, github.blog ਇਸ ਬਾਰੇ ਹੋਰ

    6 likes · 1,034 views
Trending awards, every completed day and week
Gold
01st place finishes
Silver
02nd place finishes
Bronze
03rd place finishes
Awarded repositories
0Owned by oxc-project now

No trending awards yet

None of the repositories oxc-project owns has finished in the top three of a completed trending day or week, by stars, forks or PR authors. See who is trending now.

A repository earns an award for finishing first, second or third in a completed trending day or week, ranked by new stars, new forks or pull request authors. Awards follow a repository through renames and transfers and count toward its current owner. Weeks run Monday to Sunday, UTC.