import {
For,
Show,
createMemo,
createSignal,
onCleanup,
onMount,
} from "solid-js";
import { useMail } from "./mail";
import { Item } from "./Item";
const ROW = 56;
const PAGE = 24;
export function MailList() {
const { items, query, load } =
useMail();
const [focus, setFocus] =
createSignal(0);
const [top, setTop] =
createSignal(0);
const visible = createMemo(() => {
const q = query().toLowerCase();
return items()
.filter((m) =>
m.subject
.toLowerCase()
.includes(q),
)
.slice(top(), top() + PAGE);
});
const onKey = (e: KeyboardEvent) => {
if (e.key === "ArrowDown") {
setFocus((i) =>
Math.min(i + 1, PAGE - 1),
);
} else if (e.key === "ArrowUp") {
setFocus((i) =>
Math.max(i - 1, 0),
);
} else if (e.key === "Enter") {
open(visible()[focus()].id);
}
};
onMount(() => {
load();
window.addEventListener(
"keydown",
onKey,
);
onCleanup(() =>
window.removeEventListener(
"keydown",
onKey,
),
);
});
return (
<Show
when={visible().length}
fallback={<Empty />}
>
<For each={visible()}>
{(m, i) => (
<Item
mail={m}
active={i() === focus()}
onOpen={open}
/>
)}
</For>
</Show>
);
}
import type { Email } from "~/types";
interface MailListItemProps {
email: Email;
isSelected: boolean;
onOpen: (id: string) => void;
}
export function MailListItem(props: MailListItemProps) {
return (
<div
role="listitem"
tabindex={0}
onClick={() => props.onOpen(props.email.id)}
onKeyDown={(ev) => ev.key === "Enter" && props.onOpen(props.email.id)}
class="mail-item"
data-selected={props.isSelected ? "true" : undefined}
aria-selected={props.isSelected ? "true" : undefined}
>
<div>
<div class="mail-item-subject truncate">{props.email.subject}</div>
<div class="mail-item-snippet truncate">{props.email.snippet}</div>
</div>
<time
class="text-xs muted"
datetime={props.email.date}
title={new Date(props.email.date).toLocaleString()}
>
{new Date(props.email.date).toLocaleDateString(undefined, {
month: "short",
day: "numeric",
})}
</time>
</div>
);
- 建立新的
MailListItem 處理個別郵件列表項目渲染的元件 - 從
MailList 提取郵件項目 JSX 與邏輯至新的MailListItem 元件中 - 更新
MailList 以使用新的MailListItem 元件中 - 建置專案以驗證變更後的編譯正確性
- 測試應用程式以確保功能運作正常
- 建立了一個可重複使用的元件,用於渲染個別郵件列表項目
- 接受
email ,isSelected 以及onSelect 屬性 (props) - 維持所有輔助功能 (ARIA 角色、鍵盤導覽)
- 保留既有的樣式與互動行為
- 透過移除內聯的郵件項目渲染邏輯來簡化程式碼
- 現在使用
MailListItem 元件,並透過簡潔的方式傳遞 props - 降低元件複雜度並提升可讀性
- ✅ 建置成功
- ✅ 所有功能運作正常 (篩選、選取、導覽)
- ✅ 保留鍵盤輔助功能 (Enter 鍵導覽)
- ✅ 視覺選取狀態運作正常
MailList.tsx 中的每一列提取為獨立的 MailListItem 元件。保留選取狀態、鍵盤導覽以及現有的虛擬化行為。已對應 MailList 版面配置
目前的列是內聯渲染的,選取狀態存放在useSelection 中。由於 react-window 的外層元素包裹著列表,我會讓它的列渲染器指向新元件,以保留虛擬化功能。
- 建立
MailListItem.tsx,並為其定義message、selected與onSelect等 props。 - 使用
React.memo包裹該元件,並針對message.id+selected設定比較邏輯。 - 將
useSelection提升至MailList,並將處理函式向下傳遞。
focus(),然後重新執行測試套件。MailListToolbar 元件,並為其新增 Storybook 範例。為您建置的代理程式
將任務交給 AI 代理,它們能自主規劃、進行程式碼變更、執行指令,並不斷迭代直到任務完成。
例如,指派一個基於 CLI 的代理程式在背景處理並修復錯誤,與另一個代理程式互動以使用整合瀏覽器中的即時驗證來實作功能,並委派首頁重新設計工作給一個雲端代理程式,由它開啟 Pull Request 供您的團隊審查。
開始使用 Agentpackage http
import (
"context"
"encoding/json"
"errors"
"io"
"log/slog"
"mime/multipart"
"net/http"
"time"
"golang.org/x/sync/errgroup"
"golang.org/x/sync/semaphore"
"go.opentelemetry.io/otel"
)
type Result[T any] struct {
Name string `json:"name"`
Value T `json:"value,omitempty"`
Error string `json:"error,omitempty"`
}
type Meta struct {
Format string `json:"format"`
Width int `json:"width"`
Height int `json:"height"`
Bytes int64 `json:"bytes"`
}
const (
perRequestTimeout = 30 * time.Second
maxParallel = 8
)
func (s *Server) handleBatch(
w http.ResponseWriter,
r *http.Request,
) {
ctx, span := otel.Tracer("http").
Start(r.Context(), "batch")
defer span.End()
ctx, cancel := context.WithTimeout(
ctx, perRequestTimeout,
)
defer cancel()
r.Body = http.MaxBytesReader(
w, r.Body, s.cfg.MaxBytes,
)
if err := r.ParseMultipartForm(
s.cfg.MaxBytes,
); err != nil {
s.fail(w, http.StatusBadRequest, err)
return
}
files := pickFiles(r.MultipartForm)
if len(files) == 0 {
s.fail(w, http.StatusBadRequest,
errors.New("no files"))
return
}
out := make(
[]Result[Meta], len(files),
)
sem := semaphore.NewWeighted(maxParallel)
g, gctx := errgroup.WithContext(ctx)
for i, fh := range files {
i, fh := i, fh
if err := sem.Acquire(gctx, 1); err != nil {
break
}
g.Go(func() error {
defer sem.Release(1)
out[i] = process(gctx, s, fh)
return nil
})
}
_ = g.Wait()
s.log.LogAttrs(ctx,
slog.LevelInfo, "batch.done",
slog.Int("count", len(out)),
slog.Duration("budget",
perRequestTimeout),
)
w.Header().Set(
"Content-Type", "application/json",
)
_ = json.NewEncoder(w).Encode(out)
}
func process(
ctx context.Context,
s *Server,
fh *multipart.FileHeader,
) Result[Meta] {
res := Result[Meta]{Name: fh.Filename}
f, err := fh.Open()
if err != nil {
res.Error = err.Error()
return res
}
defer f.Close()
data, err := io.ReadAll(
io.LimitReader(f, s.cfg.MaxBytes),
)
if err != nil {
res.Error = err.Error()
return res
}
m, err := s.proc.ExtractCtx(ctx, data)
if err != nil {
res.Error = err.Error()
return res
}
res.Value = Meta{
Format: m.Format,
Width: m.Width,
Height: m.Height,
Bytes: int64(len(data)),
}
return res
}
POST /process/batch 端點。以每請求預算、結構化日誌記錄與 OpenTelemetry 追蹤功能,平行處理最多 8 個檔案。並傳回每個項目的結果。已對應服務版面配置
既有的處理常式位於internal/http 中,而處理器公開了一個同步的 Extract。我會加入一個 ExtractCtx 變體,以便工作池能遵守取消請求,然後使用 errgroup + 加權信號量進行分發。
internal/ 中 grep http.HandleFunc- 使用泛型
Result[Meta]型別在batch.go中加入handleBatch。 - 使用
semaphore.NewWeighted(8)限制併發數,並以errgroup包裹分發作業。 - 將請求包裹在 OTel 追蹤與 30 秒的內容截止期限內。
- 在
server.go中接線路由,並新增表格測試。
go test ./internal/http -run Batch -race-race 檢查下皆通過。處理 64 個影像批次 (平均 1.2MB JPEG) 的產出量:端到端從 184ms 降至 31msk6 指令碼。p99_ms Prometheus 直方圖,並將其連接到既有的 Grafana 儀表板。任何代理,任何模型
使用適合您工作流程的代理工具集。無論是在本機還是雲端,都可以搭配 Copilot 或 Claude、OpenAI 等第三方供應商執行代理。
從各個供應商提供的數十種模型中進行選擇,從快速完成模型到先進推理模型皆有。您也可以匯入自己的 API 金鑰,使用來自任何供應商的任何模型。
所有工作階段,一覽無遺
當多個代理並行執行任務時,仍能保持高效。從單一檢視介面追蹤您所有的代理工作階段,無論它們在哪裡執行。
快速篩選與監控工作階段,或深入查看個別代理互動,無需切換到其他工具或終端機。
您的規則,您的代理
確保代理遵循您的規範與團隊工作流程。定義自訂指令、新增代理技能,或建置針對您專案量身打造的自訂代理。
使用 MCP 伺服器連接外部工具與服務,或安裝代理外掛程式與擴充功能以擴展代理的能力。
核心即為世界級的程式碼編輯器
十多年來,VS Code 一直是數百萬開發者的首選編輯器。AI 驅動的內聯建議、智慧型自動完成以及豐富的編輯體驗,讓您在自己編寫程式碼時同樣強大。
在代理輔助開發與親手編碼之間無縫切換,所有操作皆在同一個編輯器中完成。
開始使用 VS Codeimport numpy as np
import pandas as pd
iris_data = pd.read_csv("iris_dataset.csv")
def describe(species: str) -> pd.Series:
7
subset = data[data["species"] == species]
subset = iris_data[iris_data["species"] == species]
if subset.empty:
raise ValueError(f"{species} missing from sample")
return subset[["petal", "sepal"]].agg(["mean", "std"]).loc["mean"]
def summary():
13
for species in np.sort(data["species"].unique()):
for species in np.sort(iris_data["species"].unique()):
try:
stats = describe(species)
except ValueError:
print(f"{species}: no records")
continue
print(f"{species}: petal={stats['petal']:.2f} sepal={stats['sepal']:.2f}")
if __name__ == "__main__":
summary()
使用擴充功能進行編碼
透過擴充功能與 Model Context Protocol 伺服器中的工具來增強您的代理。或者,自行建置擴充功能,以滿足您團隊的獨特需求。
瀏覽 擴充功能市集 (Extension Marketplace) 中超過 8 萬個擴充功能
以任何語言編碼
VS Code 支援幾乎所有主流程式語言。JavaScript、TypeScript、CSS 與 HTML 等語言開箱即用,其他語言則可在 VS Code 市集中找到對應的擴充功能。

JavaScript
TypeScript
Python
C#
C++
HTML
Java
JSON
PHP
Markdown
Powershell
YAML高度可自訂
自訂您的 VS Code UI 與版面配置,使其符合您的編碼風格。
色彩主題讓您能修改 VS Code 使用者介面的色彩,以配合您的喜好與工作環境。
設定同步 (Settings Sync) 讓您能跨 VS Code 執行個體共享使用者設定。
設定檔 (Profiles) 讓您能建立多組自訂設定,並快速切換或與他人共享。
隨處編碼
無論是連線至雲端、遠端儲存庫,或是透過網頁版 VS Code (vscode.dev),您都能在最有生產力的地方進行編碼。
內建版本控制讓您開箱即用 Git 支援。許多其他原始碼控制提供者也可透過擴充功能使用。
GitHub Codespaces 為任何活動提供雲端開發環境 —— 無論是長期專案,還是處理 Pull Request 等短期任務。
功能豐富的編碼體驗
編輯器不僅僅是輸入程式碼的地方。無論是內建功能還是強大的擴充功能,這裡總有適合每個人的工具。