• Stars
    star
    1,098
  • Rank 40,832 (Top 0.9 %)
  • Language
    TypeScript
  • License
    ISC License
  • Created about 4 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Lightweight and versatile build tool based on the esbuild compiler

Estrella is a lightweight and versatile build tool based on the fantastic esbuild TypeScript and JavaScript compiler.

  • Rebuild automatically when source files change
  • Build multiple projects at once, in parallel
  • TypeScript diagnostics run in parallel
  • TypeScript diagnostics are optional even for TypeScript projects
  • Ability to remap TSXXXX TypeScript diagnostic severity levels, for example to treat some issues as warnings instead of errors
  • Scriptable — run any JavaScript you want as part of your build process
  • Can run your program automatically when it's rebuilt
  • Well-tested code
  • Fast!

See estrella.d.ts for API documentation.

Estrella tries hard to retain the blazing startup speed of esbuild. Being just a single file, with only a dependency on esbuild, estrella starts very quickly. time estrella -help completes in about 50ms with NodeJS 12. Building a simple example with time examples/minimal/build.js completes in about 65ms.

Unlike some other "builders" Estrella does not use a config file or require you to make changes to your package.json file. Instead, Estrella recognizes & embraces the fact that most projects have unique build requirements. You run Estrella from a script (instead of Estrella running a script or config file.) Essentially you create a "build.js", or lolcat.js—name it whatever you want—script in which you invoke estrella. This turns your script into a fully-featured CLI program with access to a rich API exposed by the estrella module.

Example use

  1. Add Estrella to your project: npm install -D estrella
  2. Create a build.js file in your project directory:
#!/usr/bin/env node
const { build } = require("estrella")
build({
  entry: "src/main.ts",
  outfile: "out/foo.js",
  bundle: true,
  // pass any options to esbuild here...
})

Invoke your build script: (assumes chmod +x build.js has been set)

$ ./build.js -watch
Wrote out/foo.js (419 bytes, 6.84ms)
Watching files for changes...

And that's it for basic use.

See the examples directory for more examples which you can use as templates for new projects.

See evanw/esbuild/lib/shared/types.ts for documentation of esbuild options.

TypeScript diagnostics

If there is a tsconfig.json file in the project directory, or if build({tsc:true}) is set, TypeScript's tsc is run in parallel to esbuild, checking types and providing diagnostics:

$ ./build.js
Wrote out/foo.js (419 bytes, 7.11ms)
src/main.ts:2:7 - warning TS6133: 'count' is declared but its value is never read.

2   let count = 4
        ~~~~~

TS: OK   1 warning

What tsc program is run? estrella will ask nodejs to find typescript in node_modules. If found, tsc from that package is used. Otherwise, tsc from the environment PATH is used. This way there is no hard dependency on typescript for estrella.

estrella allows remapping the severity of TypeScript diagnostics and even filtering things out completely. This is particularly useful when you are converting a codebase to a stricter set of rules but don't want your build to fail. For example, let's say that you enable noImplicitAny in your tsconfig.json file. If you just run tsc on your project, it will fail with errors. Using estrella these errors can be treated as warnings instead, still making a loud appearance on screen but not causing an error exit code.

$ ./build.js
Wrote out/foo.js (14.6kb, 11.07ms)
src/main.ts:212:24 - error TS7006: Parameter 'ev' implicitly has an 'any' type.

212   window.onmousemove = ev => { grid.origin = [ev.clientX, ev.clientY] }
                           ~~
TS: 1 error
$ echo $?
1

To make this a warning, add a rule to build() in your build script:

#!/usr/bin/env node
const { build } = require("estrella")
build({
  entry: "src/main.ts",
  outfile: "out/foo.js",
  bundle: true,
  tsrules: {
    7006: "WARNING",
  }
})

Now if we try to build again:

$ ./build.js
Wrote out/foo.js (14.6kb, 10.42ms)
src/main.ts:212:24 - warning TS7006: Parameter 'ev' implicitly has an 'any' type.

212   window.onmousemove = ev => { grid.origin = [ev.clientX, ev.clientY] }
                           ~~
TS: OK   1 warning
$ echo $?
0

The program exits successfully while still logging the issue.

tsrules is an object of type { [tscode:number] : "IGNORE"|"INFO"|"WARN"|"ERROR" } which maps TS diagnostic codes to:

  • "IGNORE" completely ignore and don't even log it.
  • "INFO" log it as information, unless the -quiet flag is set.
  • "WARN" log it as a warning
  • "ERROR" log it as an error, causing the program's exit code to be !0.

"ERROR" is the default for most issues. Too list predefined tsrules, run: node -p 'require("estrella").defaultTSRules'. Rules which you provide take precedence, so if there are any predefined rules you'd like to change, simply set those in your tsrules object.

In case you need to disable TypeScript diagnostics for a project with a tsconfig.json file, you can set tslint:false in your build config:

build({
  // your regular options ...
  tslint: false,
})

Examples and feature documentation

Your build script becomes a CLI program

When using estrella as a library from a build script, your build script becomes a program with command-line options:

$ ./build.js -help
usage: ./build.js [options]
options:
  -w, -watch         Watch source files for changes and rebuild.
  -g, -debug         Do not optimize and define DEBUG=true.
  -r, -run           Run the output file after a successful build.
  -sourcemap         Generate sourcemap.
  -inline-sourcemap  Generate inline sourcemap.
  -no-color          Disable use of colors.
  -no-clear          Disable clearing of the screen, regardless of TTY status.
  -no-diag           Disable TypeScript diagnostics.
  -color             Color terminal output, regardless of TTY status.
  -diag              Only run TypeScript diagnostics (no esbuild.)
  -quiet             Only log warnings and errors but nothing else.
  -silent            Don't log anything, not even errors.
  -estrella-version  Print version of estrella and exit 0.
  -estrella-debug    Enable debug logging of estrella itself.

You can define your own custom CLI options and parse arbitrary arguments using the cliopts object exported by the estrella module:

#!/usr/bin/env node
const { build, cliopts, file } = require("estrella")
const [ opts, args ] = cliopts.parse(
  ["c, cat" , "Prints a nice cat."],
  ["file"   , "Show contents of <file>.", "<file>"],
)
opts.cat && console.log(stdoutStyle.pink(ASCII_cat))
if (opts.file) {
  console.log(`contents of file ${opts.file}:`)
  console.log(await file.read(opts.file, "utf8"))
}
build({ ... })

Ask for help to see your options documented:

./build.js -h
usage: ./build.js [options]
options:
  [...common estrella options here...]
  -c, -cat           Prints a nice cat.
  -file=<file>       Show contents of <file>.

For a full example, see examples/custom-cli-options

Watching source files for changes

One of the key features of Estrella is its ability to watch source files for changes and rebuild only the products needed. It does this in cooperation with esbuild which provides "perfect" information about the source file graph for a given build product (via esbuild.metafile). Estrella then uses this information to watch the relevant source files for changes and trigger a rebuild. Either set watch in your config or pass -watch on the command line:

$ ./build.js -watch
Wrote out/main.js (341B, 8.03ms)
Watching files for changes...

# [make an edit to a source file]
1 file changed: foo.ts
Wrote out/main.js (341B, 10.18ms)
...

Running your program

Estrella can run and manage sub processes, making it easy to run and restart your program upon a successful build. Simply set run in your config or pass -run on the command line:

$ ./build.js -run
Hello world

Combining -run with -watch makes for a powerful "exploratory programming" setup where changes to your source files are compiled and the results of running the program shown.

$ ./build.js -watch -run
Wrote out/main.js (341B, 8.21ms)
Running out/main.js [98609]
Hello world
out/main.js exited (0)

# [make an edit to a source file]
1 file changed: message.ts
Wrote out/main.js (341B, 8.21ms)
Running out/main.js [98609]
Hello future

Estrella is good at handling processes and can make a few valuable guarantees:

  • A running process is always terminated before Estrella terminates. The only exception to this is if the estrella process is killed with an uncapturable signal like SIGKILL.
  • A running process that is restarted is always terminates before a new instance is launched. This is important if your program relies on exclusive access to resources like TCP ports or UNIX sockets.
  • Secondary subprocesses spawned by a running process are always terminated when the process Estrella controls is terminated. This guarantee only applies to OSes that support signaling process groups (most POSIX OSes like Linux, macOS, BSD, etc.)

"run" can be configured to run arbitrary commands by specifying run in your config.

Examples: (effective process invocation in comment)

// build config               // effective program invocation
run: true                     // [node, outfile] (same as `-run` on the command line)
run: ["deno", "file name.js"] // ["deno", "file name.js"]
run: "./prettier foo.js"      // runs script "./prettier foo.js" in a shell

When run is set in your config, the product will be run no matter how you invoke your build script. If you want to execute a more complex command that just node outfile while still only running it when -run is passed on the command line, conditionally enable run in your build script like this:

#!/usr/bin/env node
const { build, cliopts } = require("estrella")
const p = build({
  entry: "main.ts",
  outfile: "out/main.js",
  run: cliopts.run && ["/bin/zsh", "-e", "-c", "echo **/*.ts"],
})

./build.js -run will run your command as specified while simply ./build.js won't cause the program to run.

Building multiple products at once

estrella can build multiple variants of your program at once. Example build.js script:

#!/usr/bin/env node
const { build } = require("estrella")
const common = {
  entry: "src/main.ts",
  bundle: true,
}
build({
  ...common,
  outfile: "out/foo.min.js",
})
build({
  ...common,
  outfile: "out/foo.debug.js",
  sourcemap: true,
  debug: true,
})

Then run the script to build both an optimized product and a debug product:

$ ./build.js
Wrote out/foo.min.js (445 bytes, 6.67ms)
Wrote out/foo.debug.{js,js.map} (2.4kb, 10.59ms)
TS: OK

TypeScript diagnostics are run for all unique tsconfig.json files (or project directory in the absence of a tsconfig.json file), so in this case we get just one report, as is expected.

In fact, since estrella is just a simple library, you can really do whatever you want in your build script.

Pre-processing and post-processing

Setting onStart and/or onEnd in a build config allows you to hook into the esbuild cycle. onStart(config, changedFiles) is called when a build starts and onEnd(config, result) when a build finishes. This works in both -watch mode and regular "one shot" mode.

These callbacks can optionally be async (i.e. return a Promise) which estrella will await. This gives you the ability to perform detailed pre-processing and post-processing, like requesting some stuff from the internet.

Example build script using onEnd to show desktop notifications with node-notifier in watch mode:

#!/usr/bin/env node
const { build } = require("estrella")
const notifier = require("node-notifier")
build({
  entry: "src/main.ts",
  outfile: "out/foo.js",
  onEnd(config, result) {
    config.watch && notifier.notify({
      title: config.title,
      message: result.errors.length > 0 ?
        `Build failed with ${result.errors.length} errors` :
        `Build succeeded`
    })
  },
})

Watching arbitrary files for changes

estrella comes with functions for scanning and watching any files or directories for changes, making it easy to work with other source files not handled by esbuild. Like for example CSS or code generation.

Example build script:

#!/usr/bin/env node
const { build, scandir, watch, cliopts } = require("estrella")

build({
  entry: "src/main.ts",
  outfile: "out/foo.js",
})

function generateCode(file) {
  console.log(`generate ${file} -> ${file}.js`)
  // replace with actual logic
}

// generate all files initially
const dir = "src", filter = /\..*$/i
scandir(dir, filter, {recursive:true}).then(files => {
  files.map(generateCode)
  // in watch mode, generate files as they change
  cliopts.watch && watch(dir, {filter, recursive:true}, changes => {
    changes.map(c => generateCode(c.name))
  })
})

Running a livereload web server

Say you are building a website. You may want to run a HTTP server while in watch mode which automatically reloads your website as you develop it. Simply run a web server like serve-http in your build script:

#!/usr/bin/env node
const { build, cliopts } = require("estrella")
build({
  entry: "src/main.ts",
  outfile: "docs/app.js",
})
// Run a local web server with livereload when -watch is set
cliopts.watch && require("serve-http").createServer({
  port: 8181,
  pubdir: require("path").join(__dirname, "docs"),
})

Now when you run your build script in watch mode a web server is run as well:

$ ./build.js -w
serving ./ at http://localhost:8181/
Wrote docs/app.js (914 bytes, 12.44ms)
TS: OK

estrella as a program

estrella can also be used directly as a program:

$ estrella src/foo.ts -o foo.js
Wrote foo.js (222 bytes, 7.91ms)
TS: OK
$ estrella -h
usage: estrella [options] <srcfile> ...
options:
  -w, -watch           Watch source files for changes and rebuild.
  -g, -debug           Do not optimize and define DEBUG=true.
  -r, -run             Run the output file after a successful build.
  -sourcemap           Generate sourcemap.
  -inline-sourcemap    Generate inline sourcemap.
  -no-color            Disable use of colors.
  -no-clear            Disable clearing of the screen, regardless of TTY status.
  -no-diag             Disable TypeScript diagnostics.
  -color               Color terminal output, regardless of TTY status.
  -diag                Only run TypeScript diagnostics (no esbuild.)
  -quiet               Only log warnings and errors but nothing else.
  -silent              Don't log anything, not even errors.
  -estrella-version    Print version of estrella and exit 0.
  -estrella-debug      Enable debug logging of estrella itself.
  -o=,-outfile=<file>  Write output to <file> instead of stdout.
  -bundle              Include all dependencies.
  -minify              Simplify and compress generated code.
  -outdir=<dir>        Write output to <dir> instead of stdout.
  -esbuild=<json>      Pass arbitrary JSON to esbuild's build function.

<srcfile> is a filename, or "-" for stdin.

See estrella -h for more details.

Developing for Estrella

Like any respectable compiler, Estrella of course builds itself.

Setup instructions:

git clone https://github.com/rsms/estrella.git
cd estrella
npm install

Build instructions:

  • Build debug products: ./build.js -g (add -w for incremental compilation)
  • Build release products: ./build.js (add -w for incremental compilation)
  • Build release products and run all tests: ./test/test.sh (or npm test)
  • Build debug products and run all tests: ./test/test.sh -debug

Contributing to Estrella

Contributions are very welcome! When contributing, please follow these guidelines:

  • Use welcoming and inclusive language
  • Be respectful of differing viewpoints and experiences
  • Gracefully accept constructive criticism
  • Focus on what is best for the community
  • Show empathy towards other community members

Types of contributions and how best to make them:

  • Proposal for a new feature: Open an issue and start a conversion. Please do not create a PR until we've had time to discuss how to best approach the change.

  • Fix for a bug: Please open a PR with your fix and if you can, include a test that fails without your change but passes with it.

  • Minor changes like spelling mistakes: Open an issue and point out the concern. Please do not create a PR for small things like spelling mistakes.

Thank you for being a great person & contributor!

More Repositories

1

inter

The Inter font family
Python
16,727
star
2

peertalk

iOS and Mac Cocoa library for communicating over USB
Objective-C
3,363
star
3

fb-mac-messenger

⚡️ Mac app wrapping Facebook's Messenger for desktop
Objective-C
2,860
star
4

kod

Programmers' editor for OS X [DEAD PROJECT]
Objective-C
2,296
star
5

node-imagemagick

Imagemagick module for NodeJS — NEW MAINTAINER: @yourdeveloper
JavaScript
1,807
star
6

markdown-wasm

Very fast Markdown parser and HTML generator implemented in WebAssembly, based on md4c
C
1,446
star
7

gotalk

Async peer communication protocol & library
Go
1,193
star
8

raster

Raster — simple CSS grid system
CSS
806
star
9

js-lru

A fast, simple & universal Least Recently Used (LRU) map for JavaScript
JavaScript
774
star
10

sol

A sunny little virtual machine
C
516
star
11

scrup

Take a screenshot (in OS X) — paste the URL somewhere a second later
Objective-C
405
star
12

chromium-tabs

[historical] Chromium tabs for cocoa applications (project no longer maintained)
Objective-C
388
star
13

wasm-util

WebAssembly utilities
TypeScript
353
star
14

figplug

Figma plugin builder
TypeScript
336
star
15

cocui

Cocoa meets WebKit for more rapid UI development
Objective-C
329
star
16

ec2-webapp

A template I use to quickly set up Node.js-backed web apps on Amazon EC2
324
star
17

llvmbox

Self contained, fully static llvm tools & libs
C
317
star
18

move

A simple, functional-biased, prototypal and powerful programming language that runs on any ES3 (or better) JavaScript platform, aimed toward people new to programming
JavaScript
302
star
19

immutable-cpp

Persistent immutable data structures for C++
C++
281
star
20

rsm

Virtual computer
C
267
star
21

compis

Contemporary systems programming language in the spirit of C
C
196
star
22

uilayer

CALayer-style API for building rich, high-performance UI graphics in WebKit
JavaScript
192
star
23

sublime-theme

My Sublime Text theme
Python
187
star
24

scripter

The Scripter Figma plugin
JavaScript
178
star
25

hue

A functional programming language
C++
170
star
26

gitblog

Git-based blog/cms for PHP, meant as a replacement for Wordpress
PHP
164
star
27

co

A programming language in early development
TypeScript
147
star
28

graphviz

Graphviz web app
JavaScript
118
star
29

LazyDispatch

Thin API and concept on top of libdispatch (aka Grand Central Dispatch) for Cocoa Objective-C code.
Objective-C
102
star
30

afcgi

Asynchronous/multiplexing FastCGI for nginx (incl. ref server implementation)
C
101
star
31

rsms-utils

Collection of CLI programs to help with everyday computer life
Shell
99
star
32

colang

Programming language and compiler —WORK IN PROGRESS—
C
71
star
33

xsys

A well-defined system API for abstracting the OS platform
C
68
star
34

figma-plugins

Collection of Figma plugins
TypeScript
67
star
35

mkweb

simple static website generator
JavaScript
63
star
36

fontkit

JS & WASM library for working with fonts
C
62
star
37

js-object-merge

3-way JavaScript Object merging -- Object.merge(v1, v1a, v1b) -> v2
JavaScript
54
star
38

smolmsg

Simple messages
Go
54
star
39

tc

Tokyo Cabinet Python bindings — In need of a new maintainer
C
54
star
40

js-wasmc

Simplifies building of WebAssembly modules in C/C++ and JS
JavaScript
53
star
41

sigi-pixel-font

Sigi pixel fonts [archived]
52
star
42

WebView-OSX-Screensaver

WebKit web view as a screensaver on OS X
Objective-C
52
star
43

Go.tmbundle

TextMate bundle for the Go programming language
51
star
44

oui

Web-app client-server framework developed as part of dropular.net
JavaScript
49
star
45

wlang

Programming language in development
C
47
star
46

smisk

High performance web service framework, written in C but controlled by Python. Used by Spotify infra 2009–2015.
Python
45
star
47

memex

Software for archiving my digital stuff like tweets
Go
45
star
48

ckit

The little C kit
C
44
star
49

workenv

My personal work environment
Emacs Lisp
44
star
50

dropub

DroPub — drop and publish. Simple OS X MenuItem managing secure transfer of files in the background
Objective-C
42
star
51

serve-http

Simple, safe single-file local web server
JavaScript
42
star
52

ghp

Go Hypertext Preprocessor
Go
38
star
53

go-uuid

Binary sortable universally unique identifier
Go
38
star
54

TypoFig

Mac app for assisting type design in Figma
Objective-C
38
star
55

opencv-face-track-basics

Basic code for tracking faces and eyes using OpenCV
C++
37
star
56

qemu-macos-x86-arm64

Run arm64 Linux Alpine virtualized on macOS x86_64 with QEMU
Shell
35
star
57

tspkg

Create small, fast and easily-distributable packages from TypeScript projects
JavaScript
34
star
58

go-immutable

Immutable data structures for Go
Go
34
star
59

webkit-editor

Experimental text editor which runs in the browser
JavaScript
32
star
60

html5-video

Video player in HTML5
JavaScript
30
star
61

jo

Go-style JavaScript ES6 compiler and packager, based on Babel
JavaScript
30
star
62

hovden-stitch

A typeface weekend project from 2002 with a classic "stitching"/"embroidery" look
30
star
63

libcss-osx

Building libcss as Mac OS X universal binary. Developed as part of Kod (rsms/kod)
Objective-C
29
star
64

tumblr-theme-hunch

The theme used on my blog
28
star
65

dawn-lib

Builds Dawn on Linux and macOS as one single easier-to-use library
Shell
28
star
66

browser-require

CommonJS module require() for web browsers
JavaScript
25
star
67

jsont

A minimal and portable JSON tokenizer for building highly effective and strict parsers (in C and C++)
C
25
star
68

prog-lang-tutorial

JavaScript
25
star
69

node-fsdocs

Simple, ACID and versioned file-system based document database
JavaScript
25
star
70

js-fragment

Client-side templating for modern thinkers
JavaScript
24
star
71

node-couchdb-min

Simplistic CouchDB client with a minimal level of abstraction and connection pooling.
JavaScript
24
star
72

fontctrl

Font manager, keeping font files up to date with a distributed repository model
Go
23
star
73

nginx_http_push_module

Comet (long-polling) module for nginx
C
23
star
74

web-clipboard-promise

Demonstrates lazily-evaluated clipboard data on the Web platform
JavaScript
22
star
75

bezier-tangent

Bézier curve toy
JavaScript
22
star
76

twitter-icon

Alternative icon for Twitter.app
21
star
77

dropular-2010

Redacted snapshot of dropular.net, May 2010
JavaScript
21
star
78

dawn-wire-example

[WIP] Demo of a minimal but functional Dawn-based WebGPU client and server
C++
21
star
79

phpab

Abstract Base – universal PHP runtime library
PHP
18
star
80

NodeCocoa

Embed node.js in Cocoa or write whole Cocoa apps in node.js
Objective-C
17
star
81

ortho-remote

Some code for playing with the Teenage Engineering Ortho Remote
Objective-C
16
star
82

ml-kern

Kerning done by machines (a project to learn more about ML)
JavaScript
16
star
83

asl-logging

Convenience functions and example code for using ASL (Apple System Log facility)
C
14
star
84

js-miniglob

Minimal glob JavaScript implementation ported from Go's path/filepath
JavaScript
13
star
85

hunch-cocoa

An assortment of Cocoa — mixed extensions and additions to Cocoa
Objective-C
13
star
86

wasm-loader

WebAssembly module loader with import resolution
TypeScript
12
star
87

cmdr

Helps writing command-line programs with subcommands in Go
Go
12
star
88

spotifycocoa

Cocoa framework of libspotify
Objective-C
12
star
89

cgui

super duper simple gui for C, wrapping imgui and stb
C
12
star
90

macfusion

Fork of http://svn.macfusionapp.org/macfusion2/trunk/ — With mainly UI changes like menu item icon and OS-standard volume icons) — Download latest release build: http://cloud.github.com/downloads/rsms/Macfusion/Macfusion.zip
Objective-C
12
star
91

hunch-upload

Multiple concurrent files uploads with progress in pure HTML
JavaScript
11
star
92

functional.js

Work in a functional style with JavaScript and TypeScript
JavaScript
11
star
93

coxlang

Programming language w/ subproject that implements the Go scheduler in C++
C++
11
star
94

lolcatos

The lolcat operating system
Assembly
11
star
95

cometps

Simple comet pub/sub
C
9
star
96

node-imgdb

Image fingerprinting
C++
8
star
97

ssl-client-auth-demo

Demonstrates "client-authenticated TLS handshake"
Shell
8
star
98

connect_facebook

Facebook session support for Connect
8
star
99

mode

Node module manager and repository
JavaScript
8
star
100

flup

Drag-and-drop to quickly put images on Flickr
Objective-C
8
star