wasmpack

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 29, 2026 License: MIT Imports: 16 Imported by: 0

README

wasmpack

test Release Go Report Card License

A CLI tool and Go library for building, optimizing, and packaging WebAssembly modules compiled from Go into a single JavaScript file. Supports self-executing IIFEs, ES modules, CommonJS modules, standalone HTML pages, and a live-reloading development server.

Features

  • Build Go → WASM — compiles any Go package with GOOS=js GOARCH=wasm
  • TinyGo support — compile with tinygo instead of the standard Go toolchain
  • Skip build step — pass a pre-compiled .wasm file to skip compilation
  • Compression — DEFLATE-compresses the binary before embedding (typically 60–80% smaller)
  • Four JS output formats — IIFE (.js), ESModule (.mjs), CommonJS (.cjs), standalone HTML (.html)
  • wasm-opt integration — optional Binaryen optimisation pass via wasm-opt
  • Garble support — optional Go build obfuscation via garble
  • JS obfuscation — powered by javascript-obfuscator (no Node.js required)
  • JS minification — built-in minifier, no external tools needed
  • Pre / post JS injection — prepend or append custom JS files
  • Live-reload dev server — watches source files, rebuilds on change, auto-refreshes the browser

Installation

go install github.com/malivvan/wasmpack/cmd@latest

Or use the library in your Go project:

go get github.com/malivvan/wasmpack

CLI usage

wasmpack init [path]

Write a default wasmpack.yml configuration file.

wasmpack init                  # creates ./wasmpack.yml
wasmpack init ./myproject      # creates ./myproject/wasmpack.yml
wasmpack init path/to/cfg.yml  # creates the file at the exact path
wasmpack pack [flags] <source> <destination>

Compile source and write the result to destination. Source — a Go package directory, a main.go file, or a pre-compiled .wasm file. When source ends with .wasm the build step is skipped entirely. Destination extensions control the output format:

Extension Output
.wasm Raw binary only (no JS wrapper)
.js Self-executing IIFE — runs immediately when the script is loaded
.mjs ES module that exports run(env, args)
.cjs CommonJS module that exports run(env, args)
.html Minimal HTML page with the IIFE in a <script defer> tag

Pack flags:

Flag Description
-garble Obfuscate the Go build with garble (options from wasmpack.yml)
-tinygo Compile with tinygo instead of go (options from wasmpack.yml)
-wasm-opt Optimise the wasm binary with wasm-opt (options from wasmpack.yml)
-minify Minify the JS output
-obfuscate Obfuscate the JS output (options from wasmpack.yml)
wasmpack pack ./sample output.html             # standalone HTML page
wasmpack pack ./sample output.js              # self-executing IIFE bundle
wasmpack pack ./sample output.mjs             # ES module
wasmpack pack ./sample output.cjs             # CommonJS module
wasmpack pack ./sample output.wasm            # raw binary only
wasmpack pack compiled.wasm output.js         # skip compilation, use pre-built .wasm
wasmpack pack -tinygo ./sample output.js      # compile with tinygo
wasmpack pack -wasm-opt -minify ./sample out.js  # wasm-opt + minified JS

Example output:

  build      2.41 MB  (0.89s)
  wrap       html
  write      output.html  2.41 MB → 0.89 MB  (37.0%)
  done       1.12s
wasmpack dev [flags] <source> <addr>

Start a live-reloading development server.

Dev flags:

Flag Description
-coi Set Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp headers, enabling a cross-origin isolated context (required for SharedArrayBuffer / Atomics)
wasmpack dev ./sample :8080            # all interfaces, port 8080
wasmpack dev ./sample localhost:3000   # loopback only
wasmpack dev compiled.wasm :9000       # serve pre-built wasm, watch for changes
wasmpack dev -coi ./sample :8080       # enable cross-origin isolation

Example output:

  build      2.41 MB  (0.89s)
  watch      /home/user/project/sample
  serve      http://localhost:8080
  · main.go changed
  build      2.41 MB  (0.34s)
  reload     1 client(s)

The server:

  • Builds and serves a self-contained HTML page at /
  • Watches all .go files in the source directory (or the .wasm file) for changes
  • Rebuilds automatically on change and reloads connected browsers via SSE
  • Skips wasm-opt, garble, tinygo, obfuscation, and minification for fast iteration

Configuration (wasmpack.yml)

wasmpack.yml is discovered by walking up from the current working directory — the same mechanism Go uses for go.mod. Run wasmpack init to generate a documented template.

# wasm-opt: options for wasm-opt (used when -wasm-opt flag is passed to pack)
# garble:    options for garble (used when -garble flag is passed to pack)
# tinygo:    options for tinygo (used when -tinygo flag is passed to pack)
# pre:       path to a JS file prepended to the output
# post:      path to a JS file appended to the output
# obfuscate: javascript-obfuscator options (used when -obfuscate flag is passed to pack)
#            see https://github.com/javascript-obfuscator/javascript-obfuscator
pre: ""
post: ""
garble:
  seed: ""       # randomness seed (-seed)
  literals: false # obfuscate string literals (-literals)
  tiny: false    # smaller output (-tiny)
  flags: ""      # extra space-separated garble flags
tinygo:
  target: "wasm" # compile target (e.g. "wasm", "wasi")
  opt: ""        # optimization level (none, 0, 1, 2, s, z)
  flags: ""      # extra space-separated tinygo flags
wasm-opt:
  level: "O2"    # optimization level (O1, O2, O3, O4, Os)
  flags: ""      # extra space-separated wasm-opt flags
obfuscate:
  compact: true
  controlFlowFlattening: false
  # ... all javascript-obfuscator options supported
  # see https://github.com/javascript-obfuscator/javascript-obfuscator

Go library API

import "github.com/malivvan/wasmpack"

// Compile a Go package to raw WASM bytes.
// useGarble and useTinygo are mutually exclusive; useGarble takes precedence.
wasm, err := wasmpack.Build(
    "./mypkg",
    useGarble, wasmpack.GarbleConfig{Literals: true},
    useTinygo, wasmpack.TinygoConfig{Target: "wasm"},
    useWasmOpt, wasmpack.WasmOptConfig{Level: "O2"},
)

// Compress + encode the WASM binary into a JS inflate snippet.
packed, err := wasmpack.Pack(wasm)

// Wrap in wasm_exec.js as a self-executing IIFE.
js, err := wasmpack.WrapIIFE(packed)
// Wrap as an ES module exporting run(env, args).
js, err := wasmpack.WrapESM(packed)
// Wrap as a CommonJS module exporting run(env, args).
js, err := wasmpack.WrapCJS(packed)
// Wrap inside a minimal HTML page (IIFE in <script defer>).
html, err := wasmpack.WrapHTML(packed)

// Run wasm-opt on a WASM file in-place.
err = wasmpack.WasmOpt("/path/to/file.wasm", []string{"-O2"})

// Obfuscate JS (no Node.js required).
out, err := wasmpack.Obfuscate(js, "-controlFlowFlattening")
out, err := wasmpack.ObfuscateWithOptions(js, options)
// Parse obfuscate flag string to options map.
opts, err := wasmpack.ParseObfuscateOptions("-controlFlowFlattening -compact=false")

// Minify JS.
out, err := wasmpack.Minify(js)

// Config helpers.
cfg  := wasmpack.DefaultConfig()
path, err := wasmpack.FindConfig(".")     // walk-up search
cfg,  err  = wasmpack.LoadConfig(path)
err        = wasmpack.WriteDefaultConfig(path)

Output size

DEFLATE compression typically achieves a 60–80% reduction before wrapping:

  write    output.js  5.23 MB → 1.45 MB  (27.7%)

Requirements

Sample project

sample/main.go prints Hello, World! to the browser console.

# Live-reload dev server
wasmpack dev ./sample :8080
# Build a standalone HTML page
wasmpack pack ./sample sample/output.html

Documentation

Index

Constants

View Source
const ConfigFileName = "wasmpack.yml"

ConfigFileName is the name of the wasmpack configuration file.

Variables

This section is empty.

Functions

func Build

func Build(path string, useGarble bool, garbleCfg GarbleConfig, useTinygo bool, tinygoCfg TinygoConfig, useWasmOpt bool, wasmOptCfg WasmOptConfig) ([]byte, error)

Build compiles the Go package at path into a WebAssembly binary and returns the raw bytes. The binary is written to a temp file, optionally optimised with wasm-opt, read back, and then removed.

When useGarble is true the build is performed via garble using garbleCfg. When useTinygo is true the build is performed via tinygo using tinygoCfg. useGarble and useTinygo are mutually exclusive; useGarble takes precedence. When useWasmOpt is true the wasm binary is optimised via wasm-opt using wasmOptCfg.

func FindConfig added in v1.0.0

func FindConfig(startDir string) (string, error)

FindConfig searches for a wasmpack.yml file starting from startDir and walking up to the filesystem root, like go.mod discovery. Returns an empty string if no config file is found.

func Minify

func Minify(b []byte) ([]byte, error)

Minify takes a JavaScript source code as a byte slice and returns a minified version of it. It removes unnecessary whitespace and comments while preserving the functionality of the code.

func Obfuscate added in v1.0.0

func Obfuscate(js []byte, args string) ([]byte, error)

Obfuscate obfuscates js using options parsed from a flag-style args string. Example args: "-controlFlowFlattening -compact=false"

func ObfuscateWithOptions added in v1.0.0

func ObfuscateWithOptions(js []byte, options map[string]any) ([]byte, error)

ObfuscateWithOptions obfuscates js using the provided options map. Use ParseObfuscateOptions or ObfuscateConfig.ToOptions to build the map.

func Pack

func Pack(wasm []byte) ([]byte, error)

Pack takes the wasm bytes, compresses them using the deflate algorithm, and returns a JavaScript snippet that inflates the compressed bytes and returns them as an Uint8Array.

func ParseObfuscateOptions added in v1.0.0

func ParseObfuscateOptions(args string) (map[string]any, error)

ParseObfuscateOptions parses a flag-style argument string into a javascript-obfuscator options map. Example: "-controlFlowFlattening -compact=false"

func WasmOpt added in v1.0.0

func WasmOpt(path string, flags []string) error

WasmOpt runs wasm-opt on the wasm file at path with the given flag slice, writing the result back to the same path. Example flags: []string{"-O2"}, []string{"-O4", "--enable-simd"}.

func Wrap

func Wrap(name string, wasm []byte) ([]byte, error)

Wrap takes the wasm_exec.js file from the go installation and wraps the packed wasm bytes in it, returning the resulting JavaScript code. If name is not empty, instead of running the wasm immediately it will be assigned to a global function with the provided name that can be called with an optional env object and args array.

func WrapCJS added in v1.0.0

func WrapCJS(packed []byte) ([]byte, error)

WrapCJS wraps the packed wasm bytes in wasm_exec.js as a CommonJS module. The module exports a single `run(env, args)` function that instantiates and starts the WebAssembly module, returning a Promise. packed is the JavaScript expression returned by Pack.

func WrapESM added in v1.0.0

func WrapESM(packed []byte) ([]byte, error)

WrapESM wraps the packed wasm bytes in wasm_exec.js as an ES module. The module exports a single `run(env, args)` function that instantiates and starts the WebAssembly module, returning a Promise. packed is the JavaScript expression returned by Pack.

func WrapHTML added in v1.0.0

func WrapHTML(packed []byte) ([]byte, error)

WrapHTML wraps the packed wasm IIFE inside a minimal HTML page. The <script> tag uses defer so it executes after HTML is parsed. packed is the JavaScript expression returned by Pack.

func WrapIIFE added in v1.0.0

func WrapIIFE(packed []byte) ([]byte, error)

WrapIIFE wraps the packed wasm bytes in wasm_exec.js as a self-executing IIFE. The WebAssembly module starts running as soon as the script is loaded. packed is the JavaScript expression returned by Pack.

func WriteDefaultConfig added in v1.0.0

func WriteDefaultConfig(path string) error

WriteDefaultConfig writes a commented default wasmpack.yml to path.

Types

type Config added in v1.0.0

type Config struct {
	Pre       string          `yaml:"pre"`
	Post      string          `yaml:"post"`
	Garble    GarbleConfig    `yaml:"garble"`
	Tinygo    TinygoConfig    `yaml:"tinygo"`
	WasmOpt   WasmOptConfig   `yaml:"wasm-opt"`
	Obfuscate ObfuscateConfig `yaml:"obfuscate"`
}

Config holds all wasmpack project configuration.

func DefaultConfig added in v1.0.0

func DefaultConfig() *Config

DefaultConfig returns a Config populated with sensible defaults.

func LoadConfig added in v1.0.0

func LoadConfig(path string) (*Config, error)

LoadConfig reads and parses a wasmpack.yml file. Fields not present in the file keep their DefaultConfig values.

type GarbleConfig added in v1.0.0

type GarbleConfig struct {
	Seed     string `yaml:"seed"`     // randomness seed (-seed)
	Literals bool   `yaml:"literals"` // obfuscate string literals (-literals)
	Tiny     bool   `yaml:"tiny"`     // smaller output (-tiny)
	Flags    string `yaml:"flags"`    // extra space-separated garble flags
}

GarbleConfig holds options passed to the garble build tool.

func (GarbleConfig) ToArgs added in v1.0.0

func (g GarbleConfig) ToArgs() []string

ToArgs converts the GarbleConfig into a slice of garble flag strings.

type ObfuscateConfig added in v1.0.0

type ObfuscateConfig struct {
	Compact                               bool              `yaml:"compact"`
	ControlFlowFlattening                 bool              `yaml:"controlFlowFlattening"`
	ControlFlowFlatteningThreshold        float64           `yaml:"controlFlowFlatteningThreshold"`
	DeadCodeInjection                     bool              `yaml:"deadCodeInjection"`
	DeadCodeInjectionThreshold            float64           `yaml:"deadCodeInjectionThreshold"`
	DebugProtection                       bool              `yaml:"debugProtection"`
	DebugProtectionInterval               int               `yaml:"debugProtectionInterval"`
	DisableConsoleOutput                  bool              `yaml:"disableConsoleOutput"`
	DomainLock                            []string          `yaml:"domainLock"`
	DomainLockRedirectURL                 string            `yaml:"domainLockRedirectURL"`
	Exclude                               []string          `yaml:"exclude"`
	ForceTransformStrings                 []string          `yaml:"forceTransformStrings"`
	IdentifierNamesCache                  map[string]string `yaml:"identifierNamesCache"`
	IdentifierNamesGenerator              string            `yaml:"identifierNamesGenerator"`
	IdentifiersDictionary                 []string          `yaml:"identifiersDictionary"`
	IdentifiersPrefix                     string            `yaml:"identifiersPrefix"`
	IgnoreImports                         bool              `yaml:"ignoreImports"`
	InputFileName                         string            `yaml:"inputFileName"`
	Log                                   bool              `yaml:"log"`
	NumbersToExpressions                  bool              `yaml:"numbersToExpressions"`
	OptionsPreset                         string            `yaml:"optionsPreset"`
	RenameGlobals                         bool              `yaml:"renameGlobals"`
	RenameProperties                      bool              `yaml:"renameProperties"`
	RenamePropertiesMode                  string            `yaml:"renamePropertiesMode"`
	ReservedNames                         []string          `yaml:"reservedNames"`
	ReservedStrings                       []string          `yaml:"reservedStrings"`
	Seed                                  string            `yaml:"seed"`
	SelfDefending                         bool              `yaml:"selfDefending"`
	Simplify                              bool              `yaml:"simplify"`
	SourceMap                             bool              `yaml:"sourceMap"`
	SourceMapBaseURL                      string            `yaml:"sourceMapBaseURL"`
	SourceMapFileName                     string            `yaml:"sourceMapFileName"`
	SourceMapMode                         string            `yaml:"sourceMapMode"`
	SplitStrings                          bool              `yaml:"splitStrings"`
	SplitStringsChunkLength               int               `yaml:"splitStringsChunkLength"`
	StringArray                           bool              `yaml:"stringArray"`
	StringArrayCallsTransform             bool              `yaml:"stringArrayCallsTransform"`
	StringArrayCallsTransformThreshold    float64           `yaml:"stringArrayCallsTransformThreshold"`
	StringArrayEncoding                   []string          `yaml:"stringArrayEncoding"`
	StringArrayIndexesType                []string          `yaml:"stringArrayIndexesType"`
	StringArrayIndexShift                 bool              `yaml:"stringArrayIndexShift"`
	StringArrayRotate                     bool              `yaml:"stringArrayRotate"`
	StringArrayShuffle                    bool              `yaml:"stringArrayShuffle"`
	StringArrayWrappersCount              int               `yaml:"stringArrayWrappersCount"`
	StringArrayWrappersChainedCalls       bool              `yaml:"stringArrayWrappersChainedCalls"`
	StringArrayWrappersParametersMaxCount int               `yaml:"stringArrayWrappersParametersMaxCount"`
	StringArrayWrappersType               string            `yaml:"stringArrayWrappersType"`
	StringArrayThreshold                  float64           `yaml:"stringArrayThreshold"`
	Target                                string            `yaml:"target"`
	TransformObjectKeys                   bool              `yaml:"transformObjectKeys"`
	UnicodeEscapeSequence                 bool              `yaml:"unicodeEscapeSequence"`
}

ObfuscateConfig holds all javascript-obfuscator options.

func (*ObfuscateConfig) ToOptions added in v1.0.0

func (c *ObfuscateConfig) ToOptions() map[string]any

ToOptions converts the ObfuscateConfig into the options map consumed by the javascript-obfuscator engine.

type TinygoConfig added in v1.0.0

type TinygoConfig struct {
	Target string `yaml:"target"` // compile target (e.g. "wasm", "wasi")
	Opt    string `yaml:"opt"`    // optimization level (none, 0, 1, 2, s, z)
	Flags  string `yaml:"flags"`  // extra space-separated tinygo flags
}

TinygoConfig holds options passed to the tinygo compiler.

func (TinygoConfig) ToArgs added in v1.0.0

func (t TinygoConfig) ToArgs() []string

ToArgs converts the TinygoConfig into a slice of tinygo flag strings.

type WasmOptConfig added in v1.0.0

type WasmOptConfig struct {
	Level string `yaml:"level"` // optimization level (O1, O2, O3, O4, Os)
	Flags string `yaml:"flags"` // extra space-separated wasm-opt flags
}

WasmOptConfig holds options passed to the wasm-opt tool.

func (WasmOptConfig) ToArgs added in v1.0.0

func (o WasmOptConfig) ToArgs() []string

ToArgs converts the WasmOptConfig into a slice of wasm-opt flag strings.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL