Typescript 2 -> ES6 -> Babel -> ES5 (+ watchable / NO gulpfile! - just unix pipes) https://asciinema.org/a/20h1t61ky43xvszkrcl8h24jo

4 min read Original article ↗
#!/bin/bash # # Task wrapper. Runs various chores in a cross platform manner. # # Usage: run [-h] <command> # # Available commands are: # build: Build the project # <other>: Run any other command available in the NPM path # # Options: # -h, --help Show this help and exit ################################################################################ # Automatic configuration ################################################################################ TSC_CMD=tsc BABEL_CMD=babel PATH=./node_modules/.bin:$PATH IS_WINDOWS=false SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR_LEN=${#SCRIPT_DIR} # check if we're operating under windows (under mingw / git bash) # on windows, the symlinked script files have an obnoxious .cmd file extension. if [[ $(uname) == MINGW* ]]; then IS_WINDOWS=true TSC_CMD=tsc.cmd BABEL_CMD=babel.cmd fi ################################################################################ # Build scripts ################################################################################ # Typescript wrapper # # Typescript 2 ships with a flag to emit compiled files to stdout # (`-listEmittedFiles`). This makes it possible to convert the emitted # files from ES7+ to ES5 using, for example, the babel transpiler. # # The problem, however, is that these emitted files may be mangled with # other output of the compiler, since it emits everything to the same fd. # This script contains a `tsc` wrapper (`_tsc`) that addresses this issue # by filtering out the lines that describe an emitted file and those that # do not and re-emitting them to stdout and stderr respectively. Further, # it emits "sets" of changed files, not just single files which is help- # ful, for example, in the case of babel which seems to perform much better # given multiple files in one go, rather than performing a cold start for # each. It does so by interspering a null-byte after each set of files: # # file 1\nfile2\nfile3\n\0file4\nfile # # This script has been tested to run on git-bash under Windows as well as # Bash 3 on OSX (default). function _tsc { local IFS=$'\n' $TSC_CMD "$@" --listEmittedFiles | awk ' function flush() { if (files != "") { printf "%s%c", files, 0 files = "" } fflush() } BEGIN { files = "" } /.*Compilation complete.*/ { print $0 > "/dev/stderr" flush() next } /^TSFILE:.*\.js$/ { if (files != "") { files = files "\n" } files = files substr($0, 9) } { print $0 > "/dev/stderr" } END { flush() } ' } # Read filepaths on stdin and remove their common leading path to the root of # the project, taking into account Windows pathing. function mk_relpath { while IFS=$'\n' read -r file; do if $IS_WINDOWS; then file=/$(echo "$file" | sed 's/\\/\//g' | sed 's/://') fi eval "echo .${file:$SCRIPT_DIR_LEN}" done } # Build the project from start to finish. All typescript source files are # compiled and the output is run through the babel compiler: # # Typescript -> ES6 -> Babel -> ES5 # # Any adhoc options are passed to the typescript compiler only. Configure babel # behavior using the .babelrc file. Likewise, prefer tsconfig.json to configure # typescript and only use the adhoc options for e.g. watching (-w|--watch). function build { local IFS=$'\n' local -r outdir=$SCRIPT_DIR local relfiles _tsc "$@" |\ while read -d '' -r files; do relfiles=($(mk_relpath <<< "$files")) echo >&2 "babel: compiling ${#relfiles[@]} files" "$BABEL_CMD" >&2 --out-dir "$outdir" "${relfiles[@]}" done } ################################################################################ # Command line interface ################################################################################ # derive the help text from the first comment in a shell script function derive_help { awk ' f && !NF { exit } /^#/ && NR>2 { f=1; sub("^# ?", "", $0); print $0 } ' < "$1" } # print the help text, derived from this file function help { derive_help "${BASH_SOURCE[0]}" } case "${1:-build}" in -h|--help) help ;; build) shift; build "$@" ;; -*) echo >&2 "unknown option: $1"; exit 1 ;; *) cmd=$1; shift; "$cmd" "$@"; ;; esac