87 lines
2.8 KiB
Markdown
87 lines
2.8 KiB
Markdown
# SafeJS [](https://pkg.go.dev/github.com/hack-pad/safejs) [](https://github.com/hack-pad/safejs/actions/workflows/ci.yml) [](https://coveralls.io/github/hack-pad/safejs?branch=main)
|
|
|
|
A safer, drop-in replacement for Go's `syscall/js` JavaScript package.
|
|
|
|
## What makes it safer?
|
|
|
|
Today, `syscall/js` panics when the JavaScript runtime throws errors.
|
|
While sensible in a JavaScript runtime, [Go libraries should avoid using `panic`](https://go.dev/doc/effective_go#panic).
|
|
|
|
SafeJS provides a nearly identical API to `syscall/js`, but returns errors instead of panicking.
|
|
|
|
Although returned errors aren't pretty, they make it much easier to integrate with existing Go tools and code patterns.
|
|
|
|
#### Backward compatibility
|
|
|
|
This package uses the same backward compatibility guarantee as `syscall/js`.
|
|
|
|
In an effort to align with the Go standard library API, some breaking changes may become necessary and receive their own minor version bumps.
|
|
|
|
## Quick start
|
|
|
|
1. Import `safejs`:
|
|
```go
|
|
import "github.com/hack-pad/safejs"
|
|
```
|
|
2. Replace uses of `syscall/js` with the `safejs` alternative.
|
|
|
|
Before:
|
|
```go
|
|
//go:build js && wasm
|
|
|
|
package buttons
|
|
|
|
import "syscall/js"
|
|
|
|
// InsertButton creates a new button, adds it to 'container', and returns it. Usually.
|
|
func InsertButton(container js.Value) js.Value {
|
|
// *whisper:* There's a good chance it could panic! Eh, probably don't need to document it, right?
|
|
dom := js.Global().Get("document") // BOOM!
|
|
button := dom.Call("createElement", "button") // BANG!
|
|
container.Call("appendChild", button) // BAM!
|
|
return button
|
|
}
|
|
```
|
|
|
|
After:
|
|
```go
|
|
//go:build js && wasm
|
|
|
|
package buttons
|
|
|
|
import "github.com/hack-pad/safejs"
|
|
|
|
// InsertButton creates a new button, adds it to 'container', and returns the button or the first error.
|
|
func InsertButton(container safejs.Value) (safejs.Value, error) {
|
|
dom, err := safejs.Global().Get("document")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
button, err := dom.Call("createElement", "button")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = container.Call("appendChild", button)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return button, nil
|
|
}
|
|
```
|
|
|
|
## Even safer
|
|
|
|
For additional JavaScript safety, use the `jsguard` linter too.
|
|
|
|
`jsguard` reports the locations of unsafe JavaScript calls, which should be replaced with calls to SafeJS.
|
|
|
|
```bash
|
|
go install github.com/hack-pad/safejs/jsguard/cmd/jsguard
|
|
export GOOS=js GOARCH=wasm
|
|
jsguard ./...
|
|
```
|
|
|
|
It *does not* report use of types like `js.Value` -- only function calls on those types.
|
|
|
|
This makes it easy to integrate SafeJS into existing libraries which expose only standard library types.
|