SwiftWasm appsWatcher, bundler, and test runner for your
The main goal of
carton is to provide a smooth zero-config experience when developing for WebAssembly.
It currently supports these features with separate commands:
- Creating basic package boilerplate for apps built with SwiftWasm with
- Watching the app for source code changes and reloading it in your browser with
- Optimizing and packaging the app for distribution with
- Managing SwiftWasm toolchain and SDK installations with
The main motivation for
carton came after having enough struggles with
webpack.js, trying to make its config file work, looking for appropriate
plugins. At some point the maintainers became convinced that the required use of
SwiftWasm projects could limit the wider adoption of SwiftWasm itself. Hopefully, with
can avoid using
carton also simplifies a few other things in your SwiftWasm
development workflow such as toolchain and SDK installations.
- macOS 11 and Xcode 13.2.1 or later. macOS 10.15 may work, but is untested.
- Swift 5.5 or later and Ubuntu 18.04 or 20.04 for Linux users.
carton can be installed with Homebrew. Make sure you have Homebrew
installed and then run:
brew install swiftwasm/tap/carton
carton is also available as a Docker image for Linux. You can pull it with this command:
docker pull ghcr.io/swiftwasm/carton:latest
If Docker images are not suitable for you, you'll have to build
carton from sources on Ubuntu.
Clone the repository and run
./install_ubuntu_deps.sh in the root directory of the clone. After
that completes successfully, run
swift build -c release, the
carton binary will be located in
.build/release directory after that. Unfortunately, other Linux distributions are currently
carton 0.15. All version combinations of
You still have to keep in mind that older versions of SwiftWasm may be incompatible with newer
carton. You can follow
the compatibility matrix if you need to use older verions:
carton init command initializes a new SwiftWasm project for you (similarly to
swift package init) with multiple templates available at your choice.
carton init --template tokamak
creates a new Tokamak project, while
carton init --template basic (equivalent
carton init) creates an empty SwiftWasm project with no dependencies. Also,
carton init list-templates
provides a complete list of templates (with only
tokamak available currently).
carton dev command builds your project with the SwiftWasm toolchain and starts an HTTP server
app, reachable at http://127.0.0.1:8080/, will automatically open in your
default web browser. The port that the development server uses can also be controlled with the
--port option (or
-p for short). You can edit the app source code in your favorite editor and
carton will immediately rebuild the app and reload all browser tabs that have the app
open. You can also pass a
--verbose flag to keep the build process output available, otherwise
stale output is cleaned up from your terminal screen by default. If you have a custom
page you'd like to use when serving, pass a path to it with a
carton test command runs your test suite in
or using your default browser. You can switch between these with the
--environment option, passing
defaultBrowser. Code that depends on
--environment node or
--environment defaultBrowser options, depending on whether it needs Web APIs to work. Otherwise
If you want to run your test suite on CI or without GUI but on browser, you can pass
It enables WebDriver-based headless browser testing. Note that you
need to install a WebDriver executable in
PATH before running tests.
You can use the command with a prebuilt test bundle binary instead of building it in carton by passing
--prebuilt-test-bundle-path <your binary path>.
carton sdk command and its subcommands allow you to manage installed SwiftWasm toolchains, but
is rarely needed, as
carton dev installs the recommended version of SwiftWasm automatically.
carton sdk versions lists all installed versions, and
carton sdk local prints the version
specified for the current project in the
.swift-version file. You can however install SwiftWasm
separately if needed, either by passing an archive URL to
carton sdk install directly, or just
specifying the snapshot version, like
carton sdk install wasm-5.3-SNAPSHOT-2020-09-25-a.
carton dev can also detect existing installations of
swiftenv, so if you already have SwiftWasm
swiftenv, you don't have to do anything on top of that to start using
carton bundle command builds your project using the
release configuration (although you can
--debug flag to it to change that), and copies all required assets to the
directory. You can then use a static file hosting (e.g. GitHub Pages)
or any other server with support for static files to deploy your application. All resulting bundle
index.html are named by their content hashes to enable cache
busting. As with
carton dev, a custom
index.html page can be provided through the
--custom-index-page option. You can also pass
--debug-info flag to preserve
names and DWARF sections in the resulting
.wasm file, as these
are stripped in the
release configuration by default. By default,
carton bundle will run
on the resulting .wasm binary in order to reduce its file size. That behaviour can be disabled (in order
to speed up the build) by appending the
--wasm-optimizations none option.
carton package command proxies its subcommands to
swift package invocations on the
currently-installed toolchain. This may be useful in situations where you'd like to generate an
Xcode project file for your app with something like
carton package generate-xcodeproj. It would be
swift package generate-xcodeproj, but invoked with the SwiftWasm toolchain instead
of the toolchain supplied by Xcode.
All commands that delegate to
swift build and
can be passed
-Xswiftc arguments, which is equivalent to
swift build. All
-Xswiftc arguments are propagated to
swiftc itself unmodified.
All of these commands and subcommands can be passed a
--help flag that prints usage info and
information about all available options.
How does it work?
carton bundles a WASI polyfill, which is currently required to run any SwiftWasm code,
carton also embeds an HTTP server for previewing your SwiftWasm app directly in a browser.
The development version of the polyfill establishes a helper WebSocket connection to the server, so that
it can reload development browser tabs when rebuilt binary is available. This brings the development
experience closer to Xcode live previews, which you may have previously used when developing SwiftUI apps.
carton does not require any config files for these basic development scenarios, while some configuration
may be supported in the future, for example for complex asset pipelines if needed. The only requirement
is that your
Package.swift contains at least a single executable product, which then will be compiled
for WebAssembly and served when you start
carton dev in the directory where
Package.swift is located.
carton dev with the
carton dev will compile in the
debug configuration. Add the
--release flag to compile in the
If this tool saved you any amount of time or money, please consider sponsoring the SwiftWasm organization. Or you can sponsor some of our maintainers directly on their personal sponsorship pages: @carson-katri, @kateinoigakukun, and @MaxDesiatov. While some of the sponsorship tiers give you priority support or even consulting time, any amount is appreciated and helps in maintaining the project.
This project uses SwiftFormat and SwiftLint to enforce formatting and coding style. We encourage you to run SwiftFormat within a local clone of the repository in whatever way works best for you either manually or automatically via an Xcode extension, build phase or git pre-commit hook etc.
To guarantee that these tools run before you commit your changes on macOS, you're encouraged to run this once to set up the pre-commit hook:
brew bundle # installs SwiftLint, SwiftFormat and pre-commit pre-commit install # installs pre-commit hook to run checks before you commit
Refer to the pre-commit documentation page for more details and installation instructions for other platforms.
SwiftFormat and SwiftLint also run on CI for every PR and thus a CI build can fail with incosistent formatting or style. We require CI builds to pass for all PRs before merging.