0
0
Lập trình
Harry Tran
Harry Tran106580903228332612117

Giới thiệu ts-base: Mẫu Thư Viện TypeScript Hiện Đại

Đăng vào 7 tháng trước

• 8 phút đọc

Giới thiệu ts-base

Tám năm trước, tôi đã phát hành thư viện TypeScript mã nguồn mở đầu tiên của mình - Squirrelly - chỉ với hai tệp, package.jsonindex.js. Năm năm sau, tôi đã phát hành Eta với nhiều tính năng hơn như kiểm tra, linting, bundling và CI/CD.

Tôi nghĩ rằng đó là một thiết lập phát triển khá tốt, nhưng thời gian thay đổi và hệ sinh thái JavaScript di chuyển rất nhanh. Các công cụ mới đã xuất hiện, các phương pháp tốt nhất đã phát triển và độ phức tạp của việc phát hành một gói npm đã trở nên dễ dàng hơn đồng thời cũng khó khăn hơn.

Chỉ cần nhìn vào sự phát triển của trường "exports" trong package.json nếu bạn muốn đau đầu. Hoặc thử tìm hiểu sự kết hợp đúng của các cấu hình TypeScript, bundler và quy trình CI để phát hành một thư viện hoạt động liền mạch trên Node, Deno, Bun và trình duyệt. Thật bất ngờ là rất khó để thực hiện đúng.

Đó là lý do tôi xây dựng ts-base - một mẫu thư viện TypeScript hiện đại giúp xử lý tất cả những phức tạp này cho bạn. Nó được thiết kế có chủ kiến, đã được kiểm chứng và hoạt động ngay lập tức với mọi môi trường JavaScript lớn.

Ts-base là gì?

Ts-base là một mẫu thư viện TypeScript tích hợp công cụ hiện đại và quy trình tự động. Thay vì bắt đầu từ đầu hoặc sao chép mã mẫu lỗi thời, bạn nhận được một môi trường phát triển hoàn chỉnh bao gồm linting, kiểm tra, xây dựng, phát hành và xuất bản - tất cả đều được cấu hình sẵn và sẵn sàng để sử dụng.

Mẫu này được xây dựng xung quanh ba nguyên tắc cốt lõi:

  • Đa runtime trước tiên: Hoạt động liền mạch trên Node, Deno, Bun và trình duyệt
  • Tự động hóa thay vì cấu hình: Cài đặt tối thiểu, tự động hóa tối đa
  • Công cụ hiện đại: Chỉ ESM, TypeScript mới nhất và các phụ thuộc được chọn lọc cẩn thận

Kiến trúc Đa Runtime

Trái tim của ts-base là thiết kế không phụ thuộc vào runtime. Thay vì cố gắng làm cho một tệp hoạt động ở khắp mọi nơi (và phải đối mặt với các vấn đề tương thích), mẫu này sử dụng một sự phân tách rõ ràng:

typescript Copy
// src/internal.ts - Logic cốt lõi, không có API cụ thể cho runtime
export function add(a: number, b: number): number {
  return a + b;
}

export function greet(name: string, options = {}): string {
  const base = `Hello, ${name}`;
  return options.shout ? `${base.toUpperCase()}!` : `${base}.`;
}
typescript Copy
// src/index.ts - Adapter Node/Bun
export { add, greet } from "./internal";
import { randomBytes } from "node:crypto";

export function getSecureRandomId(): string {
  const timePart = Date.now().toString(36);
  const bytes = randomBytes(12).toString("base64url");
  return `${timePart}-${bytes}`;
}
typescript Copy
// src/browser.ts - Adapter trình duyệt
export { add, greet } from "./internal";

export function getSecureRandomId(): string {
  const timePart = Date.now().toString(36);
  const array = new Uint8Array(12);
  crypto.getRandomValues(array);
  const rand = btoa(String.fromCharCode(...array))
    .replaceAll("+", "-")
    .replaceAll("/", "_")
    .replaceAll("=", "");
  return `${timePart}-${rand}`;
}

Điều này mang lại cho bạn các imports sạch sẽ cho mọi runtime:

typescript Copy
// Node/Bun
import { add, getSecureRandomId } from "@your-package/ts-base";

// Trình duyệt (qua bundler)
import { add, getSecureRandomId } from "@your-package/ts-base/browser";

// Deno (imports TypeScript trực tiếp)
import {
  add,
  greet,
} from "https://jsr.io/@bgub/ts-base/<version>/src/index.ts";

Hệ thống xây dựng sử dụng tsdown để tạo hai gói tối ưu: một cho môi trường Node và một gói đã được nén riêng cho trình duyệt, cả hai đều có sourcemaps.

Trải nghiệm Phát triển

Ts-base tập hợp công cụ của bạn xung quanh một vài lựa chọn tuyệt vời:

Biome thay thế cả ESLint và Prettier bằng một công cụ duy nhất, nhanh chóng. Không còn xung đột cấu hình hoặc không tương thích plugin - chỉ cần định dạng và linting nhất quán hoạt động ngay lập tức.

Vitest cung cấp kiểm tra siêu nhanh với báo cáo độ bao phủ tích hợp và ngưỡng có thể tùy chỉnh. Các bài kiểm tra chạy song song, hỗ trợ TypeScript một cách tự nhiên và bao gồm các tính năng hữu ích như mocking và snapshots.

Size Limit tự động theo dõi kích thước gói của bạn. Nó chạy trong CI và bình luận trên các pull request khi thay đổi của bạn làm tăng kích thước gói, giúp bạn phát hiện bloat trước khi phát hành.

Cấu hình TypeScript được tối ưu hóa cho các bundlers hiện đại với các cài đặt như moduleResolution: "bundler"allowImportingTsExtensions: true hoạt động tốt với các công cụ như Vite, Rollup và esbuild.

Quy trình CI/CD Tự động

Một trong những điểm mạnh lớn nhất của ts-base là thiết lập CI/CD hoàn chỉnh. Mọi khía cạnh của chất lượng mã và xuất bản đều được tự động hóa:

Cửa chất lượng: Mỗi pull request kích hoạt linting, kiểm tra kiểu, kiểm tra và báo cáo độ bao phủ. CI tải độ bao phủ lên Codecov và bình luận trên PR với các báo cáo ảnh hưởng đến kích thước.

Quản lý Phát hành: Thay vì cấu hình phát hành phức tạp, ts-base sử dụng Release Please của Google. Khi các commit được ghép vào nhánh chính, Release Please tự động mở một "Release PR" cập nhật số phiên bản, tạo changelogs và tạo thẻ phát hành.

Xuất bản Tự động: Khi bạn hợp nhất Release PR, GitHub Actions tự động xây dựng và xuất bản gói của bạn lên cả npm và JSR với đầy đủ OIDC provenance và bảo mật xác nhận.

Commits Thông thường: Tiêu đề PR tự động được lint theo định dạng commit thông thường, đảm bảo việc tạo changelog nhất quán.

Tại sao Cách tiếp cận này Hiệu quả Hơn

Hầu hết các mẫu thư viện TypeScript mà tôi thấy đều quá tối thiểu (để bạn tự tìm hiểu về CI, xuất bản và hỗ trợ đa runtime) hoặc quá phức tạp với hàng tá phụ thuộc. Tôi đã thấy các mẫu với các gói như @commitlint/cli, @commitlint/config-conventional, @semantic-release/changelog, @semantic-release/git, @semantic-release/github, @semantic-release/npm, và nhiều hơn nữa chỉ để xuất bản CI!

Ts-base có cách tiếp cận khác với chỉ 8 phụ thuộc dev tổng cộng. Bằng cách chọn Release Please thay vì semantic-release, Biome thay vì ESLint+Prettier, và Vitest thay vì Jest, bạn có một đồ thị phụ thuộc đơn giản hơn dễ bảo trì và ít có khả năng bị hỏng hơn.

Triết lý tự động hóa có nghĩa là ít cấu hình hơn và ít nơi để mọi thứ có thể sai. Release Please xử lý việc tăng phiên bản, tạo changelog và tạo phát hành trong một công cụ. Các workflow của GitHub Actions xử lý mọi thứ khác.

Phép thuật của Release Please

Release Please xứng đáng được chú ý đặc biệt vì nó thay đổi cách bạn nghĩ về việc phát hành. Thay vì tự tay tăng phiên bản hoặc cấu hình các pipeline semantic-release phức tạp, Release Please hoạt động như sau:

  1. Bạn hợp nhất các commit vào main bằng cách sử dụng các tin nhắn commit thông thường
  2. Release Please tự động mở/cập nhật một "Release PR" với việc tăng phiên bản và các mục changelog
  3. Khi bạn sẵn sàng phát hành, chỉ cần hợp nhất Release PR
  4. GitHub Actions tự động xuất bản lên npm và JSR

Hệ thống cũng hỗ trợ phát hành trước. Nếu bạn phát hành một phiên bản alpha hoặc beta, nó tự động xuất bản dưới thẻ "next" trên npm. Bạn có thể ghi đè việc tăng phiên bản bằng cách sử dụng Release-As: 2.0.0 trong tin nhắn commit, và bạn có thể duy trì nhiều nhánh phát hành (như 2.x3.x) mà mỗi nhánh đều có các Release PR riêng.

Bắt đầu

Thiết lập ts-base rất đơn giản:

  1. Clone và tùy chỉnh: Clone kho lưu trữ, xóa thư mục .git, và cập nhật package.json, jsr.json, và .release-please-manifest.json với thông tin gói của bạn.

  2. Khẳng định gói của bạn: Đặt phiên bản thành 0.0.0 trong tất cả các tệp cấu hình, sau đó chạy npm publish cục bộ để khẳng định tên gói của bạn trên npm.

  3. Cấu hình xuất bản: Trong npm, đặt gói của bạn yêu cầu 2FA cho quyền truy cập chỉ (không phải xuất bản), sau đó thêm workflow GitHub của bạn như một nhà xuất bản đáng tin cậy. Trên JSR, tạo gói của bạn và thêm kho lưu trữ như một nguồn đáng tin cậy.

  4. Thiết lập GitHub: Đẩy lên GitHub, thêm CODECOV_TOKEN như một bí mật của kho lưu trữ và cấu hình các quy tắc bảo vệ nhánh.

  5. Bắt đầu phát triển: Thêm mã vào src/, viết các bài kiểm tra và đẩy các commit. Release Please sẽ xử lý phần còn lại.

Tôi khuyên bạn nên cấu hình GitHub để chỉ cho phép hợp nhất squash và sử dụng "tiêu đề pull request và chi tiết commit" làm thông điệp commit mặc định. Điều này giữ lịch sử commit của bạn sạch sẽ và đảm bảo tuân thủ commit thông thường.

Thực Hành Tốt Nhất & Mẹo

Cài đặt Kho Lưu Trữ: Bật bảo vệ nhánh trên main với các kiểm tra trạng thái bắt buộc. Vô hiệu hóa các commit hợp nhất để giữ lịch sử tuyến tính.

Điểm vào: Sử dụng xuất khẩu chính (@your-package) cho Node/Bun, xuất khẩu trình duyệt (@your-package/browser) cho mã trình duyệt đã được bundler, và imports TypeScript trực tiếp cho Deno.

Tùy chỉnh: Nếu bạn không cần các builds riêng biệt cho Node/trình duyệt, hãy xóa cấu hình không sử dụng. Mẫu được thiết kế để có thể cắt giảm theo nhu cầu cụ thể của bạn.

Chiến lược Kiểm tra: Mẫu bao gồm các ví dụ về việc kiểm tra cả mã chung và mã cụ thể cho nền tảng, bao gồm việc mocking các API trình duyệt trong môi trường kiểm tra Node.

Kết luận

Xuất bản một thư viện TypeScript không nên yêu cầu bạn có một bằng tiến sĩ về cấu hình công cụ. Ts-base cung cấp cho bạn một nền tảng hiện đại, có chủ kiến giúp xử lý sự phức tạp để bạn có thể tập trung vào việc xây dựng phần mềm tuyệt vời.

Mẫu này đại diện cho tám năm bài học từ việc duy trì các dự án mã nguồn mở. Bạn đã sẵn sàng thử nghiệm chưa? Hãy xem kho lưu trữ ts-base và bắt đầu xây dựng thư viện tiếp theo của bạn.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào