2 điểm bởi GN⁺ 2024-10-16 | 1 bình luận | Chia sẻ qua WhatsApp
  • Đây là một trung tâm tập hợp tài liệu WebAssembly·JavaScript API dành cho các nhà phát triển muốn dùng trực tiếp sqlite3 trên các trình duyệt hiện đại có hỗ trợ WASM
  • Có thể bắt đầu nhanh với HOWTO 3 bước, đồng thời kiểm tra lộ trình cài đặt và triển khai qua tài liệu tải xuống, mô-đun npm, build và chi tiết Emscripten
  • Tài liệu API bao quát từ cách tải, các công thức mã phía client, lưu trữ bền vững, cấu trúc C trong JS API cho tới cách viết bảng ảo và hàm giá trị bảng
  • Tài liệu cũng tổng hợp các trường hợp sử dụng thực tế như SQLime, Evolu, SQLiteNext, sqlite-wasm-esm, sqlite-wasm-http cùng các dự án đi trước như sql.js, wa-sqlite, absurd-js
  • Tài liệu liên kết các nguồn về Browser SQLite, OPFS, IndexedDB và WASI để có thể nhanh chóng so sánh các lựa chọn triển khai SQLite trong môi trường web

Phạm vi tài liệu sqlite3 WASM

Trường hợp sử dụng và hệ sinh thái liên quan

  • Các dự án bên thứ ba sử dụng dự án này

    • SQLime: Cung cấp giao diện trình duyệt cơ sở dữ liệu
    • Evolu: Nền tảng local-first tập trung vào quyền riêng tư, tính dễ dùng và không phụ thuộc nhà cung cấp
    • SQLiteNext: Demo tích hợp dự án này với next.js
    • sqlite-wasm-esm: Minh họa cách dùng dự án này trong toolchain Vite
    • sqlite-wasm-http: SQLite VFS cung cấp quyền truy cập chỉ đọc vào cơ sở dữ liệu được phục vụ trực tiếp qua HTTP
  • Công trình đi trước và các dự án lân cận

    • sql.js của Alon Zakai: Được biết đến là trường hợp đầu tiên dùng trực tiếp sqlite3 trong trình duyệt nếu không tính WebSQL, với lịch sử truy về commit năm 2012
    • wa-sqlite của Roy Hashimoto: Được biết đến là triển khai đầu tiên của OPFS storage cho cơ sở dữ liệu sqlite3, đồng thời bao gồm cả công việc liên quan tới SQLite VFS phía JS
    • absurd-js của James Long: Minh họa cách lưu cơ sở dữ liệu sqlite3 bên trong cơ sở dữ liệu IndexedDB
    • postgres-wasm: Chạy Postgres database server trong trình duyệt
    • Jaccwabyt: Thư viện JS nhỏ để thao tác các cấu trúc C được host trong WASM bằng mã JS, được tạo ra để hỗ trợ triển khai OPFS sqlite3_vfs của dự án này
    • CoWasm: “Collaborative WebAssembly for Servers and Browsers”, trong đó demo app có bao gồm bản build WASM của ứng dụng sqlite3 shell
    • absurder-js: Dự án Nicholas G. Piesco tái hình dung absurd-js, đồng thời cũng có bài giới thiệu trên SQLite forum
    • sqlite-wasm-rs: Cung cấp Rust SQLite binding cho build wasm32-unknown-unknown
  • Tài liệu và bài viết bên ngoài

1 bình luận

 
GN⁺ 2024-10-16
Ý kiến trên Hacker News
  • Sẽ rất thú vị nếu chạy SQLite trong bộ nhớ trên trình duyệt, rồi stream bản sao WAL log lên máy chủ theo cách tương tự Litestream và Cloudflare Durable Objects đang dùng
    Có thể dùng WebSocket, hoặc có vẻ cũng làm được bằng các POST fetch() gián đoạn. Trong những lần truy cập sau, sẽ dùng dữ liệu phía máy chủ để nạp lại SQLite phía client
    Tuy nhiên, xem bài viết trên diễn đàn SQLite thì bản build SQLite WASM mặc định không có chế độ WAL, nên có lẽ cần bản build tùy chỉnh

    • Có nhiều tầng nghĩa của việc “nó không hoạt động như vậy” ở đây
      SQLite trong bộ nhớ không dùng WAL, và Wasm trên trình duyệt không hỗ trợ những thứ như API bộ nhớ dùng chung mà chế độ WAL của SQLite kỳ vọng
      Litestream cần một cấu hình WAL rất chính xác; với cấu hình mặc định của SQLite native thì tình cờ khớp khá tốt, nhưng rất khó tái hiện trong Wasm
      Cloudflare Durable Objects có thể lấy cảm hứng từ Litestream, nhưng cách hoạt động thực tế khá khác, LiteFS hay Turso cũng vậy
      Bản thân ý tưởng lớn về việc stream các thay đổi của SQLite là khả thi, nhưng khối lượng công việc lớn và khó triển khai vì mô hình đồng thời của Wasm trên trình duyệt
      Tôi từng viết bài trên diễn đàn đó và đã làm cho WAL hoạt động trong bản build Wasm SQLite phía máy chủ, nhưng đó không phải là lựa chọn dùng được hoặc khả thi trên trình duyệt
    • Tháng 8/2022, tôi đã làm một bằng chứng khái niệm tương tự và gửi Twitter DM nhưng không nhận được hồi âm. Handle là justjs14
      Phải tìm lại mã khi đó, nhưng tôi đã biên dịch SQLite có VFS sang Wasm trong trình duyệt để mở DB, sửa đổi, rồi có thể push/pull WAL lên máy chủ. Cũng có thể đồng bộ giữa các trình duyệt, thủ công hoặc qua WebRTC, và nếu cấp token GitHub cho client trình duyệt thì nó cũng chạy trên GitHub Pages
      Nếu quan tâm, tôi có thể làm lại từ đầu để chạy được. Khi đó tôi đã thử nghiệm khá nhiều với cách tiếp cận này và cho rằng ít nhất nó có thể hữu ích cho một số ứng dụng
      Cũng có demo chỉ có chức năng pull ở đây: https://just.billywhizz.io/sqlite/demo/#https://just.billywhizz.io/sqlite/demo/db/chinook.db
    • Khác với vài ý kiến khác ở đây, tôi cho rằng stream bản sao WAL là khả thi về mặt kỹ thuật. Tuy nhiên phải triển khai bên trong VFS
      “Bộ nhớ dùng chung” có thể là SharedArrayBuffer, và nếu mỗi lần chỉ mở một kết nối DB thì buffer thông thường cũng được. Ví dụ có thể làm như vậy trong SharedWorker, vốn đã khá phổ biến
      Việc triển khai sẽ không đơn giản, nhưng chắc chắn là có thể. Thực ra vấn đề lớn hơn là nó bắt các thay đổi ở cấp khối, chứ không phải cấp hàng
      Vì vậy có thể dùng để nhân bản toàn bộ DB, nhưng khó đồng bộ một phần kiểu chỉ chia sẻ một số hàng với người dùng khác
      Nếu cần thay đổi ở cấp hàng để đồng bộ một phần, nên dùng trigger hoặc SQLite session extension: https://sqlite.org/sessionintro.html
      PowerSync đang dùng trigger phía client, và ngoài công việc bảo trì trigger thì tôi chưa thấy nhược điểm lớn nào
    • Có phải đang nghĩ đến thứ như https://electric-sql.com/ không?
    • Tôi chưa hiểu hoàn toàn ý tưởng “hydration” này, nhưng gần đây tôi bắt đầu quan tâm đến việc dùng Wasm để chạy một phần logic backend trong trình duyệt
      Ví dụ, nếu chạy phần render template thông thường hoặc một số endpoint Htmx bằng Wasm, thì ngay cả các web framework phía máy chủ thông thường cũng có thể cung cấp chức năng offline bằng kho lưu trữ SQLite Wasm tương tự điều OP nói
      Ví dụ Django đầy đủ: https://github.com/m-butterfield/django_webassembly
      Ví dụ Rust tối thiểu tách client/server bằng macro: https://github.com/richardanaya/wasm-service
      Clojure Electric làm việc tương tự mà không cần Wasm, với nhiều macro hơn: https://github.com/hyperfiddle/electric
      Trong số các công cụ web gần đây của Microsoft cũng có một thứ bắt đầu bằng chữ B
      Trong vài năm qua, một phần đáng ngạc nhiên của hệ sinh thái Python đã có hỗ trợ Wasm, nên có thể tận dụng cho cách tiếp cận này. Không chỉ các thư viện rõ ràng liên quan đến machine learning, mà còn có các thư viện game như Pygame, Pyxel; SDL2 đã bổ sung hỗ trợ, nên có vẻ hỗ trợ thư viện UI đa chạm Kivy cũng không còn xa
      Có vẻ có rất nhiều khả năng mới để chạy mã trên bất kỳ máy tính nào, và khi cần thì chạy trong sandbox của trình duyệt web để tránh thủ tục quan liêu nền tảng hoặc phí hoa hồng
  • Tài liệu nói rằng các thành phần này lần đầu xuất hiện dưới dạng beta công khai trong 3.40, và API dự kiến sẽ ổn định trong 3.41 dựa trên phản hồi từ cộng đồng
    Tuy nhiên bản phát hành SQLite mới nhất là 3.46.1 vào ngày 2024-08-13, nên có lẽ API đã ổn định rồi nhưng tài liệu chưa được cập nhật
    Sẽ là một phương thức phân phối tốt nếu nhóm SQLite phát hành gói npm chính thức kèm phiên bản WASM. Sau đó tôi thấy theo phần trả lời thì đã có rồi
    Cá nhân tôi vẫn thích nhất SQLite-in-WASM biến thể Pyodide. Nó đã tồn tại từ lâu trước bản triển khai SQLite chính thức, và khi dùng Pyodide thì WASM SQLite đi kèm như một phần của thư viện chuẩn Python
    Nó được dùng như vậy tại https://lite.datasette.io/, và cũng có thể thử tại https://pyodide.org/en/stable/console.html
    Nếu chạy select sqlite_version() bằng sqlite3.connect(':memory:') thì kết quả là 3.39.0 từ ngày 2022-06-25, nên có vẻ Pyodide cần nâng phiên bản. Phiên bản này dường như được kế thừa từ emscripten: https://github.com/emscripten-core/emscripten/blob/main/tools/ports/sqlite3.py

    • Đúng là API đã ổn định. Lần tới khi ngồi trước máy tính, tôi sẽ thử cập nhật câu đó
      Tuy nhiên nhóm SQLite sẽ không phát hành gói npm chính thức. Chúng tôi chỉ phân phối JS thuần, và kiên quyết từ chối chui vào cái hang thỏ hỗ trợ công cụ ngoài ngôn ngữ. Không thành viên nào trong dự án dùng những công cụ như vậy
      Chúng tôi hỗ trợ bản build npm “được phê duyệt chính thức” do Thomas Steiner duy trì, nhưng không chủ động nhắm tới bất kỳ framework JS nào làm đối tượng phát triển
      Nếu trực tiếp hỗ trợ một framework cụ thể, bao gồm npm, điều đó có thể tạo ấn tượng rằng chúng tôi bảo chứng cho framework đó, và chúng tôi chủ động tránh bảo chứng cho dự án bên thứ ba
    • Có vẻ nhóm SQLite đã làm việc đó được một thời gian rồi. Chỉ cần import @sqlite.org/sqlite-wasm từ jsdelivr trong module JS và tải sqlite3-bundler-friendly.mjs cùng sqlite3.wasm
      Khi đó có thể dùng C API của SQLite và API hướng đối tượng oo1, đồng thời nó hoạt động cả với thẻ script type=module thông thường lẫn Deno
      HTML ví dụ ở đây: https://github.com/Ciantic/experimenting-sqlite-wasm/blob/main/standalone.html
    • https://github.com/sqlite/sqlite-wasm
      sqlite-wasm tải nhanh hơn Pyodide rất nhiều, nên nếu không cần Python thì cái trước là lựa chọn tốt hơn
    • DuckDB WASM có thể dùng độc lập với Pyodide và cũng có thể mở rộng SQLite
      Tuy nhiên có vẻ khá hạn chế. Vì không có sqlite_version() nên tôi thậm chí không kiểm tra được phiên bản, và phiên bản trong kho là 3.38.1, khá cũ
      Hiện tại web shell của DuckDB không thể tải phần mở rộng SQLite vì phần mở rộng SQLite cho bản 1.1.2 mới ra hôm qua chưa được phát hành. Phiên bản trước hoạt động với bản WASM edition vừa được cập nhật gần đây
      Cũng có thể gắn thêm spatial extension, GDAL, tìm kiếm vector, v.v.: https://github.com/duckdb/duckdb-wasm/releases/tag/v1.29.0
      Tự tạo một “SQL web shell” cũng không quá khó, nhưng tài liệu chưa đủ hoàn chỉnh
      https://github.com/duckdb/sqlite_scanner/blob/main/src/sqlite/sqlite3.h
    • Đọc FAQ trên trang đó có thể sẽ hữu ích
  • Khi dùng với Go, tôi rất thích gói Wasm SQLite của ncruces https://github.com/ncruces/go-sqlite3
    Gói Go của cznic cũng rất tuyệt, nhưng bản Wasm này hoạt động tốt ngay cả trong các môi trường như OpenBSD

  • WebSQL lẽ ra chỉ nên là SQLite, và nếu vậy thì hệ sinh thái offline-first cũng như kho lưu trữ ứng dụng nói chung hẳn đã tốt hơn nhiều
    Giờ liệu còn khả năng nào không? Thay vì trừu tượng hóa SQLite và đặc tả quá mức, liệu có thể đặc tả phiên bản SQLite API mà trình duyệt cần hỗ trợ rồi định kỳ nâng phiên bản không?

    • Cách “định kỳ nâng phiên bản” trong trình duyệt có khả năng gây khá nhiều vấn đề
      Một trong những điểm cốt lõi của web là nếu có thể thì những thứ cũ vẫn phải tiếp tục hoạt động, và những thay đổi phá vỡ tương thích như vậy rất khó
      Ngay cả khi đặc tả liệt kê vài phiên bản và để trang web chọn, trình duyệt sẽ phải gánh trách nhiệm phiền phức là duy trì các phiên bản SQLite cũ có thể đã không còn được hỗ trợ. Mỗi phiên bản lại chiếm khoảng 1MB
      Nếu vậy, có lẽ cứ để từng website tự chịu cái giá cho lựa chọn của mình như hiện nay thì tốt hơn
      Nếu lo việc tải lặp lại tài nguyên chung, thì đó đã là vấn đề mà các CDN khác cũng chấp nhận. Một giải pháp shared caching cho các dependency chung sẽ có giá trị lớn hơn nhiều so với việc chỉ giới hạn ở SQLite
      Cách hiện tại trông có vẻ tốt hơn phiên bản do trình duyệt cung cấp
    • Tôi thích SQLite, nhưng phải thừa nhận rằng nó có nhiều hành vi đặc thù để đưa vào mọi trình duyệt. Vì vậy một API kiểu giống SQLite có lẽ sẽ tốt hơn
    • Tôi lại thấy may vì WebSQL đã không phổ biến
      Giờ khi cần, ta có thể lấy SQLite mới nhất dưới dạng WASM blob nén 410KB. Nếu bị trói vào phiên bản SQLite do trình duyệt áp đặt thì có khi giờ chúng ta vẫn đang dùng phiên bản 10 năm tuổi
  • Lướt nhanh qua trang thì chưa rõ lắm các trường hợp sử dụng
    Cụ thể hơn, cái này có thể trở thành phương án thay thế IndexedDB không? Dữ liệu có được lưu bền vững không, hay phải tự lưu tệp SQLite trực tiếp vào File System API hoặc IndexedDB/localStorage?

    • Theo trang giới thiệu, một trong các mục tiêu của dự án này là hỗ trợ lưu trữ bền vững phía client bằng các API JS có thể dùng được trong phạm vi khả thi
      Hiện tại bao gồm lưu trữ qua Origin-Private FileSystem(OPFS) và, dù rất hạn chế, qua các backend window.localStorage, window.sessionStorage
  • Gần đây tôi rất quan tâm đến mảng local-first, nhưng so với việc dùng các API lưu trữ tích hợp sẵn của trình duyệt, đặc biệt là IndexedDB, thì việc nhúng SQLite có vẻ khá nặng
    Các thư viện mã nguồn mở lớn nhìn chung cũng có vẻ dùng API tích hợp sẵn
    Tôi muốn thấy một giải pháp mã nguồn mở cung cấp API kiểu SQLite và đồng bộ hóa trên lớp lưu trữ native của trình duyệt, thay vì cố nhét thêm một executable khác bằng WebAssembly

    • SQL có thể được xem là dễ dùng hơn API IndexedDB, và chẳng hạn dùng mệnh đề WHERE thay cho bộ lọc if() cũng có thể tốn ít bộ nhớ và CPU hơn
    • Có thể bạn sẽ quan tâm đến TinyBase. Đây là thư viện do tôi tạo ra
  • Tải từ trang download chính thức rồi xóa hết các tệp mjs và tệp “bundler-friendly”, thì phụ thuộc SQLite Wasm tối thiểu vẫn khoảng 1,3MB
    Với ứng dụng trình duyệt thì có vẻ hơi lớn, nhưng ngày nay Wasm cũng chạy ở những nơi khác, nên trong các môi trường đó có thể hợp lý hơn

    • Dù vậy nó nén khá tốt. sqlite3.js và Wasm có dung lượng gốc 1,3MB, nhưng nếu minify JS và nén Brotli hai tệp thì giảm xuống còn 410KB
    • Tôi cho rằng 1,3MB là kích thước hoàn toàn hợp lý với một web app hiện đại. Đặc biệt là sau lần truy cập đầu tiên, nó sẽ được cache
      Nếu chỉ để lưu thiết lập người dùng thì dĩ nhiên không cần tải SQLite, nhưng nếu là tác vụ mà một cơ sở dữ liệu đầy đủ đem lại lợi ích, thì không cần quá lo vì 1MB rồi tự dưng đi phát minh lại bánh xe
      Nếu bình luận khác nói đúng thì trên mạng ban đầu cũng không phải là 1,3MB
    • Đây là yếu tố đáng cân nhắc cùng với việc trình duyệt đã tích hợp sẵn IndexedDB
      Dù vậy, với các ứng dụng trình duyệt như Figma hay Photoshop, hoặc ứng dụng machine learning, nơi mã và dữ liệu ứng dụng vốn đã lớn, thì 1,3MB có thể không phải gánh nặng bổ sung đáng kể
      Cũng đáng cân nhắc rằng việc parse Wasm nhanh hơn đáng kể so với JS. Hiện tôi không tìm được nguồn cho nhận định này, nhưng đã từng có ít nhất một bài viết hay liên quan
      https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API
    • Cần nghĩ đến mô hình sandbox của WebAssembly. Về lý thuyết, chương trình, ở đây là SQLite, có thể chạy ở bất cứ đâu phù hợp để thực thi
      Có thể là cục bộ, trên máy chủ trung tâm, hoặc ở edge gần người dùng
    • Ở phía server, rất có khả năng cần một bản build Wasm SQLite riêng xử lý đồng thời và khóa tệp theo cách khác
      Ngoài ra WASI vẫn còn xa mới là câu trả lời. SQLite amalgamation build tốt với WASI, nhưng tính đồng thời vẫn là vấn đề chưa được giải quyết
      Tôi đã phải tạo VFS từ đầu để đưa driver SQLite dựa trên Wasm vào trạng thái có thể dùng được
      https://github.com/ncruces/go-sqlite3/blob/main/vfs/README.md
  • Tôi đã cố làm cho cái này chạy trong hệ sinh thái Rust một thời gian, nhưng các wrapper SQL trên blessed.rs như rusqlite, sqlx dường như vẫn chưa tận dụng được nó
    Tự bọc lại cũng khó, vì tôi không tìm được cách để mã Wasm của emscripten hoạt động khớp với wasm32-unknown-unknown
    Cuối cùng vẫn cần một JS wrapper ở dạng nào đó, rồi phải triển khai interface mà các crate đó kỳ vọng và expose nó từ JS. Nếu việc này được giải quyết trong Rust thì sẽ rất tuyệt

    • Tôi đang làm việc liên quan đến chuyện đó. Nếu quan tâm hoặc muốn đóng góp, có thể tham gia ở đây: https://github.com/rhashimoto/wa-sqlite/discussions/154
      Về bản chất, cần đưa bản build SQLite emscripten vào wasm-bindgen qua header extern C, biên dịch ở chế độ đa luồng để có thể truy cập shared array buffer, đồng thời triển khai lại VFS bằng Rust
      Sau đó có thể truy cập các hàng SQLite dưới dạng byte Wasm thô, rồi tạo wrapper hoặc tích hợp kiểu Rust-SQLite
      Các tiện ích như connection pooling có lẽ vẫn sẽ không có, nhưng trong Wasm có khả năng nên dùng DB ở chế độ độc quyền
    • Có thứ đã làm cho bản build SQLite này hoạt động cùng Diesel SQLite của Rust tại đây: https://github.com/xmtp/diesel-wasm-sqlite
      Tuần này đang chuẩn bị bản phát hành 0.2 và sẽ chỉnh lại một vài vấn đề. Ngoài ra, có thể dùng Diesel ORM gần như native
    • Có tin tốt về phần làm cho mã Wasm của emscripten khớp tốt với wasm32-unknown-unknown
      Có kế hoạch để Emscripten và Rust hoạt động tốt cùng nhau trên Wasm: https://github.com/rustwasm/wasm-bindgen/pull/4014#issuecomment-2356908451
    • Tôi cũng đã chờ điều này khá lâu. Có vài PR bị treo khoảng một năm, và tôi đã thấy proof of concept, nhưng vẫn còn xa mới đến mức dùng thực tế được
  • Tôi đã tạo một thư viện SQLite chạy trên JVM thuần túy bằng cách dùng bản build Wasm của SQLite và runtime Chicory: https://github.com/dylibso/sqlite-zero
    Nó giống một thử nghiệm hơn là nhắm tới trạng thái sẵn sàng cho production, nhưng tôi nghĩ có thể hữu ích trong việc đưa một công cụ SQLite không phụ thuộc vào hệ sinh thái JVM

    • Việc truy cập hệ thống tệp diễn ra theo cách nào? Có phải WASI không?
  • Một câu hỏi chung: trong tình huống nào thì gửi toàn bộ DB và để trình duyệt xử lý truy vấn lại có lợi hơn?
    Nói cách khác, khi nào ta sẽ dùng cách này để cải thiện trải nghiệm người dùng so với mô hình DB host trên server truyền thống?

    • Cá nhân tôi đang dùng cho một website host tĩnh, nên cơ sở dữ liệu host trên server ngay từ đầu đã không phải là lựa chọn
      Nếu dùng driver phù hợp, có thể stream các chunk cơ sở dữ liệu cần thiết thay vì gửi toàn bộ cơ sở dữ liệu: https://github.com/mmomtchev/sqlite-wasm-http
      Có thể tìm kiếm toàn văn bằng SQLite mà không cần tải xuống toàn bộ cơ sở dữ liệu FTS. Nếu từ khóa tìm kiếm đủ ngắn thì vẫn sẽ nhận phần lớn dữ liệu, nhưng không phải tất cả
    • Khi nhìn tiêu đề bài này, điều tôi trực giác nghĩ tới là cách PouchDB và CouchDB tương tác trong các ứng dụng ưu tiên offline
      https://medium.com/offline-camp/couchdb-pouchdb-and-hoodie-as-a-stack-for-progressive-web-apps-a6078a985f18
    • Với việc sử dụng offline, cách này có thể phù hợp khi xử lý lượng lớn dữ liệu
      Có thể là từ thư viện âm thanh cho đến phần mềm mô hình hóa 3D. Bạn tạo và lưu bền vững các thay đổi cục bộ, rồi đồng bộ với phía server theo định kỳ hoặc khi online trở lại
    • Tôi đang xây dựng các dashboard giao tiếp trực tiếp với nhiều dịch vụ. Trên server của tôi chỉ có rất ít dữ liệu để kiểm soát truy cập và quản lý token, còn dữ liệu thực tế không đi qua server của tôi
      Những ứng dụng kiểu này là ứng viên rất phù hợp cho DB nhúng phía client