Chỉ mục tài liệu SQLite3 WebAssembly
(sqlite.org)- Đâ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
- Đây là tài liệu WebAssembly·JavaScript API của dự án SQLite, đề cập tới các API giúp sử dụng sqlite3 trên các trình duyệt hiện đại có hỗ trợ WASM
-
Giới thiệu dự án và kênh hỗ trợ
- About the sqlite3 WASM subproject
- Project news
- FAQ: Frequently Asked Questions
- TODOs: Đề cập cả các tính năng đã lên kế hoạch lẫn chưa có kế hoạch
- Hỗ trợ kỹ thuật và phản hồi được tiếp nhận trên SQLite forum, còn người dùng có commercial SQLite support contracts có thể dùng kênh hỗ trợ hiện có
-
Tài liệu chạy thử·cài đặt·build
- three-step HOWTO: Minh họa cách включить và chạy mô-đun sqlite3 WASM cùng JavaScript API liên quan
- Downloads: Có trên trang tải xuống của dự án chính
- Prerelease snapshots: Được cập nhật thường xuyên
- npm module
- Building sqlite3 WASM: Trình bày quy trình build sqlite3 WASM và mã JS liên quan
- Chi tiết build bằng Emscripten
-
Tài liệu về API và chi tiết triển khai
- The API index: Giải thích các biến thể API và cách tải·truy cập
- Cookbook: Các công thức cho mã phía client
- Persistent storage options: Các lựa chọn lưu trữ bền vững
- C-structs: Cách dùng cấu trúc C trong JS API
- virtual tables: Cách tạo bảng ảo và hàm giá trị bảng từ JS
- API changes: Các thay đổi API có thể ảnh hưởng tới client
- module symbols app: Tạo danh sách biểu tượng API sqlite3 từ mô-đun JavaScript/WASM
-
Quản lý tài liệu và kho mã
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
- Porting WebSQL to OPFS: Bài viết về SQLite WASM của đội ngũ Google Chrome dev
- building SQLite3 for WASI: Bài viết của đội VMWare OCTO về build SQLite3 cho WASI
1 bình luận
Ý 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 clientTuy 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
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
justjs14Phả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
“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 trongSharedWorker, vốn đã khá phổ biếnViệ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
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ằngsqlite3.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.pyTuy 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
@sqlite.org/sqlite-wasmtừjsdelivrtrong module JS và tảisqlite3-bundler-friendly.mjscùngsqlite3.wasmKhi đó 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ẻ scripttype=modulethông thường lẫn DenoHTML ví dụ ở đây: https://github.com/Ciantic/experimenting-sqlite-wasm/blob/main/standalone.html
sqlite-wasmtả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ơnTuy 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
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?
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
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?
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.sessionStorageGầ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
WHEREthay cho bộ lọcif()cũng có thể tốn ít bộ nhớ và CPU hơnTải từ trang download chính thức rồi xóa hết các tệp
mjsvà tệp “bundler-friendly”, thì phụ thuộc SQLite Wasm tối thiểu vẫn khoảng 1,3MBVớ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
sqlite3.jsvà 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 410KBNế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
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ó thể là cục bộ, trên máy chủ trung tâm, hoặc ở edge gần người dùng
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,sqlxdườ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-unknownCuố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
Về bản chất, cần đưa bản build SQLite emscripten vào
wasm-bindgenqua headerextern 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 RustSau đó 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
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
emscriptenkhớp tốt vớiwasm32-unknown-unknownCó 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 đã 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
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?
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ả
https://medium.com/offline-camp/couchdb-pouchdb-and-hoodie-as-a-stack-for-progressive-web-apps-a6078a985f18
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
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