Hành trình chuyển sang TypeScript của Figma
(figma.com)- Figma đã chuyển toàn bộ mã Skew sang TypeScript sau khi ngôn ngữ nội bộ Skew dùng cho rendering di động và trình xem prototype chạm tới giới hạn về onboarding, tích hợp và hệ sinh thái
- Điều kiện tiên quyết cho quá trình chuyển đổi gồm việc hỗ trợ WebAssembly trên trình duyệt di động được mở rộng, thay thế engine C++ cho các đường đi cốt lõi, và sự phát triển của các nhóm prototyping và mobile
- Quá trình migration diễn ra theo 3 giai đoạn:
Write Skew, build Skew→Write Skew, build TypeScript→Write TypeScript, build TypeScript, trong đó transpiler Skew-to-TypeScript giúp duy trì luồng phát triển - Trong quá trình chuyển đổi thực tế, nhiều vấn đề tương thích đã lộ ra như hiệu năng destructuring mảng, khác biệt về devirtualization, thứ tự khởi tạo, liên kết source map và việc thiếu conditional compilation
- Cuối cùng, Figma đã có được codebase TypeScript vượt qua unit test và đạt hiệu năng tương tự Skew; bước tiếp theo là tích hợp mã nội bộ và bên ngoài, quản lý package và tận dụng hệ sinh thái TypeScript
Vì sao chuyển từ Skew sang TypeScript
- Skew bắt đầu từ một side project ở giai đoạn đầu của Figma và đáp ứng nhu cầu tạo nhanh trình xem prototype hỗ trợ cả web lẫn mobile
- Khi phát triển thành một ngôn ngữ biên dịch sang JavaScript, nó cung cấp tối ưu hóa nâng cao và thời gian biên dịch nhanh, nhưng chi phí bảo trì tăng dần khi mã tích lũy trong trình xem prototype
- Nhân viên mới khó làm quen
- Không dễ tích hợp với phần còn lại của codebase
- Không có hệ sinh thái nhà phát triển bên ngoài Figma
- Figma kỳ vọng việc chuyển sang TypeScript sẽ mở rộng tốc độ phát triển và phạm vi cộng tác
- Đơn giản hóa tích hợp mã nội bộ và bên ngoài nhờ static import và quản lý package native
- Tận dụng công cụ do cộng đồng nhà phát triển lớn xây dựng như linter, bundler và static analyzer
- Sử dụng các tính năng JavaScript hiện đại như async/await cùng hệ thống kiểu linh hoạt hơn
- Giảm rào cản onboarding cho lập trình viên mới và cho các nhóm khác tham gia
Những điều kiện khiến việc chuyển đổi chỉ mới khả thi gần đây
- Khi Figma lần đầu xây dựng codebase mobile, trình duyệt di động chưa hỗ trợ WebAssembly, và cũng khó tải các bundle lớn với hiệu năng tốt
- TypeScript khi đó vẫn còn ở giai đoạn đầu, nên Skew với static type và hệ thống kiểu chặt chẽ hơn là lựa chọn thực tế hơn vào thời điểm đó
- Đến năm 2018, WebAssembly đã được hỗ trợ rộng rãi trên mobile, và theo thử nghiệm của Figma, đến năm 2020 hiệu năng mobile đã đạt mức đáng tin cậy
- Thế mạnh ban đầu của Skew là các tối ưu hóa compiler truyền thống như constant folding và devirtualization, cùng các tối ưu hóa đặc thù web như sinh JavaScript dùng phép toán số nguyên thực sự
- Benchmark năm 2020 cho thấy việc tải prototype Figma bằng TypeScript trên Safari có thể chậm gần gấp đôi, và do Safari là engine trình duyệt duy nhất được phép trên iOS nên đây là rào cản lớn cho việc chuyển đổi
- Từ iOS 17.4, Apple mở các engine trình duyệt khác cho người dùng EU, nhưng với người dùng ở khu vực khác thì WebKit vẫn là engine duy nhất
- Sau đó, nhiều thành phần cốt lõi của Skew engine được thay bằng các thành phần tương ứng trong C++ engine, làm giảm rủi ro hiệu năng khi chuyển sang TypeScript
- Bao gồm những đường đi mã nóng nhất như file loading
- Từ đó có thêm tự tin rằng tổn thất hiệu năng khi chuyển sang TypeScript là chấp nhận được
- Khi các nhóm prototyping và mobile phát triển thành tổ chức lớn hơn, Figma có thể đầu tư nguồn lực vào migration tự động và cải thiện trải nghiệm lập trình viên
Chuyển đổi codebase theo 3 giai đoạn
- Ở nguyên mẫu migration đầu tiên năm 2020, hiệu năng TypeScript chậm gần gấp đôi
- Sau khi hỗ trợ WebAssembly và việc chuyển mobile engine sang C++ đã đủ chín muồi, Figma đã tận dụng Maker Week để chỉnh lại nguyên mẫu cũ và trình diễn một bản migration hoạt động, vượt qua toàn bộ test
- Mục tiêu là chuyển toàn bộ codebase sang TypeScript, nhưng viết lại thủ công có thể làm chậm tốc độ phát triển và gây lỗi runtime hoặc suy giảm hiệu năng
- Khác biệt ngữ nghĩa giữa Skew và TypeScript lớn hơn một lần chuyển đổi đơn giản giữa các biến thể “JavaScript có kiểu”
- TypeScript chỉ khởi tạo namespace và class sau khi file được import
- Nếu thứ tự import không như dự kiến thì có thể xảy ra lỗi runtime
- Skew cho phép mọi symbol khả dụng ở runtime trên toàn bộ codebase ngay khi tải
- Figma đã phát triển transpiler Skew-to-TypeScript dựa trên công việc Evan Wallace từng khởi đầu trước đó
-
Phase 1: Viết Skew, build Skew
- Phát triển transpiler trong khi vẫn giữ nguyên quy trình build cũ
- Check in mã TypeScript được sinh ra lên GitHub để lập trình viên có thể xem hình dạng của codebase mới
-
Phase 2: Viết Skew, build TypeScript
- Sau khi tạo được bundle TypeScript vượt qua toàn bộ unit test, Figma dần rollout traffic production sang bản build từ codebase TypeScript
- Lập trình viên vẫn tiếp tục viết Skew, còn transpiler chuyển mã Skew sang TypeScript và cập nhật mã TypeScript trên GitHub
- Các lỗi kiểu trong mã sinh ra cũng tiếp tục được sửa
- TypeScript vẫn có thể tạo bundle hợp lệ ngay cả khi còn lỗi kiểu
-
Phase 3: Viết TypeScript, build TypeScript
- Sau khi toàn bộ người dùng đã chạy qua quy trình build TypeScript, Figma chuyển mã TypeScript thành nguồn chân lý duy nhất cho phát triển
- Họ chọn thời điểm không có code merge để dừng quy trình sinh mã tự động và xóa mã Skew khỏi codebase
- Tối thứ Sáu, họ merge việc bỏ sinh mã tự động và thay đổi các job CI sang chạy trực tiếp file TypeScript
- Trong quá trình rollout dần, họ phát hiện nội bộ tính năng Smart Animate bị hỏng; nhờ cơ chế rollout theo gate, họ có thể tắt rollout, sửa lỗi rồi xem xét lại kế hoạch
Những vấn đề lộ ra từ transpiler
- Compiler thường gồm frontend và backend
- Frontend phân tích mã đầu vào, kiểm tra kiểu và cú pháp rồi chuyển sang biểu diễn trung gian (IR)
- Backend chuyển IR sang ngôn ngữ khác
- Backend của compiler Skew tạo ra JavaScript đã được obfuscate và minify
- Transpiler là một dạng compiler đặc biệt có backend sinh ra mã mà con người có thể đọc được; Figma cần sinh TypeScript dễ đọc từ Skew IR
- Bản triển khai ban đầu tương đối suôn sẻ vì lấy nhiều cảm hứng từ JavaScript backend của Skew, nhưng về sau xuất hiện nhiều vấn đề khó theo dõi và xử lý
-
Hiệu năng destructuring mảng
- Khi điều tra chênh lệch hiệu năng offline giữa Skew và TypeScript trong prototype mẫu, Figma thấy TypeScript có frame rate thấp hơn
- Nguyên nhân là array destructuring của JavaScript
- Với thao tác như
const [a, b] = function_that_returns_an_array(), JavaScript không truy cập mảng trực tiếp theo chỉ số mà tạo iterator để duyệt - Figma dùng cách này để lấy đối số từ từ khóa
argumentscủa JavaScript, và trong một số test case cụ thể điều đó gây chậm - Khi sinh mã truy cập trực tiếp mảng arguments thay vì destructuring, độ trễ mỗi frame được cải thiện tới 25%
-
Tối ưu devirtualization của Skew
- Compiler Skew thực hiện tối ưu devirtualization bằng cách trong một số điều kiện nhất định đưa hàm bên trong class ra ngoài thành hàm toàn cục
myObject.myFunc(a, b)có thể trở thànhmyFunc(myObject, a, b)- TypeScript không làm tối ưu hóa này
- Lỗi Smart Animate xảy ra khi
myObjectlà null - Lời gọi đã devirtualize vẫn chạy bình thường, nhưng lời gọi chưa devirtualize ném ra ngoại lệ truy cập null
- Figma thêm logging vào tất cả hàm có thể tham gia devirtualization để tìm các điểm gọi có cùng vấn đề
- Sau một thời gian ngắn bật logging, họ phân tích log production và sửa các điểm gọi lỗi
-
Khác biệt về thứ tự khởi tạo
- Trong Skew, có thể khai báo biến, class, namespace và hàm ở bất kỳ đâu mà không cần quan tâm đến thứ tự
- Trong TypeScript, thứ tự khởi tạo của biến toàn cục hoặc định nghĩa class là quan trọng
- Nếu khởi tạo biến static của class trước khi định nghĩa class thì sẽ gây lỗi compile-time
- Transpiler ban đầu không dùng namespace mà làm phẳng mọi hàm vào global scope để giữ hành vi gần giống Skew
- Kết quả là mã khó đọc, nên sau đó Figma sửa transpiler để xuất TypeScript theo đúng thứ tự và thêm lại namespace để cải thiện khả năng đọc
- Cuối cùng họ đã tạo được một transpiler có thể biên dịch ra mã TypeScript vượt qua unit test và đạt hiệu năng ngang Skew
- Một số vấn đề nhỏ được xử lý bằng cách sửa thủ công trong mã nguồn Skew hoặc sửa sau khi đã chuyển sang TypeScript thay vì tiếp tục chỉnh transpiler
Duy trì trải nghiệm debug bằng source map
- Figma coi source map là yếu tố quan trọng để lập trình viên vẫn có thể debug liền mạch trong suốt quá trình chuyển sang TypeScript
- Trình debugger của trình duyệt chỉ hiểu JavaScript, nhưng lập trình viên lại đặt breakpoint trong mã Skew hoặc TypeScript
- Source map liên kết vị trí trong JavaScript đã biên dịch với vị trí trong mã nguồn gốc
- Ví dụ có thể ánh xạ như
helper → c,myInt → a,arrayOfInts → b
- Ví dụ có thể ánh xạ như
- Thông thường sẽ có một file source map đuôi
.mapgắn với bundle JavaScript cuối cùng - Hạ tầng cũ tạo source map Skew → JavaScript, nhưng ở Phase 2 pipeline đổi sang luồng Skew → TypeScript → bundling bằng esbuild
- Nếu dùng nguyên source map cũ, ánh xạ giữa JavaScript và mã Skew sẽ bị sai lệch, khiến lập trình viên không thể debug
- Quy trình build mới tạo source map theo 3 bước
- Step 1: esbuild tạo source map TypeScript → JavaScript là
ts-to-js.map - Step 2: transpiler tạo source map Skew → TypeScript cho từng file Skew
- Step 3: hợp thành hai source map để tạo source map cuối cùng Skew → JavaScript
- Step 1: esbuild tạo source map TypeScript → JavaScript là
- Nhờ source map cuối cùng này, bundle JavaScript mới vẫn có thể được ánh xạ về mã Skew, giúp duy trì trải nghiệm lập trình viên trong Phase 2
Xử lý conditional compilation trong TypeScript
- Skew hỗ trợ conditional compilation bằng câu lệnh
ifở cấp cao nhất và tùy chọndefinestruyền cho compiler - Tính năng này cho phép tạo các bundle khác nhau từ cùng một codebase
- Bundle thực tế được triển khai cho người dùng
- Bundle chỉ dành cho unit test
- Các hàm hoặc class dùng implementation khác nhau giữa build debug và release
- Vì TypeScript không có conditional compilation, Figma dùng
definescủa esbuild cùng dead code elimination sau bước type checking để xử lý ở giai đoạn bundling - Cách này có nghĩa là
defineskhông thể ảnh hưởng đến quá trình type checking- Các đoạn như
testOnlyFunctionchỉ tồn tại khiBUILD == "TEST"không thể giữ nguyên trong TypeScript
- Các đoạn như
- Cách giải quyết là luôn định nghĩa class và method, rồi rẽ nhánh theo giá trị
BUILDbên trong method- Nếu
testOnlyFunctionbị gọi trong build không dành cho test thì sẽ ném lỗiUnexpected call to test-only function
- Nếu
- JavaScript cuối cùng vẫn có thể được biên dịch giống với JavaScript mà mã Skew ban đầu tạo ra
- Tuy nhiên, một số symbol vốn chỉ tồn tại ở một số chế độ compile nhất định nay lại xuất hiện trong mọi chế độ, khiến bundle cuối hơi lớn hơn
- Trong thử nghiệm, mức tăng kích thước bundle là chấp nhận được, và các top-level symbol không export có thể bị loại bỏ bằng tree-shaking
Hướng đi sau chuyển đổi
- Việc chuyển toàn bộ mã Skew sang TypeScript đã hiện đại hóa một trong các codebase cốt lõi của Figma
- Việc tích hợp với mã nội bộ và bên ngoài trở nên dễ hơn, và lập trình viên có thể làm việc hiệu quả hơn
- Với nhu cầu và năng lực của Figma ở thời điểm trước đó, quyết định khởi đầu codebase bằng Skew là phù hợp
- Khi công nghệ trưởng thành hơn, TypeScript — vốn trước đây chưa phù hợp — nay đã trở thành lựa chọn thích hợp
- Figma đang tiếp tục khám phá các khả năng tiếp theo
- Tích hợp với phần còn lại của codebase
- Quản lý package dễ dàng hơn nhiều
- Dùng trực tiếp các tính năng mới từ hệ sinh thái TypeScript năng động
- Trong quá trình chuyển đổi, họ cũng học được nhiều khía cạnh của TypeScript như phân giải import, hệ thống module và sinh mã JavaScript
1 bình luận
Các ý kiến trên Hacker News
Việc Figma từng có ngôn ngữ tùy chỉnh cho JS đã đáng ngạc nhiên, và việc nó nhanh hơn TS còn đáng ngạc nhiên hơn
Nhưng cũng thú vị là cuối cùng họ vẫn chuyển sang TS chậm hơn
Những chuyện như vậy khá thường thấy: ban đầu công ty tự xây công nghệ riêng, rồi sau khi lớn lên thì chuyển sang thứ “chuẩn” hơn
Khi đội ngũ và sản phẩm lớn hơn nhiều, họ lại chuyển nền tảng sang một stack quen thuộc và được dùng rộng rãi hơn
Thành công của quá trình chuyển đổi như vậy phụ thuộc rất lớn vào việc văn hóa kỹ thuật của tổ chức vững đến đâu. Không có bằng chứng, nhưng có vẻ Evan và các nhà sáng lập đã xây dựng một văn hóa kỹ thuật tuyệt vời ở Figma, và tổ chức trông có đủ khả năng phục hồi để sửa sai nếu có lỗi xảy ra
Đến thời điểm đó chỉ còn lại mã kết dính, và ngôn ngữ tùy chỉnh không còn lý do để tồn tại nữa
Rồi khi cộng đồng bắt kịp và có động lực lớn hơn cả công ty, việc chuyển sang triển khai chuẩn trở nên hợp lý
Tôi cũng xem luồng từ Borg của Google đến k8s có phần tương tự. Tuy vậy, Google là bên mời cộng đồng tham gia quanh tiêu chuẩn do chính họ tạo ra
Cần so sánh chi phí của lập trình viên có thể học được một framework hoàn toàn mới ngay lần đầu nhìn thấy, với giá trị của lập trình viên đã có kinh nghiệm được ghi nhận bằng tài liệu trên nền tảng hoặc công nghệ đang dùng
Nếu tự phát triển hoàn toàn, bạn có thể vắt ra hiệu năng cực lớn từ bất kỳ ngôn ngữ hay framework nào, nhưng khi dự án phải xử lý nhiều tình huống hơn, số lập trình viên cần để bảo trì tăng lên, và cuối cùng sẽ đến lúc phần mềm có sẵn trở nên tốt hơn, dù nó chậm và không khớp hoàn hảo với yêu cầu
Nếu về dài hạn có thể duy trì tiêu chuẩn tuyển dụng cấp kỳ lân thì có lẽ vẫn duy trì được một stack hoàn toàn tùy chỉnh. Nhưng đa số tổ chức phải chuyển sang hướng mà các nhân sự mới ở mức trung bình có thể duy trì trong tương lai, và thường điều đó có nghĩa là sản phẩm của các nhà cung cấp phần mềm nổi tiếng và nhàm chán
Với người có tham vọng, đó có thể là lý do để rời đi; việc tuyển dụng cũng khó hơn và onboarding dài hơn. Về sau, khi bỏ ngôn ngữ tùy chỉnh, còn cần một dự án chuyển đổi lớn
Đôi khi việc đó đáng giá nếu mức tăng hiệu năng là cực lớn, hoặc nếu có thể viết mã an toàn hơn, hoặc nếu chủ đích là chỉ tuyển những người thích học ngôn ngữ mới
Tôi đã làm trong dự án này. Tôi có viết thêm một chút trên Twitter: https://twitter.com/andrew_k_chan/status/1786769203912925477
Tiêu đề bài viết dễ gây hiểu nhầm. Ở Figma, chúng tôi đã dùng Typescript trong các phần khác của codebase gần 10 năm, và trong gần như toàn bộ thời gian đó, lượng mã Typescript nhiều hơn mã Skew
Như bài blog giải thích, Skew được dùng cho engine di động, rồi sau đó cho trình phát prototyping, tính năng mirroring, và một hoặc hai khu vực sản phẩm nào đó tôi không nhớ
Skew không chỉ nhanh hơn TypeScript một chút
Theo Evan Wallace, cựu CTO của Figma, nhờ các tối ưu mà hệ thống kiểu chặt chẽ hơn cho phép, nó nhanh hơn 1,5~2 lần
Có vẻ nó gặp vài vấn đề khá lớn, nhưng việc giảm bớt một phần tính động để tối ưu dễ dự đoán hơn nghe như một đánh đổi tốt cho các ứng dụng cấp production
Nếu tối ưu các đường thực thi nóng, lợi thế 2 lần rất có khả năng sẽ biến mất
Tất nhiên khi đó có thể nói rằng bạn sẽ phải viết JS đã tối ưu ở nhiều nơi, ảnh hưởng đến khả năng đọc. Đúng vậy, nhưng phương án thay thế là dùng một ngôn ngữ biên dịch sang JS hoàn toàn mới, ít được hỗ trợ công cụ và ít được biết đến
Nhìn lại thì có vẻ không đáng, và bài blog có cảm giác đang tô điểm phần nào cho một lựa chọn công nghệ trước đây vốn gây tranh luận
Tôi tự hỏi liệu có thể giới hạn việc dùng TypeScript trong một tập con đạt được hiệu năng đó hay không
Điều thú vị là khi hoàn tất một thao tác như
const [a, b] = function_that_returns_an_array(), JavaScript không index trực tiếp vào mảng mà tạo một iterator để duyệt mảngVì sao JS không đơn giản index trực tiếp vào mảng khi gán destructuring?
Symbol.iterator, và destructuring phải hoạt động cả với những object như vậy. Thậm chí bản thânSymbol.iteratorcủa mảng cũng có thể bị patch, nên VM phải xử lýArray.prototype[Symbol.iterator] = function*() { yield 1; yield 2; yield 3; }[...[4, 5, 6]][1, 2, 3]Hiệu năng tệ hại của iterator protocol đã được bàn luận ngay từ lúc đó, nhưng bị phớt lờ với lập luận rằng escape analysis sẽ giải quyết [0]. Đến giờ gần 10 năm trôi qua, escape analysis vẫn chưa giải quyết được, dùng GC rất nhiều và vẫn chẳng tốt. Đây là một đặc tả tệ do những người không quan tâm đến hiệu năng thiết kế
Nếu người dùng không patch
Symbol.iterator, việc engine chuyên biệt hóa destructuring và splicing của mảng để loại bỏ overhead của iterator protocol cũng có lý, nhưng đó lại là một vấn đề đau đầu khác[0] https://esdiscuss.org/topic/performance-of-iterator-next-as-...
Điều kỳ lạ hơn là trong một số engine JavaScript, khi destructuring mảng có hai ba phần tử, destructuring object kiểu
{0: foo, 1: bar}có thể nhanh hơnBài viết không đề cập nhiều đến tác động lâu dài lên trải nghiệm lập trình viên khi mất các tính năng tiện lợi của Skew, mà chỉ nói về các chuyển đổi thực hiện một lần khi di chuyển codebase
Ví dụ, trong TypeScript rất dễ gặp trường hợp phải import file theo đúng thứ tự, nếu không có thể bị hỏng. Ngoài ra destructuring chậm, nên nếu hiệu năng dù chỉ hơi quan trọng thì không nên dùng
Sau vài năm dùng TypeScript, tôi thấy có hàng chục cái bẫy như vậy; một số kế thừa từ JavaScript, một số thì không. Nếu có nhiều kỹ sư, ít nhất cũng cần một style guide đồ sộ
Tôi tự hỏi liệu có kỹ sư nào tiếc khi Skew biến mất không
Nhờ vậy, lập trình viên có thể xem kết quả trông thế nào trong PR review và báo cáo vấn đề
Về hiệu năng và tính đúng đắn khi chạy, đúng là TS có vài cái bẫy. Những vấn đề như destructuring mảng được phát hiện bằng instrumentation và giám sát nghiêm ngặt
Việc mất một số tính năng của Skew, chẳng hạn operator overloading và kiểu số nguyên, chắc chắn là đáng tiếc. Nhưng cuối cùng việc di chuyển là quyết định của toàn đội, và tôi cũng nghĩ đó là quyết định đúng
Bài viết nói “các tính năng JavaScript hiện đại như async/await và hệ thống kiểu linh hoạt hơn”, vậy Skew chỉ có callback thôi sao?
Promisechăng?Với tư cách người không rành về Figma, tôi tò mò vì sao họ dùng WebAssembly
Figma làm những việc đó cực kỳ tốt. Ngay cả trên một canvas rất lớn với nhiều màn hình UI phức tạp, nó vẫn phản hồi nhanh đến khó tin
Ngay cả trong các ứng dụng desktop ngày nay, hiếm có thứ nào chạy tốt đến mức này. Tôi tin chắc dạng tối ưu hóa này là một phần quan trọng trong thành công của Figma
Một bài blog khác cũng có các chi tiết thú vị về cách Figma tạo TypeScript DSL + compiler tùy chỉnh để giải quyết vấn đề bảo mật, tức là quyền hạn
https://www.figma.com/blog/how-we-rolled-out-our-own-permiss...
Nghe hơi đau lòng. Công ty lớn nào cũng có công cụ, ngôn ngữ, thứ kiểu Kubernetes nội bộ của riêng mình. Sao họ không chia sẻ nhỉ
Nếu Skew là mã nguồn mở, có lẽ nó đã trở thành một TypeScript tốt hơn
Mã nguồn mở không có nghĩa là sẽ tự nhiên có đóng góp miễn phí. Mỗi PR không tầm thường đều cần review dài, thảo luận, thậm chí có thể phải viết lại
Tôi thích TypeScript và cũng có hệ thống full-stack bằng TypeScript, nhưng nó không hoàn hảo. Việc cấu hình TypeScript trong monorepo đúng là ác mộng
Để làm cho mọi thứ dễ hiểu cùng các package nội bộ dưới pnpm monorepo, phải chỉnh tay rất nhiều trong
tsconfig.jsonsao cho mọi đường dẫn khớp với nhauVà cho đến trước khi package
tsxtuyệt vời xuất hiện, toolchain cho production về cơ bản là không thể bảo trìNgoài ra nó còn chậm đến vô lý. Do Zod có vấn đề làm hiệu năng TypeScript language server chậm đi đáng kể, cuối cùng đã phải đưa vào project references và tắt project reference redirects
Tổng hợp lại thì TypeScript vẫn còn rất nhiều chỗ để cải thiện. Đặc biệt là ở khía cạnh monorepo và hiệu năng
Vấn đề monorepo nghe giống như không dùng cùng một cấu hình cho tất cả package. Nếu vậy, tôi sẽ sửa trước bằng cách ép dùng cùng cấu hình và chuẩn coding. Đây cũng không phải vấn đề của TypeScript
Có phải trước
tsxbạn dùngts-nodekhông? Nếu đúng thìtsxvững chắc hơn nhiều. Nó cứ thế hoạt động tốtTôi đang vận hành một monorepo cỡ trung, nhiều app và nhiều service hầu hết bằng TypeScript, và ngay cả với cấu hình dựa trên npm workspaces khá nhàm chán thì vẫn chạy ổn
Hoàn toàn không có ý nói TypeScript nhanh, nhưng vì nó được viết bằng JavaScript nên cũng khó mà nhanh được
Tuy nhiên, để TypeScript chạy code nhằm suy luận kiểu trong một ứng dụng quy mô lớn thì trông giống như vấn đề tự tạo ra