Step-by-step: add a new module
-
Create a new directory:
src/wasm/modules/<module-name>/.- Replace
<module-name>with your actual module name (lowercase, e.g.,audio,filters).
- Replace
-
Add
src/,include/directories and aCMakeLists.txtfile. -
Make sure the module's
CMakeLists.txtwrites output tobuild/withindex.jsandindex.wasm(the repo's alias generator expectsmodules/{name}/build). -
vite.config.jswill automatically find the module and create an alias@wasm-<module-name>on nextvitestart (or rebuild of the config). Example usage:import init from '@wasm-<module-name>/index.js';
await init(); -
Commit the
CMakeLists.txtand source files; do not commitbuild/artifacts unless you want to vendor the WASM for static hosting without building.
Minimal module CMakeLists.txt (copy/paste)
# =============================================
# <Module Name> WASM Module - CMake Build Configuration
# =============================================
# Get module name from directory
get_filename_component(MODULE_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
# Capitalize first letter for export name (e.g., "audio" -> "Audio")
string(SUBSTRING ${MODULE_NAME} 0 1 FIRST_LETTER)
string(TOUPPER ${FIRST_LETTER} FIRST_LETTER_UPPER)
string(SUBSTRING ${MODULE_NAME} 1 -1 REST_OF_NAME)
set(CAP_MODULE_NAME "${FIRST_LETTER_UPPER}${REST_OF_NAME}")
# Collect source files
file(GLOB_RECURSE SRC_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
)
# Output directory
set(BUILD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/build")
# Create executable target (Emscripten produces .js + .wasm)
add_executable(${MODULE_NAME}_wasm ${SRC_FILES})
# Include directories
target_include_directories(${MODULE_NAME}_wasm PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
# Shared Emscripten options
# Adjust INITIAL_MEMORY and MAXIMUM_MEMORY based on your module's needs
set(COMMON_FLAGS
"SHELL:-s MODULARIZE=1"
"SHELL:-s EXPORT_ES6=1"
"SHELL:-s EXIT_RUNTIME=1"
"SHELL:-s ENVIRONMENT=web"
"SHELL:-s EXPORTED_FUNCTIONS=['_malloc','_free']"
"SHELL:-s EXPORTED_RUNTIME_METHODS=['ccall','cwrap','getValue','setValue','HEAPU8']"
"SHELL:-s INITIAL_MEMORY=256MB"
"SHELL:-s MAXIMUM_MEMORY=512MB"
"SHELL:-s ALLOW_MEMORY_GROWTH=1"
"SHELL:-s EXPORT_NAME=create${CAP_MODULE_NAME}Module"
)
# Apply common flags
target_link_options(${MODULE_NAME}_wasm PRIVATE ${COMMON_FLAGS})
# Build-type specific flags
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_options(${MODULE_NAME}_wasm PRIVATE -O0 -g4)
target_link_options(${MODULE_NAME}_wasm PRIVATE
"SHELL:-s ASSERTIONS=2"
-g4
)
else()
target_compile_options(${MODULE_NAME}_wasm PRIVATE -O3)
target_link_options(${MODULE_NAME}_wasm PRIVATE
"SHELL:-s SINGLE_FILE=0"
)
endif()
# Set output location and name
set_target_properties(${MODULE_NAME}_wasm PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${BUILD_DIR}"
OUTPUT_NAME "index"
SUFFIX ".js"
)
message(STATUS "Module '${MODULE_NAME}' configured (export: create${CAP_MODULE_NAME}Module)")
Directory structure
Your new module should look like:
src/wasm/modules/<module-name>/
├── CMakeLists.txt
├── include/
│ └── your_header.h
├── src/
│ └── main.cpp
└── build/ # Generated (gitignored)
├── index.js
└── index.wasm
Building
Once added, the module is automatically discovered by the root CMakeLists.txt. Simply run:
npm run build-wasm # Release build
npm run build-wasm:debug # Debug build with source maps
npm run clean-wasm # Clean all build artifacts
The build system works identically on Windows, macOS, and Linux.