Skip to content

Instantly share code, notes, and snippets.

@dzil123
Last active June 16, 2020 10:09
Show Gist options
  • Save dzil123/53a90510c49562499d65bd5f041b0ece to your computer and use it in GitHub Desktop.
Save dzil123/53a90510c49562499d65bd5f041b0ece to your computer and use it in GitHub Desktop.
Helper to create and build projects with https://github.com/yewstack/yew as an alternative to wasm-pack
#!/usr/bin/bash
# uses bash specific features
# Formatted with 'shfmt -i 4 -w file.sh'
# set -e
# set -u
set -o pipefail
shopt -s lastpipe
cargo_bin=$(realpath ${CARGO_INSTALL_ROOT:-${CARGO_HOME:-~/.cargo}/bin})
export PATH="$PATH:$cargo_bin"
function fail() {
echo $@ >&2
exit 1
}
function cargo_install_fail() {
echo "" >&2
echo "Unable to access '$1'!" >&2
echo "Please ensure $cargo_bin is where cargo installs executables" >&2
echo "Or otherwise add '$1' to PATH" >&2
exit 1
}
function ensure_deps_installed() {
cargo add --version >/dev/null 2>&1 || cargo_install_fail "cargo add"
wasm-bindgen --version >/dev/null 2>&1 || cargo_install_fail "wasm-bindgen"
}
# Install dependencies for Arch Linux and rustup
function install() {
sudo pacman -Syu --needed binaryen npm jq rustup
rustup toolchain add stable
rustup target add wasm32-unknown-unknown
rustup update
cargo install wasm-bindgen-cli cargo-edit
}
#src rust source
#static html/js/css source
#-- ignored --
#target compiled rust
#dist compiled html/js/css wasm
function new() {
ensure_deps_installed
cargo new -- "$1"
mkdir --parents "$1"
cd "$1"
# to generate:
# tar -czv .cargo/config .gitignore src/lib.rs static/index.html | base64
base64 -d <<EOF | tar xz
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
EOF
# Last major release as of 06/15/2020
cargo add --sort js-sys@0.3 wee_alloc@0.4 wasm-bindgen@0.2 yew@0.16
cat >>Cargo.toml <<EOF
[profile.release]
panic = 'abort'
codegen-units = 1
opt-level = 'z'
lto = true
EOF
# package name != "$1" because "$1" could have subdirectories
pkg_name=$(grep Cargo.toml -e "^name" | cut -d'"' -f2 | head --lines 1)
cat >src/main.rs <<EOF
fn main() {
yew::start_app::<$pkg_name::Model>();
}
EOF
git add .
git commit -m"Initial commit"
}
# Usage: `find_up filename`
# Recursively looks in current and parent directories
# until it finds the file.
# If found, echo the directory and exit 0.
# If not found, exit 1.
function find_up() {
dir=$(pwd)
while [[ $dir != / ]]; do
find "$dir" -maxdepth 1 -mindepth 1 -name "$1" | read
if [ $? -eq 0 ]; then
echo $dir
return 0
fi
dir="$(realpath -s "$dir"/..)"
done
return 1
}
function copy() {
cp --verbose "$1" "$2"
}
# Usage: `minify_whatever source dest`
function minify_html() {
# todo: uhhhhhh
copy $@
}
function minify_js() {
(
npx --version >/dev/null 2>&1 &&
npx terser -c -m module=true,reserved=['init'] \
-o "$2" -- "$1"
) || copy $@
}
function minify_wasm() {
(
wasm-opt --version >/dev/null 2>&1 &&
wasm-opt "$1" -Oz --strip-debug --output "$2"
) || copy $@
}
function cargo_build_debug() {
# run once to get good user output, then run again to get json output
cargo build --target wasm32-unknown-unknown $@ >&2 &&
cargo build --target wasm32-unknown-unknown --message-format json $@ 2>/dev/null
}
function cargo_build_release() {
cargo_build_debug --release $@
}
# Usage: `wasm-bindgen_mode compiled.wasm temp_dir [extras...]`
function wasm_bindgen_release() {
source=$1
dest=$2
shift 2
mkdir --parents "$dest"
wasm-bindgen $@ --target web --no-typescript --out-dir "$dest" --out-name wasm "$source"
}
function wasm_bindgen_debug() {
wasm_bindgen_release $@ --keep-debug --debug
}
function parse_location() {
# TARGET="$SRCDIR/target/wasm32-unknown-unknown/{profile}/{name}.wasm"
# jq --raw-output 'select(.target?.kind?[0] == "bin") | .target.name' | tail --lines 1
# todo: catch {"reason":"build-finished","success":false} ?
jq --raw-output 'select(.target?.kind?[0] == "bin") | .executable' | tail --lines 1
}
function cd_srcdir() {
srcdir=$(find_up Cargo.toml)
if [ $? -ne 0 ]; then
fail "Could not find source directory"
fi
cd "$srcdir"
}
# Usage: `build` for debug
# `build 1` for release
function build() {
ensure_deps_installed
cd_srcdir
# mode == 0 -> debug, else release
[[ $1 -eq 0 ]]
mode=$?
(
if ((mode == 0)); then
cargo_build_debug
else
cargo_build_release
fi
) | parse_location | read binary || fail "Cargo build failed"
echo "Binary at $binary"
wasm_bindgen_dir="$(dirname "$binary")/wasm_bindgen_temp/"
mkdir --parents dist
# todo: copy arbitrary static/ files with correct minifiers
if ((mode == 0)); then
wasm_bindgen_debug "$binary" ./dist
copy ./static/index.html ./dist/index.html
else
wasm_bindgen_release "$binary" "$wasm_bindgen_dir"
minify_html ./static/index.html ./dist/index.html
minify_js "$wasm_bindgen_dir/wasm.js" ./dist/wasm.js
minify_wasm "$wasm_bindgen_dir/wasm_bg.wasm" ./dist/wasm_bg.wasm
fi
}
function clean() {
cd_srcdir
rm -fdrv dist
}
function usage() {
echo "Usage: $programname build|run [-r|--release]"
echo " $programname clean"
echo " $programname new <path>"
echo " $programname install # Arch-only"
return 1
}
function build_cmd() {
release=0
case $1 in
"r" | "-r" | "--release")
release=1
;;
"") ;;
*)
usage
return
;;
esac
build $release
}
function run() {
build_cmd $@ &&
# todo: port?
python -m http.server --directory ./dist
}
function main() {
programname=$(basename "$0")
subcommand=$1
shift
case $subcommand in
"b" | "build")
build_cmd $@
;;
"r" | "run")
run $@
;;
"n" | "new")
new $@
;;
"install")
install
;;
"c" | "clean")
clean
;;
"" | "help" | "-h" | "--help")
usage
;;
*)
echo "Unknown command '$subcommand'"
usage
;;
esac
}
main $@
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment