diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 5db1baae..54d18182 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -229,7 +229,7 @@ }, "//wasm:extensions.bzl%cpp_component": { "general": { - "bzlTransitiveDigest": "YU7JsTXFs8hEATBVVvSVGFzGeR0TTteNnCcfeBreyXM=", + "bzlTransitiveDigest": "gurbwZbcu7kpgIR1CGsEp6ijFk4u9LAKHSURX4+iT8k=", "usagesDigest": "60f0O3+qNo5tYrXjypa0YLZBtNMmSOws3xIOdJkff/0=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, @@ -254,7 +254,7 @@ }, "//wasm:extensions.bzl%jco": { "general": { - "bzlTransitiveDigest": "YU7JsTXFs8hEATBVVvSVGFzGeR0TTteNnCcfeBreyXM=", + "bzlTransitiveDigest": "gurbwZbcu7kpgIR1CGsEp6ijFk4u9LAKHSURX4+iT8k=", "usagesDigest": "PQqUinjtsk87/5n7cHDUYhpglImiMDMUgHdoZs4aVNg=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, @@ -279,7 +279,7 @@ }, "//wasm:extensions.bzl%tinygo": { "general": { - "bzlTransitiveDigest": "YU7JsTXFs8hEATBVVvSVGFzGeR0TTteNnCcfeBreyXM=", + "bzlTransitiveDigest": "gurbwZbcu7kpgIR1CGsEp6ijFk4u9LAKHSURX4+iT8k=", "usagesDigest": "tE5hZWIXf+a1hThQOIcRRVjPbVQjFDb2aj5a1eEhvaA=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, @@ -303,7 +303,7 @@ }, "//wasm:extensions.bzl%wasi_sdk": { "general": { - "bzlTransitiveDigest": "YU7JsTXFs8hEATBVVvSVGFzGeR0TTteNnCcfeBreyXM=", + "bzlTransitiveDigest": "gurbwZbcu7kpgIR1CGsEp6ijFk4u9LAKHSURX4+iT8k=", "usagesDigest": "RoedjSblpjIxlcUjWjhz1L4mn2x/vCtO1RtPL64VguE=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, @@ -490,7 +490,7 @@ }, "//wasm:extensions.bzl%wasm_toolchain": { "general": { - "bzlTransitiveDigest": "YU7JsTXFs8hEATBVVvSVGFzGeR0TTteNnCcfeBreyXM=", + "bzlTransitiveDigest": "gurbwZbcu7kpgIR1CGsEp6ijFk4u9LAKHSURX4+iT8k=", "usagesDigest": "j2w0KsG/e6tltUI+WAeNH505251eBn4uleGJW2ExVag=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, @@ -524,7 +524,7 @@ }, "//wasm:extensions.bzl%wasmtime": { "general": { - "bzlTransitiveDigest": "YU7JsTXFs8hEATBVVvSVGFzGeR0TTteNnCcfeBreyXM=", + "bzlTransitiveDigest": "gurbwZbcu7kpgIR1CGsEp6ijFk4u9LAKHSURX4+iT8k=", "usagesDigest": "s1jIaDZbU9PAsYZLH9PgXwfrefil+sn/XLcVn/P9Q6U=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, @@ -549,7 +549,7 @@ }, "//wasm:extensions.bzl%wizer": { "general": { - "bzlTransitiveDigest": "YU7JsTXFs8hEATBVVvSVGFzGeR0TTteNnCcfeBreyXM=", + "bzlTransitiveDigest": "gurbwZbcu7kpgIR1CGsEp6ijFk4u9LAKHSURX4+iT8k=", "usagesDigest": "6/Tf087fjdhszmx0SYaOq709EsMncT4yVq6Sh711KFo=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, @@ -574,7 +574,7 @@ }, "//wasm:extensions.bzl%wkg": { "general": { - "bzlTransitiveDigest": "YU7JsTXFs8hEATBVVvSVGFzGeR0TTteNnCcfeBreyXM=", + "bzlTransitiveDigest": "gurbwZbcu7kpgIR1CGsEp6ijFk4u9LAKHSURX4+iT8k=", "usagesDigest": "mH3SUo8xNuIm+C21hj2zQVuSslC4w2RVQ5JRqzScS24=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, diff --git a/cpp/defs.bzl b/cpp/defs.bzl index 095ae61b..2e41feaa 100644 --- a/cpp/defs.bzl +++ b/cpp/defs.bzl @@ -25,11 +25,25 @@ def _cpp_component_impl(ctx): headers = ctx.files.hdrs wit_file = ctx.file.wit - # Collect dependency headers + # Collect dependency headers and libraries using CcInfo provider dep_headers = [] dep_libraries = [] + dep_includes = [] + for dep in ctx.attr.deps: - if DefaultInfo in dep: + if CcInfo in dep: + # Use proper CcInfo provider for header and library information + cc_info = dep[CcInfo] + dep_headers.extend(cc_info.compilation_context.headers.to_list()) + dep_includes.extend(cc_info.compilation_context.includes.to_list()) + + # Extract static libraries from linking context + for linker_input in cc_info.linking_context.linker_inputs.to_list(): + for library in linker_input.libraries: + if library.static_library: + dep_libraries.append(library.static_library) + elif DefaultInfo in dep: + # Fallback for non-CcInfo dependencies (e.g., legacy rules) for file in dep[DefaultInfo].files.to_list(): if file.extension in ["h", "hpp", "hh", "hxx"]: dep_headers.append(file) @@ -74,7 +88,23 @@ def _cpp_component_impl(ctx): # Basic compiler flags for Preview2 compile_args.add("--target=wasm32-wasip2") - compile_args.add("--sysroot=" + sysroot) + + # Build sysroot path from toolchain repository for external compatibility + if sysroot_files and sysroot_files.files: + # Use sysroot_files to determine the actual sysroot directory + toolchain_file = sysroot_files.files.to_list()[0] + + # Extract the sysroot directory by removing the file component + if "/sysroot/" in toolchain_file.path: + # Get everything up to and including /sysroot/ + sysroot_base = toolchain_file.path.split("/sysroot/")[0] + "/sysroot" + sysroot_path = sysroot_base + else: + sysroot_path = sysroot + else: + sysroot_path = sysroot + + compile_args.add("--sysroot=" + sysroot_path) # Component model definitions compile_args.add("-D_WASI_EMULATED_PROCESS_CLOCKS") @@ -109,19 +139,34 @@ def _cpp_component_impl(ctx): # Include directories compile_args.add("-I" + work_dir.path) - + # Add C++ standard library paths for wasm32-wasip2 target if ctx.attr.language == "cpp": - compile_args.add("-I" + sysroot + "/include/wasm32-wasip2/c++/v1") - compile_args.add("-I" + sysroot + "/include/c++/v1") - + # WASI SDK stores C++ headers in share/wasi-sysroot, not just sysroot + if "/external/" in sysroot_path: + toolchain_repo = sysroot_path.split("/sysroot")[0] + wasi_sysroot = toolchain_repo + "/share/wasi-sysroot" + else: + wasi_sysroot = sysroot_path + compile_args.add("-I" + wasi_sysroot + "/include/wasm32-wasip2/c++/v1") + compile_args.add("-I" + wasi_sysroot + "/include/c++/v1") + + # Also add clang's builtin headers + if "/external/" in sysroot_path: + compile_args.add("-I" + toolchain_repo + "/lib/clang/20/include") + for include in ctx.attr.includes: compile_args.add("-I" + include) - # Add dependency header directories + # Add dependency include directories from CcInfo + for include_dir in dep_includes: + if include_dir not in [work_dir.path] + ctx.attr.includes: + compile_args.add("-I" + include_dir) + + # Add dependency header directories (fallback for non-CcInfo deps) for dep_hdr in dep_headers: include_dir = dep_hdr.dirname - if include_dir not in [work_dir.path] + ctx.attr.includes: + if include_dir not in [work_dir.path] + ctx.attr.includes + dep_includes: compile_args.add("-I" + include_dir) # Defines @@ -400,7 +445,17 @@ def _cc_component_library_impl(ctx): # Compile arguments compile_args = ctx.actions.args() compile_args.add("--target=wasm32-wasip2") - compile_args.add("--sysroot=" + sysroot) + + # Resolve sysroot path dynamically for external repository compatibility + if sysroot_files and sysroot_files.files: + toolchain_file = sysroot_files.files.to_list()[0] + if "/sysroot/" in toolchain_file.path: + sysroot_dir = toolchain_file.path.split("/sysroot/")[0] + "/sysroot" + else: + sysroot_dir = sysroot + else: + sysroot_dir = sysroot + compile_args.add("--sysroot=" + sysroot_dir) compile_args.add("-c") # Compile only, don't link # Component model definitions @@ -431,12 +486,22 @@ def _cc_component_library_impl(ctx): # Include directories for hdr in ctx.files.hdrs: compile_args.add("-I" + hdr.dirname) - + # Add C++ standard library paths for wasm32-wasip2 target if ctx.attr.language == "cpp": - compile_args.add("-I" + sysroot + "/include/wasm32-wasip2/c++/v1") - compile_args.add("-I" + sysroot + "/include/c++/v1") - + # WASI SDK stores C++ headers in share/wasi-sysroot, not just sysroot + if "/external/" in sysroot_dir: + toolchain_repo = sysroot_dir.split("/sysroot")[0] + wasi_sysroot = toolchain_repo + "/share/wasi-sysroot" + else: + wasi_sysroot = sysroot_dir + compile_args.add("-I" + wasi_sysroot + "/include/wasm32-wasip2/c++/v1") + compile_args.add("-I" + wasi_sysroot + "/include/c++/v1") + + # Also add clang's builtin headers + if "/external/" in sysroot_dir: + compile_args.add("-I" + toolchain_repo + "/lib/clang/20/include") + for include in ctx.attr.includes: compile_args.add("-I" + include) @@ -480,8 +545,33 @@ def _cc_component_library_impl(ctx): progress_message = "Creating component library %s" % ctx.label, ) + # Collect transitive headers and libraries from dependencies + transitive_headers = [] + transitive_libraries = [] + transitive_includes = [] + + for dep in ctx.attr.deps: + if CcInfo in dep: + cc_info = dep[CcInfo] + transitive_headers.append(cc_info.compilation_context.headers) + transitive_includes.extend(cc_info.compilation_context.includes.to_list()) + transitive_libraries.append(cc_info.linking_context.linker_inputs) + + # Create compilation context with current headers and transitive headers + compilation_context = cc_common.create_compilation_context( + headers = depset(ctx.files.hdrs, transitive = transitive_headers), + includes = depset([h.dirname for h in ctx.files.hdrs] + ctx.attr.includes, transitive = [depset(transitive_includes)]), + ) + + # Create CcInfo provider with compilation context only + # Note: We don't create linking context since we're using custom WASM toolchain + cc_info = CcInfo( + compilation_context = compilation_context, + ) + return [ DefaultInfo(files = depset([library] + ctx.files.hdrs)), + cc_info, OutputGroupInfo( library = depset([library]), objects = depset(object_files), diff --git a/docs-site/astro.config.mjs b/docs-site/astro.config.mjs index e454389a..675764dc 100644 --- a/docs-site/astro.config.mjs +++ b/docs-site/astro.config.mjs @@ -23,7 +23,16 @@ export default defineConfig({ expressiveCode: { themes: ['github-dark', 'github-light'], // Map languages for better syntax highlighting - langs: ['python', 'rust', 'go', 'javascript', 'typescript', 'bash', 'yaml', 'json', 'dockerfile', 'starlark'] + langs: ['python', 'rust', 'go', 'javascript', 'typescript', 'bash', 'yaml', 'json', 'dockerfile'], + // Use Python grammar for Starlark since Starlark syntax is a subset of Python + shiki: { + langAlias: { + 'starlark': 'python', + 'star': 'python', + 'bzl': 'python', + 'bazel': 'python' + } + } }, social: [ { @@ -79,6 +88,9 @@ export default defineConfig({ label: 'Examples', items: [ { label: 'Basic Component', slug: 'examples/basic' }, + { label: 'Calculator (C++)', slug: 'examples/calculator' }, + { label: 'HTTP Service (Go)', slug: 'examples/http-service' }, + { label: 'Multi-Language System', slug: 'examples/multi-language' }, ], }, { @@ -98,6 +110,8 @@ export default defineConfig({ label: 'Production', items: [ { label: 'Deployment Guide', slug: 'production/deployment-guide' }, + { label: 'OCI Publishing', slug: 'production/publishing' }, + { label: 'Performance Optimization', slug: 'production/performance' }, ], }, { diff --git a/docs-site/docs_dev.bzl b/docs-site/docs_dev.bzl new file mode 100644 index 00000000..c337d925 --- /dev/null +++ b/docs-site/docs_dev.bzl @@ -0,0 +1,125 @@ +"""Bazel rule for running documentation development server with live reload""" + +def _docs_dev_server_impl(ctx): + """Implementation of docs_dev_server rule for local development""" + + # Get jco toolchain for hermetic Node.js access + jco_toolchain = ctx.toolchains["@rules_wasm_component//toolchains:jco_toolchain_type"] + node = jco_toolchain.node + npm = jco_toolchain.npm + + # Create runner script + runner = ctx.actions.declare_file(ctx.attr.name + "_runner.sh") + + # Input source files and package.json + source_files = ctx.files.srcs + package_json = ctx.file.package_json + + # Prepare source file list + source_paths = [] + for src in source_files: + if src.path.startswith("docs-site/"): + source_paths.append(src.path) + + ctx.actions.write( + output = runner, + content = """#!/bin/bash +set -euo pipefail + +# Store paths +EXEC_ROOT="$(pwd)" +PACKAGE_JSON="{package_json}" +NODE="{node}" +NPM="{npm}" + +# Create temporary workspace +WORK_DIR="$(mktemp -d)" +echo "πŸš€ Setting up documentation development server in: $WORK_DIR" + +# Cleanup on exit +trap "echo 'πŸ›‘ Shutting down dev server...'; rm -rf $WORK_DIR" EXIT + +# Copy package.json +cp "$PACKAGE_JSON" "$WORK_DIR/package.json" + +# Copy all source files +echo "πŸ“¦ Copying source files..." +{copy_commands} + +# Change to workspace +cd "$WORK_DIR" + +# Install dependencies +echo "πŸ“₯ Installing dependencies..." +$NPM install --no-audit --no-fund + +# Start development server +echo "🌐 Starting Astro development server..." +echo "πŸ“ Documentation will be available at: http://localhost:4321" +echo "" +echo "Press Ctrl+C to stop the server" +echo "" + +# Run dev server +$NPM run dev +""".format( + package_json = package_json.path, + node = node.path, + npm = npm.path, + copy_commands = "\n".join([ + 'if [[ "{src}" == docs-site/* ]]; then\n' + + ' rel_path="${{src#docs-site/}}"\n'.format(src=src) + + ' dest_file="$WORK_DIR/$rel_path"\n' + + ' dest_dir="$(dirname "$dest_file")"\n' + + ' mkdir -p "$dest_dir"\n' + + ' cp "{src}" "$dest_file"\n'.format(src=src) + + 'fi' + for src in source_paths + ]) + ), + is_executable = True, + ) + + return [ + DefaultInfo( + files = depset([runner]), + runfiles = ctx.runfiles( + files = source_files + [package_json, node, npm], + ), + executable = runner, + ), + ] + +docs_dev_server = rule( + implementation = _docs_dev_server_impl, + attrs = { + "srcs": attr.label_list( + allow_files = True, + mandatory = True, + doc = "Documentation source files", + ), + "package_json": attr.label( + allow_single_file = ["package.json"], + mandatory = True, + doc = "package.json file with dependencies", + ), + }, + toolchains = ["@rules_wasm_component//toolchains:jco_toolchain_type"], + executable = True, + doc = """ + Runs a development server for the documentation site with live reload. + + This rule starts an Astro dev server on http://localhost:4321 with hot module + replacement for rapid documentation development. + + Example: + docs_dev_server( + name = "docs_dev", + srcs = glob(["src/**/*", "public/**/*", "*.json", "*.mjs"]), + package_json = "package.json", + ) + + Run with: + bazel run //docs-site:docs_dev + """, +) \ No newline at end of file diff --git a/docs-site/src/content/docs/examples/calculator.mdx b/docs-site/src/content/docs/examples/calculator.mdx new file mode 100644 index 00000000..d4db8221 --- /dev/null +++ b/docs-site/src/content/docs/examples/calculator.mdx @@ -0,0 +1,171 @@ +--- +title: Calculator Component (C++) +description: Math operations component with error handling in C++ +--- + +# Calculator Component (C++) + +A comprehensive C++ calculator component demonstrating advanced WebAssembly component development patterns. + +## Features + +- Basic arithmetic operations (add, subtract, multiply, divide) +- Error handling for division by zero +- C++20 features and standard library usage +- WASI Preview 2 integration + +## Project Structure + +``` +examples/cpp_component/calculator/ +β”œβ”€β”€ BUILD.bazel +β”œβ”€β”€ src/ +β”‚ β”œβ”€β”€ calculator.cpp # Main component implementation +β”‚ β”œβ”€β”€ calculator_impl.h # Calculator interface +β”‚ β”œβ”€β”€ math_utils.cpp # Utility functions +β”‚ └── math_utils.h # Math utilities header +└── wit/ + └── calculator.wit # WIT interface definition +``` + +## WIT Interface + +```wit +package example:calculator@1.0.0; + +interface calculator { + // Basic arithmetic operations + add: func(a: f64, b: f64) -> f64; + subtract: func(a: f64, b: f64) -> f64; + multiply: func(a: f64, b: f64) -> f64; + + // Division with error handling + divide: func(a: f64, b: f64) -> result; + + // Advanced operations + power: func(base: f64, exponent: f64) -> f64; + sqrt: func(value: f64) -> result; +} + +world calculator { + export calculator; +} +``` + +## Implementation + +```cpp +// calculator.cpp +#include "calculator_impl.h" +#include "math_utils.h" +#include +#include + +namespace calculator { + +double Calculator::add(double a, double b) { + return a + b; +} + +double Calculator::subtract(double a, double b) { + return a - b; +} + +double Calculator::multiply(double a, double b) { + return a * b; +} + +std::expected Calculator::divide(double a, double b) { + if (std::abs(b) < std::numeric_limits::epsilon()) { + return std::unexpected("Division by zero"); + } + return a / b; +} + +double Calculator::power(double base, double exponent) { + return std::pow(base, exponent); +} + +std::expected Calculator::sqrt(double value) { + if (value < 0) { + return std::unexpected("Cannot take square root of negative number"); + } + return std::sqrt(value); +} + +} // namespace calculator +``` + +## BUILD Configuration + +```starlark +load("@rules_wasm_component//cpp:defs.bzl", "cpp_component", "cc_component_library") + +# Math utilities library +cc_component_library( + name = "math_utils", + srcs = ["src/math_utils.cpp"], + hdrs = ["src/math_utils.h"], + cxx_std = "c++20", + enable_exceptions = True, + language = "cpp", + optimize = True, +) + +# Calculator component +cpp_component( + name = "calculator_cpp_component", + package_name = "example:calculator@1.0.0", + srcs = ["src/calculator.cpp"], + hdrs = ["src/calculator_impl.h"], + cxx_std = "c++20", + enable_exceptions = True, + language = "cpp", + optimize = True, + wit = "wit/calculator.wit", + world = "calculator", + deps = [":math_utils"], +) +``` + +## Building + +```bash +# Build the component +bazel build //examples/cpp_component/calculator:calculator_cpp_component + +# Validate the component +bazel run //tools:wasm-tools -- validate \\ + bazel-bin/examples/cpp_component/calculator/calculator_cpp_component.wasm +``` + +## Advanced Features + +### Error Handling +The component demonstrates proper error handling using C++23's `std::expected`: + +```cpp +auto result = calculator.divide(10.0, 0.0); +if (!result) { + // Handle error: result.error() contains "Division by zero" +} +``` + +### Standard Library Usage +Uses modern C++ features: +- `` for mathematical functions +- `` for epsilon comparisons +- Exception handling for robust error management + +## Testing + +```bash +# Run component tests +bazel test //examples/cpp_component/calculator:all +``` + +## Next Steps + +- [Multi-Language System](/examples/multi-language/) - Combine with other language components +- [Performance Optimization](/production/performance/) - Add Wizer pre-initialization +- [HTTP Service (Go)](/examples/http-service/) - Build web services \ No newline at end of file diff --git a/docs-site/src/content/docs/examples/http-service.mdx b/docs-site/src/content/docs/examples/http-service.mdx new file mode 100644 index 00000000..82526c79 --- /dev/null +++ b/docs-site/src/content/docs/examples/http-service.mdx @@ -0,0 +1,286 @@ +--- +title: HTTP Service Component (Go) +description: Web service component built with TinyGo and WASI Preview 2 +--- + +# HTTP Service Component (Go) + +A production-ready HTTP service component demonstrating web service development with TinyGo and WebAssembly. + +## Features + +- HTTP/1.1 server implementation +- JSON request/response handling +- Middleware support +- WASI Preview 2 networking +- Resource management and cleanup + +## Project Structure + +``` +examples/go_component/http_service/ +β”œβ”€β”€ BUILD.bazel +β”œβ”€β”€ src/ +β”‚ β”œβ”€β”€ main.go # HTTP server implementation +β”‚ β”œβ”€β”€ handlers.go # Request handlers +β”‚ β”œβ”€β”€ middleware.go # HTTP middleware +β”‚ └── models.go # Data models +└── wit/ + └── http-service.wit # WIT interface definition +``` + +## WIT Interface + +```wit +package example:http-service@1.0.0; + +interface http-handler { + // HTTP request/response types + record http-request { + method: string, + path: string, + headers: list>, + body: option>, + } + + record http-response { + status: u32, + headers: list>, + body: option>, + } + + // Handle HTTP requests + handle-request: func(request: http-request) -> http-response; +} + +world http-service-world { + export http-handler; + import wasi:http/outgoing-handler@0.2.0; + import wasi:http/incoming-handler@0.2.0; +} +``` + +## Implementation + +```go +// main.go +package main + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" +) + +//go:export handle-request +func handleRequest(method, path string, headers []Header, body []byte) *Response { + // Create request object + req := &Request{ + Method: method, + Path: path, + Headers: headers, + Body: body, + } + + // Route requests + switch { + case req.Path == "/health": + return handleHealth(req) + case req.Path == "/api/users" && req.Method == "GET": + return handleGetUsers(req) + case req.Path == "/api/users" && req.Method == "POST": + return handleCreateUser(req) + case strings.HasPrefix(req.Path, "/api/users/"): + return handleUserByID(req) + default: + return &Response{ + Status: 404, + Body: []byte(`{"error": "Not Found"}`), + Headers: []Header{ + {"Content-Type", "application/json"}, + }, + } + } +} + +func handleHealth(req *Request) *Response { + return &Response{ + Status: 200, + Body: []byte(`{"status": "healthy", "service": "http-service"}`), + Headers: []Header{ + {"Content-Type", "application/json"}, + }, + } +} + +func handleGetUsers(req *Request) *Response { + users := []User{ + {ID: 1, Name: "Alice", Email: "alice@example.com"}, + {ID: 2, Name: "Bob", Email: "bob@example.com"}, + } + + data, err := json.Marshal(users) + if err != nil { + return errorResponse(500, "Failed to serialize users") + } + + return &Response{ + Status: 200, + Body: data, + Headers: []Header{ + {"Content-Type", "application/json"}, + }, + } +} +``` + +## Data Models + +```go +// models.go +package main + +type Request struct { + Method string `json:"method"` + Path string `json:"path"` + Headers []Header `json:"headers"` + Body []byte `json:"body,omitempty"` +} + +type Response struct { + Status int `json:"status"` + Headers []Header `json:"headers"` + Body []byte `json:"body,omitempty"` +} + +type Header struct { + Name string `json:"name"` + Value string `json:"value"` +} + +type User struct { + ID int `json:"id"` + Name string `json:"name"` + Email string `json:"email"` +} +``` + +## BUILD Configuration + +```starlark +load("@rules_wasm_component//go:defs.bzl", "go_wasm_component") + +go_wasm_component( + name = "http_service_component", + srcs = [ + "src/main.go", + "src/handlers.go", + "src/middleware.go", + "src/models.go", + ], + wit = "wit/http-service.wit", + world = "http-service-world", + package_name = "example:http-service@1.0.0", + + # TinyGo optimization settings + gc = "leaking", # Use leaking GC for better performance + scheduler = "none", # No goroutine scheduler needed + + # Performance optimizations + optimize = True, + wasm_opt_flags = ["-O3", "--enable-bulk-memory"], +) +``` + +## Building and Testing + +```bash +# Build the HTTP service component +bazel build //examples/go_component/http_service:http_service_component + +# Validate the component +bazel run //tools:wasm-tools -- validate \\ + bazel-bin/examples/go_component/http_service/http_service_component.wasm + +# Run integration tests +bazel test //examples/go_component/http_service:integration_tests +``` + +## Middleware Support + +```go +// middleware.go +package main + +type Middleware func(*Request, func(*Request) *Response) *Response + +func LoggingMiddleware(req *Request, next func(*Request) *Response) *Response { + // Log request + fmt.Printf("Request: %s %s\\n", req.Method, req.Path) + + // Process request + resp := next(req) + + // Log response + fmt.Printf("Response: %d\\n", resp.Status) + + return resp +} + +func CORSMiddleware(req *Request, next func(*Request) *Response) *Response { + resp := next(req) + + // Add CORS headers + resp.Headers = append(resp.Headers, + Header{"Access-Control-Allow-Origin", "*"}, + Header{"Access-Control-Allow-Methods", "GET, POST, PUT, DELETE"}, + ) + + return resp +} +``` + +## Performance Considerations + +### TinyGo Optimizations +- Use leaking GC for better performance in short-lived components +- Disable goroutine scheduler for single-threaded operations +- Enable bulk memory operations for faster data transfers + +### Memory Management +```go +// Efficient byte slice handling +func handleLargePayload(body []byte) *Response { + // Process in chunks to reduce memory pressure + const chunkSize = 4096 + for i := 0; i < len(body); i += chunkSize { + end := i + chunkSize + if end > len(body) { + end = len(body) + } + processChunk(body[i:end]) + } + + return successResponse("Processed") +} +``` + +## Production Deployment + +Use with Wizer for better startup performance: + +```starlark +wasm_component_wizer_library( + name = "optimized_http_service", + component = ":http_service_component", + init_func = "init_service", + allow_wasi = True, +) +``` + +## Next Steps + +- [Multi-Language System](/examples/multi-language/) - Compose with other components +- [Performance Optimization](/production/performance/) - Add pre-initialization +- [Calculator (C++)](/examples/calculator/) - Learn C++ component development \ No newline at end of file diff --git a/docs-site/src/content/docs/examples/multi-language.mdx b/docs-site/src/content/docs/examples/multi-language.mdx new file mode 100644 index 00000000..470d7409 --- /dev/null +++ b/docs-site/src/content/docs/examples/multi-language.mdx @@ -0,0 +1,387 @@ +--- +title: Multi-Language System +description: Polyglot component composition demonstrating language interoperability +--- + +# Multi-Language System + +A comprehensive example demonstrating how to compose WebAssembly components written in different programming languages into a cohesive system. + +## Architecture Overview + +This example showcases a microservices-like architecture where each component is written in a different language: + +```mermaid +graph TB + subgraph "Multi-Language Component System" + A[Rust Authentication] --> D[Go HTTP Gateway] + B[C++ Math Engine] --> D + C[JavaScript UI Handler] --> D + D --> E[Database Service] + D --> F[External APIs] + end + + subgraph "Languages Used" + G[πŸ¦€ Rust - Auth & Security] + H[🐹 Go - HTTP & Networking] + I[⚑ C++ - Performance Critical] + J[🟨 JavaScript - UI Logic] + end +``` + +## Components + +### 1. Authentication Service (Rust) + +High-security authentication with cryptographic operations: + +```rust +// auth-service/src/lib.rs +use jwt_simple::prelude::*; +use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier}; + +wit_bindgen::generate!({ + world: "auth-service", + path: "wit/auth.wit" +}); + +export!(AuthService); + +struct AuthService; + +impl Guest for AuthService { + fn authenticate(username: String, password: String) -> Result { + // Verify password using Argon2 + let parsed_hash = PasswordHash::new(&get_stored_hash(&username)?) + .map_err(|_| AuthError::InvalidCredentials)?; + + Argon2::default() + .verify_password(password.as_bytes(), &parsed_hash) + .map_err(|_| AuthError::InvalidCredentials)?; + + // Generate JWT token + let claims = JWTClaims { + subject: username, + issued_at: now(), + expires_at: now() + Duration::from_hours(24), + }; + + let key = HS256Key::from_bytes(&get_secret_key()); + key.authenticate(claims) + .map_err(|_| AuthError::TokenGeneration) + } +} +``` + +### 2. Math Engine (C++) + +Performance-critical mathematical computations: + +```cpp +// math-engine/src/math_engine.cpp +#include +#include +#include +#include + +#include "math_engine.h" + +extern "C" { + // Matrix operations with SIMD optimization + double* matrix_multiply(const double* a, const double* b, + size_t rows_a, size_t cols_a, size_t cols_b) { + auto result = new double[rows_a * cols_b](); + + // Parallel matrix multiplication + std::transform( + std::execution::par_unseq, + a, a + (rows_a * cols_a), + result, + [&](const double& val) -> double { + // Vectorized operations here + return compute_element(a, b, /* indices */); + } + ); + + return result; + } + + // Statistical functions + double compute_stddev(const double* data, size_t len) { + double mean = std::reduce( + std::execution::par_unseq, + data, data + len + ) / len; + + double variance = std::transform_reduce( + std::execution::par_unseq, + data, data + len, + 0.0, + std::plus(), + [mean](double x) { return (x - mean) * (x - mean); } + ) / (len - 1); + + return std::sqrt(variance); + } +} +``` + +### 3. HTTP Gateway (Go) + +High-performance HTTP routing and middleware: + +```go +// http-gateway/src/main.go +package main + +import ( + "encoding/json" + "fmt" + "context" + "time" +) + +//go:export handle-request +func handleRequest(method, path string, headers []Header, body []byte) *Response { + ctx := context.Background() + + // Route to appropriate service + switch { + case path == "/api/auth/login": + return handleAuth(ctx, method, body) + case path == "/api/math/compute": + return handleMath(ctx, method, body) + case path == "/api/ui/render": + return handleUI(ctx, method, body) + default: + return notFoundResponse() + } +} + +func handleAuth(ctx context.Context, method string, body []byte) *Response { + if method != "POST" { + return methodNotAllowedResponse() + } + + var req AuthRequest + if err := json.Unmarshal(body, &req); err != nil { + return badRequestResponse("Invalid JSON") + } + + // Call Rust authentication service + token, err := authService.Authenticate(req.Username, req.Password) + if err != nil { + return unauthorizedResponse(err.Error()) + } + + return jsonResponse(200, AuthResponse{Token: token}) +} + +func handleMath(ctx context.Context, method string, body []byte) *Response { + // Call C++ math engine + result := mathEngine.Compute(/* parameters */) + return jsonResponse(200, result) +} +``` + +### 4. UI Handler (JavaScript) + +Client-side logic and DOM manipulation: + +```javascript +// ui-handler/src/main.js +import { render, html } from 'lit-html'; + +// Export functions for the component interface +export function renderDashboard(userData, mathResults) { + const template = html` +
+ + +
+

Computation Results

+ ${mathResults.map(result => html` +
+

${result.operation}

+

Result: ${result.value}

+ Computed in ${result.duration}ms +
+ `)} +
+
+ `; + + return template.strings.join(''); +} + +export function handleUserAction(action, data) { + switch (action) { + case 'compute': + return { type: 'math-request', payload: data }; + case 'refresh': + return { type: 'data-refresh' }; + default: + return { type: 'unknown-action', error: 'Unknown action' }; + } +} + +function logout() { + // Clear local state and redirect + return { type: 'logout' }; +} +``` + +## WAC Composition + +The system is composed using WAC (WebAssembly Compositions): + +```yaml +# composition.wac +package multi-language:system@1.0.0; + +world composed-system { + import auth-service: auth-service; + import math-engine: math-engine; + import ui-handler: ui-handler; + + export gateway: gateway; +} + +instantiate auth = auth-service-component with []; +instantiate math = math-engine-component with []; +instantiate ui = ui-handler-component with []; +instantiate gateway = http-gateway-component with [ + (import "auth" (instance auth)) + (import "math" (instance math)) + (import "ui" (instance ui)) +]; + +export gateway; +``` + +## BUILD Configuration + +```starlark +load("@rules_wasm_component//rust:defs.bzl", "rust_wasm_component") +load("@rules_wasm_component//cpp:defs.bzl", "cpp_component") +load("@rules_wasm_component//go:defs.bzl", "go_wasm_component") +load("@rules_wasm_component//js:defs.bzl", "js_wasm_component") +load("@rules_wasm_component//wac:defs.bzl", "wac_compose") + +# Individual language components +rust_wasm_component( + name = "auth_service_component", + srcs = ["auth-service/src/lib.rs"], + wit = "wit/auth.wit", + world = "auth-service", + optimization = "release", + features = ["crypto", "jwt"], +) + +cpp_component( + name = "math_engine_component", + srcs = ["math-engine/src/math_engine.cpp"], + wit = "wit/math.wit", + world = "math-engine", + cxx_std = "c++20", + optimize = True, + copts = ["-march=native", "-O3"], +) + +go_wasm_component( + name = "http_gateway_component", + srcs = ["http-gateway/src/main.go"], + wit = "wit/gateway.wit", + world = "gateway", + optimize = True, +) + +js_wasm_component( + name = "ui_handler_component", + srcs = ["ui-handler/src/main.js"], + wit = "wit/ui.wit", + world = "ui-handler", + npm_deps = ["lit-html"], +) + +# Composed system +wac_compose( + name = "multi_language_system", + composition = "composition.wac", + components = [ + ":auth_service_component", + ":math_engine_component", + ":http_gateway_component", + ":ui_handler_component", + ], +) +``` + +## Building and Testing + +```bash +# Build individual components +bazel build //examples/multi-language:auth_service_component +bazel build //examples/multi-language:math_engine_component +bazel build //examples/multi-language:http_gateway_component +bazel build //examples/multi-language:ui_handler_component + +# Build composed system +bazel build //examples/multi-language:multi_language_system + +# Run integration tests +bazel test //examples/multi-language:integration_test + +# Validate composition +bazel run //tools:wac -- validate \\ + bazel-bin/examples/multi-language/multi_language_system.wasm +``` + +## Performance Characteristics + +### Language-Specific Optimizations + +| Language | Use Case | Performance Benefit | +|----------|----------|-------------------| +| **Rust** | Security, Memory Safety | Zero-cost abstractions, memory safety | +| **C++** | Compute-Heavy Operations | Native performance, SIMD optimization | +| **Go** | Networking, Concurrency | Efficient HTTP handling, fast compilation | +| **JavaScript** | UI Logic, DOM Operations | Familiar APIs, rapid development | + +### System-Level Benefits + +- **Modularity**: Each component can be developed, tested, and deployed independently +- **Language Expertise**: Teams can use their preferred languages for specific tasks +- **Performance**: Critical paths use optimal languages (C++ for math, Rust for security) +- **Maintainability**: Clear component boundaries and interfaces + +## Production Considerations + +### Monitoring and Observability + +```starlark +# Add telemetry to each component +wac_compose( + name = "production_system", + composition = "composition.wac", + components = [...], + telemetry = True, + metrics = ["latency", "memory", "cpu"], +) +``` + +### Security + +- Rust component handles all cryptographic operations +- C++ component runs in isolated memory space +- JavaScript component has limited system access +- Go component provides secure HTTP boundaries + +## Next Steps + +- [Performance Optimization](/production/performance/) - Add Wizer pre-initialization +- [OCI Publishing](/production/publishing/) - Distribute composed systems +- [Component Signing](/security/component-signing/) - Secure multi-component deployments \ No newline at end of file diff --git a/docs-site/src/content/docs/guides/advanced-features.mdx b/docs-site/src/content/docs/guides/advanced-features.mdx index c254c9f5..1896a105 100644 --- a/docs-site/src/content/docs/guides/advanced-features.mdx +++ b/docs-site/src/content/docs/guides/advanced-features.mdx @@ -420,4 +420,88 @@ wkg_multi_registry_publish( ) ``` +## WASI-NN Machine Learning Integration + +Build WebAssembly components that perform neural network inference using the standardized WASI-NN interfaces. + +### Supported WASI-NN Versions + +All WASI-NN releases are supported with proper version isolation: + +```starlark title="BUILD.bazel" +# Latest version (recommended for new projects) +wit_library( + name = "ml_latest", + srcs = ["inference.wit"], + deps = ["@wasi_nn//:nn"], # v0.2.0-rc-2024-10-28 +) + +# Pinned version for production stability +wit_library( + name = "ml_production", + srcs = ["inference.wit"], + deps = ["@wasi_nn_v0_2_0_rc_2024_06_25//:nn"], # Initial stable release +) +``` + +### Machine Learning Component Pattern + +```wit title="ml-component.wit" +package company:ml-service@1.0.0; + +world ml-inference { + // Neural network operations + import wasi:nn/graph@0.2.0-rc-2024-10-28; + import wasi:nn/tensor@0.2.0-rc-2024-10-28; + import wasi:nn/inference@0.2.0-rc-2024-10-28; + import wasi:nn/errors@0.2.0-rc-2024-10-28; + + // File access for models + import wasi:filesystem/types@0.2.3; + import wasi:io/streams@0.2.3; + + // Export high-level ML API + export classify-image: func(image-data: list) -> result; + export load-model: func(model-path: string) -> result<(), string>; +} +``` + +### Real-World ML Deployment + +```python title="BUILD.bazel" +# Production ML inference service +rust_wasm_component_bindgen( + name = "image_classifier", + srcs = ["src/classifier.rs"], + wit = ":ml_interfaces", + profiles = ["release"], +) + +# Test with validation dataset +rust_wasm_component_test( + name = "classifier_accuracy_test", + component = ":image_classifier", + data = ["//testdata:validation_dataset"], +) + +# Deploy to container registry +wkg_publish( + name = "deploy_classifier", + component = ":image_classifier", + registry = "ghcr.io/company", + tag = "v1.0.0", +) +``` + +### WASI-NN Interface Guide + +The WASI-NN specification provides four core interfaces: + +- **`tensor`**: Multi-dimensional arrays for ML data (input/output) +- **`graph`**: Neural network model loading and management +- **`inference`**: Execute inference operations on loaded models +- **`errors`**: Standardized error handling for ML operations + +This enables portable ML components that work across different runtime environments while maintaining consistent APIs for neural network operations. + These advanced features enable enterprise-grade WebAssembly component development, deployment, and management at scale. diff --git a/docs-site/src/content/docs/guides/example.md b/docs-site/src/content/docs/guides/example.md deleted file mode 100644 index ebd0f3bc..00000000 --- a/docs-site/src/content/docs/guides/example.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Example Guide -description: A guide in my new Starlight docs site. ---- - -Guides lead a user through a specific task they want to accomplish, often with a sequence of steps. -Writing a good guide requires thinking about what your users are trying to do. - -## Further reading - -- Read [about how-to guides](https://diataxis.fr/how-to-guides/) in the DiΓ‘taxis framework diff --git a/docs-site/src/content/docs/guides/external-wit-dependencies.mdx b/docs-site/src/content/docs/guides/external-wit-dependencies.mdx index c9dc65cc..85e8ae2b 100644 --- a/docs-site/src/content/docs/guides/external-wit-dependencies.mdx +++ b/docs-site/src/content/docs/guides/external-wit-dependencies.mdx @@ -213,7 +213,11 @@ The most common external dependencies are WASI interfaces. These are pre-configu # Enable WASI WIT interfaces wasi_wit_ext = use_extension("@rules_wasm_component//wasm:extensions.bzl", "wasi_wit") wasi_wit_ext.init() -use_repo(wasi_wit_ext, "wasi_io") +use_repo(wasi_wit_ext, + "wasi_io", "wasi_cli", "wasi_clocks", "wasi_random", # Core WASI + "wasi_filesystem", "wasi_sockets", "wasi_http", # Advanced WASI + "wasi_nn", "wasi_nn_v0_2_0_rc_2024_08_19", "wasi_nn_v0_2_0_rc_2024_06_25" # Neural Network +) ``` ```starlark title="BUILD.bazel" @@ -277,6 +281,14 @@ The following WASI interfaces are pre-configured and available with dual version | `@wasi_sockets//:sockets` | `wasi:sockets@0.2.3` | `network`, `udp`, `tcp`, `ip-name-lookup` | Network operations ⚠️ | | `@wasi_http//:http` | `wasi:http@0.2.3` | `types`, `handler`, `outgoing-handler`, `proxy` | HTTP client/server ⚠️ | +### WASI-NN (Neural Network / Machine Learning) + +| Package | Target | Interfaces | Description | +|---------|--------|-------------|-------------| +| `@wasi_nn//:nn` | `wasi:nn@0.2.0-rc-2024-10-28` | `tensor`, `graph`, `inference`, `errors` | Neural network inference (latest) | +| `@wasi_nn_v0_2_0_rc_2024_08_19//:nn` | `wasi:nn@0.2.0-rc-2024-08-19` | `tensor`, `graph`, `inference`, `errors` | Neural network inference | +| `@wasi_nn_v0_2_0_rc_2024_06_25//:nn` | `wasi:nn@0.2.0-rc-2024-06-25` | `tensor`, `graph`, `inference`, `errors` | Neural network inference (initial) | + ### WASI 0.2.0 (Original - Maximum Compatibility) | Package | Target | Interfaces | Description | @@ -288,9 +300,11 @@ The following WASI interfaces are pre-configured and available with dual version ### Status & Recommendations - βœ… **Core WASI (IO, CLI, Clocks, Random)**: Work perfectly with current toolchain -- ⚠️ **Advanced WASI (Filesystem, Sockets, HTTP)**: Complete architecture but may have toolchain compatibility issues +- ⚠️ **Advanced WASI (Filesystem, Sockets, HTTP)**: Complete architecture but may have toolchain compatibility issues +- βœ… **WASI-NN (Neural Networks)**: All versions supported, stable interface across releases - πŸ”„ **Use 0.2.0 versions**: For maximum compatibility with older toolchains - πŸ“ˆ **Use 0.2.3 versions**: For latest features when toolchain supports +- 🧠 **Use latest WASI-NN**: `@wasi_nn//:nn` recommended for new projects ### Usage Examples @@ -319,6 +333,19 @@ wit_library( ) ``` +**Machine learning component:** +```starlark +wit_library( + name = "ml_service", + srcs = ["ml.wit"], + deps = [ + "@wasi_nn//:nn", # Neural network inference (latest) + "@wasi_io//:streams", # I/O operations + "@wasi_filesystem//:filesystem", # Model file access + ], +) +``` + **Advanced component (when toolchain supports):** ```starlark wit_library( @@ -345,6 +372,30 @@ wit_library( ) ``` +**WASI-NN version selection:** +```starlark +# Latest features (recommended) +wit_library( + name = "ml_latest", + deps = ["@wasi_nn//:nn"], # v0.2.0-rc-2024-10-28 +) + +# Specific version for compatibility +wit_library( + name = "ml_stable", + deps = ["@wasi_nn_v0_2_0_rc_2024_06_25//:nn"], # Initial stable version +) + +# Multiple versions for migration testing +wit_library( + name = "ml_migration_test", + deps = [ + "@wasi_nn_v0_2_0_rc_2024_06_25//:nn", # Old version + "@wasi_nn//:nn", # New version + ], +) +``` + ## Working with WKG (WebAssembly Component Registry) WKG is the standard registry for WebAssembly components and interfaces, similar to npm for JavaScript or crates.io for Rust. @@ -451,7 +502,79 @@ wkg_publish( Here are real-world scenarios showing when and how to use each method: -### Scenario 1: Building a Web Service +### Scenario 1: Building a Machine Learning Inference Service +**Goal:** Create an ML service that processes data using neural network models + +```python title="MODULE.bazel" +# Enable WASI-NN interfaces +wasi_wit_ext = use_extension("@rules_wasm_component//wasm:extensions.bzl", "wasi_wit") +wasi_wit_ext.init() +use_repo(wasi_wit_ext, "wasi_nn", "wasi_io", "wasi_filesystem") +``` + +```starlark title="BUILD.bazel" +wit_library( + name = "ml_inference_wit", + srcs = ["ml-inference.wit"], + deps = [ + "@wasi_nn//:nn", # Neural network operations + "@wasi_io//:streams", # Data I/O + "@wasi_filesystem//:filesystem", # Model file loading + ], +) + +rust_wasm_component_bindgen( + name = "ml_inference_service", + srcs = ["src/lib.rs"], + wit = ":ml_inference_wit", +) +``` + +```wit title="ml-inference.wit" +package example:ml-inference@1.0.0; + +world ml-inference { + // Import WASI-NN for neural network operations + import wasi:nn/graph@0.2.0-rc-2024-10-28; + import wasi:nn/tensor@0.2.0-rc-2024-10-28; + import wasi:nn/inference@0.2.0-rc-2024-10-28; + import wasi:nn/errors@0.2.0-rc-2024-10-28; + + // Import WASI for file and I/O operations + import wasi:filesystem/types@0.2.3; + import wasi:io/streams@0.2.3; + + // Export inference API + export infer: func(model-path: string, input-data: list) -> result, string>; +} +``` + +```rust title="src/lib.rs" +use crate::bindings::wasi::nn::{graph, tensor, inference}; + +impl Guest for Component { + fn infer(model_path: String, input_data: Vec) -> Result, String> { + // 1. Load the neural network model + let graph_builder = graph::load(&model_path) + .map_err(|e| format!("Failed to load model: {:?}", e))?; + + // 2. Create input tensor from raw data + let tensor_data = tensor::TensorData { + data: input_data, + dimensions: vec![1, 784], // Example: 28x28 image flattened + }; + + // 3. Execute inference + let outputs = inference::compute(&graph_builder, &[tensor_data]) + .map_err(|e| format!("Inference failed: {:?}", e))?; + + // 4. Extract and return results + Ok(outputs[0].data.iter().map(|&x| x as f32).collect()) + } +} +``` + +### Scenario 2: Building a Web Service **Goal:** Create a web service that handles HTTP requests and accesses a database ```python title="MODULE.bazel" @@ -719,7 +842,7 @@ wit_library( Update `MODULE.bazel`: ```python title="MODULE.bazel" -use_repo(wasi_wit_ext, "wasi_io", "company_shared_wit") +use_repo(wasi_wit_ext, "wasi_io", "wasi_nn", "company_shared_wit") ``` ## Calculating SHA256 Checksums diff --git a/docs-site/src/content/docs/production/performance.mdx b/docs-site/src/content/docs/production/performance.mdx new file mode 100644 index 00000000..2a2a9cca --- /dev/null +++ b/docs-site/src/content/docs/production/performance.mdx @@ -0,0 +1,90 @@ +--- +title: Performance Optimization +description: Optimize WebAssembly components for production using Wizer pre-initialization +--- + +# Performance Optimization + +Learn how to optimize WebAssembly components for faster startup times and better runtime performance. + +## Wizer Pre-initialization + +Wizer is a WebAssembly pre-initialization tool that can dramatically improve startup performance by running initialization code at build time. + +### Basic Usage + +```starlark +load("@rules_wasm_component//wasm:defs.bzl", "wasm_component_wizer_library") + +wasm_component_wizer_library( + name = "optimized_component", + component = ":my_component", + init_func = "init", + allow_wasi = True, +) +``` + +### Performance Gains + +Wizer can provide: +- **1.35-6x faster startup** for typical components +- Reduced cold start latency +- Pre-computed initialization state + +### Best Practices + +1. **Identify expensive initialization** - Profile your component to find slow startup code +2. **Design for pre-initialization** - Structure code to separate initialization from runtime logic +3. **Test thoroughly** - Ensure pre-initialized state is correct + +## Build Optimizations + +### Compiler Flags + +```starlark +rust_wasm_component( + name = "optimized_rust_component", + srcs = ["lib.rs"], + wit = "component.wit", + optimization = "release", # Use release optimizations + features = ["opt-level=s"], # Optimize for size +) +``` + +### Profile-Based Optimization + +Use different optimization profiles: + +```starlark +rust_wasm_component( + name = "my_component_all_profiles", + srcs = ["lib.rs"], + wit = "component.wit", + profiles = ["debug", "release", "size"], +) +``` + +## Runtime Performance + +### Memory Management +- Use appropriate memory allocation strategies +- Profile memory usage with tools like `wasm-profiler` +- Consider memory pre-allocation for performance-critical paths + +### Function Call Optimization +- Minimize host function calls +- Batch operations when possible +- Use efficient data serialization + +## Measurement and Profiling + +Track key metrics: +- Component load time +- First function call latency +- Memory usage +- Execution time + +## Next Steps + +- [Deployment Guide](/production/deployment-guide/) - Production deployment strategies +- [Component Signing](/security/component-signing/) - Secure your optimized components \ No newline at end of file diff --git a/docs-site/src/content/docs/production/publishing.mdx b/docs-site/src/content/docs/production/publishing.mdx new file mode 100644 index 00000000..4ba2d477 --- /dev/null +++ b/docs-site/src/content/docs/production/publishing.mdx @@ -0,0 +1,54 @@ +--- +title: OCI Publishing +description: Distribute WebAssembly components via container registries +--- + +# OCI Publishing + +This guide covers publishing WebAssembly components to OCI (Open Container Initiative) registries for distribution and sharing. + +## Overview + +The rules support publishing components to OCI-compatible registries like: +- Docker Hub +- GitHub Container Registry (ghcr.io) +- AWS ECR +- Azure Container Registry +- Any OCI-compatible registry + +## Basic Publishing + +```starlark +load("@rules_wasm_component//oci:defs.bzl", "oci_push") + +oci_push( + name = "publish_component", + image = ":my_component", + repository = "ghcr.io/myorg/my-component", + tag = "latest", +) +``` + +## Registry Authentication + +Configure authentication using standard OCI methods: +- Docker config file (`~/.docker/config.json`) +- Environment variables +- Service account credentials + +## Automated Publishing + +Integrate with CI/CD pipelines: + +```yaml +# GitHub Actions example +- name: Publish Component + run: bazel run //my/component:publish_component + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +``` + +## Next Steps + +- [Component Signing](/security/component-signing/) - Add cryptographic signatures +- [WAC + OCI Integration](/composition/wac-oci-integration/) - Use published components in compositions \ No newline at end of file diff --git a/docs-site/src/content/docs/reference/example.md b/docs-site/src/content/docs/reference/example.md deleted file mode 100644 index 0224f096..00000000 --- a/docs-site/src/content/docs/reference/example.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Example Reference -description: A reference page in my new Starlight docs site. ---- - -Reference pages are ideal for outlining how things work in terse and clear terms. -Less concerned with telling a story or addressing a specific use case, they should give a comprehensive outline of what you're documenting. - -## Further reading - -- Read [about reference](https://diataxis.fr/reference/) in the DiΓ‘taxis framework diff --git a/toolchains/cpp_component_toolchain.bzl b/toolchains/cpp_component_toolchain.bzl index d57c4ca5..5a2440c0 100644 --- a/toolchains/cpp_component_toolchain.bzl +++ b/toolchains/cpp_component_toolchain.bzl @@ -312,7 +312,7 @@ cpp_component_toolchain( llvm_ar = ":llvm_ar_binary", wit_bindgen = ":wit_bindgen_binary", wasm_tools = ":wasm_tools_binary", - sysroot_path = "external/+cpp_component+cpp_toolchain/sysroot", + sysroot_path = "sysroot", sysroot_files = ":sysroot_files", include_dirs = glob(["sysroot/include/**/*"]), )