Conversation
🦋 Changeset detectedLatest commit: c6e6781 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
| // Create and return the Promise object | ||
| promiseConstructor := js.Global().Get("Promise") | ||
| return promiseConstructor.New(handler) |
There was a problem hiding this comment.
Small refactor to return a Promise from transform.
cmd/astro-wasm/astro-wasm.go
Outdated
| // Hoist styles and scripts to the top-level | ||
| transform.ExtractScriptsAndStyles(doc) |
There was a problem hiding this comment.
Main difference here is that we're splitting up the transform step into preprocessing and postprocessing.
cmd/astro-wasm/astro-wasm.go
Outdated
| // Pre-process styles | ||
| // Important! These goroutines need to be spawned from this file or they don't work | ||
| var wg sync.WaitGroup | ||
| if len(doc.Styles) > 0 { | ||
| if transformOptions.PreprocessStyle.IsUndefined() != true { | ||
| for i, style := range doc.Styles { | ||
| wg.Add(1) | ||
| i := i | ||
| go preprocessStyle(i, style, transformOptions, wg.Done) | ||
| } | ||
| } | ||
| } | ||
| // Wait for all the style goroutines to finish | ||
| wg.Wait() |
There was a problem hiding this comment.
This spawns workers that run the async preprocessStyle functions and waits until they are all complete to continue.
There was a problem hiding this comment.
Note that this is the preprocessStyle function in Go which has a different signature. It safely invokes the JS preprocessStyle.
cmd/astro-wasm/astro-wasm.go
Outdated
| // Perform CSS and element scoping as needed | ||
| transform.Transform(doc, transformOptions) |
There was a problem hiding this comment.
At this point, our CSS is (presumably) actually CSS and we can scope it!
internal/transform/utils.go
Outdated
| func GetAttrs(n *astro.Node) js.Value { | ||
| attrs := js.Global().Get("Object").New() | ||
| for _, attr := range n.Attr { | ||
| switch attr.Type { | ||
| case astro.QuotedAttribute: | ||
| attrs.Set(attr.Key, attr.Val) | ||
| case astro.EmptyAttribute: | ||
| attrs.Set(attr.Key, true) | ||
| } | ||
| } | ||
| return attrs | ||
| } |
There was a problem hiding this comment.
This function returns compile-time known attributes as a JS object, which can then be passed to the preprocessors.
| // See https://stackoverflow.com/questions/68426700/how-to-wait-a-js-async-function-from-golang-wasm | ||
| func Await(awaitable js.Value) ([]js.Value, []js.Value) { | ||
| then := make(chan []js.Value) | ||
| defer close(then) | ||
| thenFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} { | ||
| then <- args | ||
| return nil | ||
| }) | ||
| defer thenFunc.Release() | ||
|
|
||
| catch := make(chan []js.Value) | ||
| defer close(catch) | ||
| catchFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} { | ||
| catch <- args | ||
| return nil | ||
| }) | ||
| defer catchFunc.Release() | ||
|
|
||
| awaitable.Call("then", thenFunc).Call("catch", catchFunc) | ||
|
|
||
| select { | ||
| case result := <-then: | ||
| return result, nil | ||
| case err := <-catch: | ||
| return nil, err | ||
| } | ||
| } |
There was a problem hiding this comment.
This is some magic I don't fully understand, borrowed from StackOverflow. But it works the same as await in JS!
There was a problem hiding this comment.
lol I'm both scared and thrilled!
lib/compiler/shared/types.ts
Outdated
| sourcefile?: string; | ||
| sourcemap?: boolean | 'inline' | 'external' | 'both'; | ||
| as?: 'document'|'fragment'; | ||
| preprocessStyle: (content: string, attrs: Record<string, string>) => Promise<string> |
There was a problem hiding this comment.
That's it, that's the feature!
lib/compiler/test.js
Outdated
| preprocessStyle: async (value, attrs) => { | ||
| let x = i++; | ||
| if (!attrs.lang) { | ||
| return null; | ||
| } | ||
| console.log(`Starting to preprocess style ${x} as ${attrs.lang}`); | ||
| await sleep(3000); | ||
| console.log(`Finished preprocessing ${x}`); | ||
| return value.replace('color', 'background'); |
There was a problem hiding this comment.
Should be very straightforward.
preprocessStyle is an async function that gets the contents of the style element and any compile-time known attrs (we only care about lang now, but maybe others in the future!)
Simulating some expensive work with sleep here.
|
I'll leave for others to review, but if this works and we understand how it works, then this sounds super cool! |
|
The CI error makes me worried that this is using something not supported by tinygo but I presume this was tested against using tinygo, right? I which case I don't know what that error is about... Anyways, clever approach, I hope it works out! |
bfcedb0 to
c87e08a
Compare
| "GOOS": "js", | ||
| "GOARCH": "wasm", |
There was a problem hiding this comment.
Ayyyy no more VS Code warnings for using WASM
| func preprocessStyle(i int, style *astro.Node, transformOptions transform.TransformOptions, cb func()) { | ||
| defer cb() | ||
| attrs := wasm_utils.GetAttrs(style) | ||
| data, _ := wasm_utils.Await(transformOptions.PreprocessStyle.(js.Value).Invoke(style.FirstChild.Data, attrs)) |
There was a problem hiding this comment.
This took me a bit to figure out. PreprocessStyle is typed as interface{} which is very similar to TypeScript's any (but a little more strict). The transformOptions.PreprocessStyle.(js.Value) part casts the type as js.Value so we can access methods on that type.
| @@ -0,0 +1,48 @@ | |||
| package wasm_utils | |||
There was a problem hiding this comment.
Moved all of the wasm_utils to their own internal_wasm directory because we can't test them directly (easily, at least)
|
lgtm |
09d5897 to
c6e6781
Compare
Changes
preprocessStylefunction to the compiler to preprocess styles.Currently, this function has to be sync becauseasyncin Go turns out to be pretty weird. I tried.Here are some handy Go + WASM resources specifically around Promises (that may or may not be useful)
Testing
We don't have automatic WASM tests yet, but we should think about adding them!
Docs
N/A