Dev server & automatic rebuilds
This repository configures a Vite plugin (watch-cpp-and-build-wasm) that watches .cpp and .h files and runs npm run build-wasm when changes occur. The plugin logic prevents overlapping builds with a __isBuilding flag.
Important points:
- The watcher registers
src/wasm/**/*.{cpp,h}with Vite's watcher so edits trigger rebuilds. - The build uses the root
src/wasm/CMakeLists.txtwhich iterates through the modules and calls each module'sCMakeLists.txt. - For faster local iteration use
npm run dev:debug— this runsmake debugand launches the dev server.
Root CMakeLists.txt contract
The root src/wasm/CMakeLists.txt (provided in the repo) implements two main targets, build & debug.
Submodule CMakeLists.txt must therefore support at least build (default) & debug targets.
Example submodule CMakeLists.txt template (recommended)
# =================================================================
# <ModuleName> 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., "example" -> "Example")
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 (recursively)
file(GLOB_RECURSE SRC_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
)
# Output directory
set(BUILD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/build")
set(OUT_JS "${BUILD_DIR}/index.js")
# 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
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=1024MB"
"SHELL:-s MAXIMUM_MEMORY=2048MB"
"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)")
note
- Place your C++ headers in include/ and sources in src/
- Use exported functions via ccall/cwrap in JS
- Adjust memory flags if your module needs more/less WASM memory
- For module-specific Emscripten options, add them before target_link_options
This template compiles all .cpp files under src/ into build/index.js + build/index.wasm using simple flags. Tailor flags and link-time options to your needs.
Debugging tips
- Build with
debugtarget to keep symbols and turn onASSERTIONS. - Use
EMSCRIPTEN_KEEP_UNWANTED_CODEonly when you need to preserve functions — avoid it in production. - Use
console.login Emscripten glue JS — Emscripten prints useful warnings if symbols are missing.