Skip to content

feat: add WebAssembly build for browser-based VCL tooling#556

Open
acme wants to merge 13 commits intoysugimoto:mainfrom
acme:acme/add-wasm
Open

feat: add WebAssembly build for browser-based VCL tooling#556
acme wants to merge 13 commits intoysugimoto:mainfrom
acme:acme/add-wasm

Conversation

@acme
Copy link
Collaborator

@acme acme commented Feb 4, 2026

Compile Falco to WebAssembly, exposing a JavaScript API for VCL development in the browser.

  • New cmd/wasm/ package with entry point and API implementation

    • FalcoVCL.parse(vcl) parses VCL to AST
    • FalcoVCL.tokenize(vcl) tokenizes with semantic categories for syntax highlighting
    • FalcoVCL.format(vcl, options) formats with configurable options
    • FalcoVCL.lint(vcl, options) lints with scope-aware validation
  • Use https://github.com/dip-proto/go-pcre/tree/wasm for PCRE in both Go and Wasm

  • Makefile targets make wasm and make wasm_exec

  • Demo and tests

    • wasm/index.html interactive demo page
    • wasm/tests/ Vitest browser tests via Playwright
image

Compile Falco to WebAssembly, exposing a JavaScript API for VCL development in
the browser.

- New `cmd/wasm/` package with entry point and API implementation
  - `FalcoVCL.parse(vcl)` parses VCL to AST
  - `FalcoVCL.tokenize(vcl)` tokenizes with semantic categories for syntax
    highlighting
  - `FalcoVCL.format(vcl, options)` formats with configurable options
  - `FalcoVCL.lint(vcl, options)` lints with scope-aware validation

- Build-tagged regex validation splits PCRE dependency for Wasm compatibility
  - `linter/regex.go` uses PCRE for native builds
  - `linter/regex_wasm.go` uses Go's `regexp` for Wasm (documented limitations)

- Makefile targets `make wasm` and `make wasm_exec`

- Demo and tests
  - `wasm/index.html` interactive demo page
  - `wasm/tests/` Vitest browser tests via Playwright
@jedisct1
Copy link
Collaborator

jedisct1 commented Feb 4, 2026

Have you considered https://pkg.go.dev/go.arsenm.dev/pcre for PCRE ?

@acme
Copy link
Collaborator Author

acme commented Feb 4, 2026

Have you considered https://pkg.go.dev/go.arsenm.dev/pcre for PCRE ?

It looks like that depends on modernc.org/libc/, which won't work in Wasm?

cmd/wasm/api.go Outdated
errors = append(errors, LintError{
Severity: "error",
Message: l.FatalError.Error.Error(),
Line: 1,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't Fatal errors get a line/position?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So they can! 4648db0 implements that.

@jedisct1
Copy link
Collaborator

jedisct1 commented Feb 4, 2026

Have you considered https://pkg.go.dev/go.arsenm.dev/pcre for PCRE ?

It looks like that depends on modernc.org/libc/, which won't work in Wasm?

Indeed.

Maybe that package could work on Wasm with a minimal libc shim?

PCRE is a common requirement, so this would be very useful for Go and WebAssembly users in general, and it would also avoid an inconsistency between Falco running on Wasm and non-Wasm environments.

@jedisct1
Copy link
Collaborator

jedisct1 commented Feb 4, 2026

The CGO-free PCRE can work on WebAssembly: https://github.com/dip-proto/go-pcre/tree/wasm

acme added 2 commits February 4, 2026 13:32
- Replace `go.elara.ws/pcre` with `dip-proto/go-pcre` fork that supports
  js/wasm target
- Remove `regex_wasm.go` fallback that used Go's limited `regexp` package
- Consolidate into single `regex.go` without build tags
- Enables lookahead/lookbehind regex validation in browser environment
@acme
Copy link
Collaborator Author

acme commented Feb 4, 2026

The CGO-free PCRE can work on WebAssembly: https://github.com/dip-proto/go-pcre/tree/wasm

Nice! 0d5280b uses that instead.

wasm/README.md Outdated
Comment on lines 21 to 30
## Limitations

**Regex validation**: The native Falco CLI uses PCRE for regex validation, but PCRE's native code cannot run in WebAssembly. The Wasm build uses Go's standard `regexp` package instead, which lacks support for some PCRE features:

- Lookahead (`(?=...)`, `(?!...)`)
- Lookbehind (`(?<=...)`, `(?<!...)`)
- Atomic groups (`(?>...)`)
- Possessive quantifiers (`*+`, `++`, `?+`)

VCL patterns using these features will pass validation in the WASM build but may fail in production or when using the native CLI.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That section can be removed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, removed as part of fe56ea0

Copy link
Owner

@ysugimoto ysugimoto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking how we provide as wasm... and then this PR is great solution, thanks.

Probably we should release wasm binary at the same time with common binaries (should be done on another PR)

package linter

import (
regexp "go.elara.ws/pcre"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From discussion of #556 (comment), can we replace to github.com/dip-proto/go-pcre ?

modernc.org/memory v1.2.0 // indirect
)

replace go.elara.ws/pcre => github.com/dip-proto/go-pcre v0.0.0-20260204122309-dcbff9cb6240
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer we need replace section due to you have removed this package?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm not sure. I think we still need it as @jedisct1's fork identifies as go.elara.ws/pcre https://github.com/dip-proto/go-pcre/blob/wasm/go.mod#L1C8-L2C1 ?

}

function escapeHtml(str) {
return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To escape completely, I think we need to escape ' and " for HTML attribute also.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

79fa83c renames the function and adds a comment to make it clearer what it is escaping

acme added 3 commits February 11, 2026 14:06
- Clarify that the function only escapes characters needed for safe
  text node insertion, not attribute values
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants