fix: build and run in the browser with GOOS=js GOARCH=wasm#369
fix: build and run in the browser with GOOS=js GOARCH=wasm#369paralin wants to merge 1 commit intoncruces:mainfrom
Conversation
|
Doesn't it make more sense to just do: func (vfsOS) FullPathname(path string) (string, error) {
if runtime.GOOS == "js" {
return filepath.Clean(path), nil
}
link, err := evalSymlinks(path)
// ...
} |
|
@ncruces Ack I fixed that now. I had to do some other changes to get the tests to pass, (and they all do now), but Im going and reviewing what can be undone now to reduce the commit size. |
|
OK. I'll be frank. I tried to run the tests. A bunch failed. If the needed changes are big, it's very likely this will regress unless tested. And I'm not sure I want to commit to supporting So, first of all, why? Why do you want to open files with |
Fixes build + run in the web browser with GOOS=js GOARCH=wasm. Some files needed extra build tags to exclude behavior that doesn't work on js. Testable with: https://github.com/agnivade/wasmbrowsertest/ Signed-off-by: Christian Stewart <christian@aperture.us>
|
@ncruces I understand you don't want to commit to supporting it. I excluded some of the test cases with go:build flags in the most recent commit. If you want to close this out I'm happy to just fork and work on it there instead. But to answer your questions:
The Origin Private File System: https://developer.mozilla.org/en-US/docs/Web/API/File_System_API/Origin_private_file_system It's already possible to open and use sqlite databases with this through sqlite.wasm, however, the thought is to do it from Go via your library (to avoid a separate .wasm binary). |
|
OK, sure. But isn't that better resolved by implementing a VFS from scratch for just that use case? Is the Go I've often wondered if the default VFS should be It seems entirely non-obvious to me that my default VFS would be useful in a browser. SQLite doesn't ship its Unix VFS to browsers either. |
|
That's valid. I'll retract this for now and think it through further. Thanks. |
|
@ncruces I would like to add that I actually did get this working just fine: package wasm
import (
"context"
"database/sql"
"os"
"path/filepath"
"runtime"
sqlite "github.com/ncruces/go-sqlite3"
_ "github.com/ncruces/go-sqlite3/driver"
_ "github.com/ncruces/go-sqlite3/vfs/memdb"
)
// SqliteWasmConfig implements the SQLiteDriverConfig interface for pure Go SQLite driver.
// This uses github.com/ncruces/go-sqlite3 which is sqlite -> wasm -> go.
type SqliteWasmConfig struct{}
// DriverName returns the driver name for pure Go SQLite.
func (c SqliteWasmConfig) DriverName() string {
return "sqlite3"
}
// OpenDSN returns the DSN to use with sql.Open().
func (c SqliteWasmConfig) OpenDSN(path string) string {
if runtime.GOOS == "js" {
return "file:" + filepath.ToSlash(path) +
"?vfs=memdb&_pragma=journal_mode(WAL)&_pragma=synchronous(NORMAL)&_pragma=busy_timeout(5000)"
}
return "file:" + filepath.ToSlash(path) +
"?_pragma=journal_mode(WAL)&_pragma=synchronous(NORMAL)&_pragma=busy_timeout(5000)"
}
// Description returns a description for pure Go SQLite.
func (c SqliteWasmConfig) Description() string {
return "SQLite database key-value store using SQLite to wasm to pure Go driver"
}
// IsBusyError checks if the error is a SQLITE_BUSY error for pure Go driver.
func (c SqliteWasmConfig) IsBusyError(err error) bool {
if sqliteErr, ok := err.(*sqlite.Error); ok {
return sqliteErr.Code() == sqlite.BUSY
}
return false
}
// IsNestedTxError checks if the error is a nested transaction error for pure Go driver.
// This occurs when BeginTx is called on a connection that already has an active transaction.
func (c SqliteWasmConfig) IsNestedTxError(err error) bool {
if sqliteErr, ok := err.(*sqlite.Error); ok {
// SQLITE_ERROR (1) with message containing "cannot start a transaction within a transaction"
return sqliteErr.Code() == sqlite.ERROR
}
return false
}
// Store is a SQLite database key-value store using pure Go SQLite driver.
type Store = common.Store[SqliteWasmConfig]
// NewStore constructs a new key-value store from a SQLite database.
func NewStore(db *sql.DB, table string) (*Store, error) {
return common.NewStore(db, table, SqliteWasmConfig{})
}
// Open opens a SQLite database store using pure Go driver.
func Open(ctx context.Context, path string, table string) (*Store, error) {
return common.Open(ctx, path, table, SqliteWasmConfig{})
}
// OpenWithMode opens a SQLite database store with file mode.
func OpenWithMode(ctx context.Context, path string, mode os.FileMode, table string) (*Store, error) {
if runtime.GOOS == "js" {
return common.Open(ctx, path, table, SqliteWasmConfig{})
}
return common.OpenWithMode(ctx, path, mode, table, SqliteWasmConfig{})
}
// _ is a type assertion
var _ kvtx.Store = ((*Store)(nil)) |
|
So I had more errors because I was using an older version of In the end, I think I ended up where you did: testable examples don't work with I still don't think the standard file based And the problem remains that if I don't add something like this to CI, it'll become instantly broken. So, I'm not sure. I could not reproduce the crashes in #370. |
|
I'm running gotip which might have something to do with it. My PR to bring wasmbrowsertest up to date with latest deps was just approved and hopefully merged soon; that fixed a lot of random errors. I agree that deeper thought is required on how to make this work properly in your library. It's promising though - I was able to get SQL working! As for CI it's possible to run wasmbrowsertest in GitHub actions. Anyway, right now I'm pushing forward on binding to the upstream sqlite-wasm for browser as it has some complex logic for syncing between multiple writers with SharedArrayBuffer that I don't want to think through replicating in Go just yet, but maybe soon I will circle back and try to tackle having feature parity with that here too, since being able to run sqlite without the message passing latency is definitely a win. One of the main issues that I ran into is that currently you can't access the synchronous file system apis within a SharedWorker, which is where I'm running go currently. So that kind of makes any performance wins from this approach less promising, however, the asynchronous apis are available and theoretically could work. From what I've read though, they are a lot slower than the synchronous version. |
|
I just committed some of the test skips. No point in excluding examples, as that's easier done with: Some time back I had to remove running tests with |
Fixes build + run in the web browser with GOOS=js GOARCH=wasm.
Testable with:
https://github.com/agnivade/wasmbrowsertest/