esbuild-flavoured react-scripts.
note: this project is still under construction; the following documentation is a guiding principle, until stable release - use with caution
Create a new React project (Yarn version)
$ yarn init$ yarn add react react-domAdd @nathanjhood/esbuild-scripts and esbuild
$ yarn add @nathanjhood/esbuild-scripts esbuildAlias our scripts in your package.json:
Power your React (and React Native Web) projects with esbuild using zero config, including Typescript support:
Bash (Apple, Linux):
$ NODE_ENV=development yarn startPowerShell (Windows):
> $env:NODE_ENV=development yarn startIf you need a React project template to get you started, have a look at:
React single-web-page application projects which consume esbuild-scripts shall (soon) be able to alias the below "script" commands via npm/yarn:
buildfor bundling React single-web-page applicationstestfor running unit test files for React single-web-page applicationsstartfor running a local development server with modern features such as hot reloading/fast-refresh and error overlay middlewareinitfor quickly drafting up a new React single-web-page application project from a chosen template.- Additionally,
ejectmight also provided, which transforms React single-web-page applications into deployable bundles - Additionally, esbuild's Javascript API has some interesting other features that might also get added to the list of available scripts, such as the fast-and-minimal
transform()method
React projects which consume esbuild-scripts shall be able to use the above commands via npm/yarn, providing React projects with the same functionality of the usual react-scripts package, but using - primarily - only ESBuild and NodeJS as dependencies.
Additional features such as fast-refresh, developer error overlay, and support for both Typescript and React Native Web shall be implemented to present a similar experience to using react-scripts for end-consumers of esbuild-scripts.
- port
react-scriptsCLI to modern NodeJS Javascript API and Typescript using a 'test-and-declarations-first' approach - DONE - port
react-scripts buildcommand to the same - DONE - port
react-scripts startcommand to the same - STARTED - port
react-scripts testcommand to the same - PENDING - port
react-scripts initcommand to the same, usingts-esbuild-reactandts-esbuild-react-native-webas the two project skeleton templates - PENDING
Initial ports of all of the above are easily found in the other "preview" projects mentioned in the "See a Preview" section. Those are very much ad-verbatim copies of the original react-scripts, with WebPack swapped out for the nearest ESBuild-equivalent functionality*, and shall be replaced with the esbuild-scripts package once complete.
To build your React single-page web application with ESBuild:
$ yarn buildTo serve your React single-page web application with ESBuild's local development server with fast-refresh and dev error overlay:
$ yarn startTo test your React single-page web application:
$ yarn testTo prepare your React single-page web for deployment as a bundle:
$ yarn ejectWhen invoking this package via its' command line interface (the esbuild-scripts part of the esbuild-scripts build command), additionally functionality is available, with regards to the original react-scripts, such as chaining multiple scripts in a "workflow"-like pattern in a single invocation.
For example, the following commands:
$ yarn esbuild-scripts test$ yarn esbuild-scripts build$ yarn esbuild-scripts startcan be chained together to create a concurrent "for each command":
$ yarn esbuild-scripts test build startEach script shall be passed to esbuild-scripts and invoked in the same order, either concurrently (sync) or simultaenously (async) (see Sync vs Async modes). Addtional arguments, including options (--option=), positionals (option), and option-terminators (--) shall also be correctly parsed and filtered:
$ yarn esbuild-scripts -- test --timeoutMs=20000 -- build --verbose=true -- start --When running multiple scripts in sync mode (the default), each script is used to spawn a child process, where each next process will begin only once the previous process has completed. A typical output might look like this:
$ yarn esbuild-scripts --sync=true test build start
Starting @nathanjhood/esbuild-scripts v0.1.0
┊
├──┐
│ │
│ ├─ Recieved Script: test
│ │ │
esbuild-scripts test: Done in 12.414ms
│ │ │
│ │ └─ test time taken: 29.265ms
│ │
│ ├─ Recieved Script: build
│ │ │
esbuild-scripts build: Done in 12.847ms
│ │ │
│ │ └─ build time taken: 29.711ms
│ │
│ └─ Recieved Script: start
│ │
esbuild-scripts start: Done in 20.315ms
│ │
│ └─ start time taken: 32.566ms
│
├─ @nathanjhood/esbuild-scripts time taken: 147.669ms
┊
Done in 8.66sWhen running multiple scripts with sync mode explicitly set to false, each script is used to spawn a child process, where each process runs simultaneously. A typical output might look like this:
$ yarn esbuild-scripts --sync=false test build start
Starting @nathanjhood/esbuild-scripts v0.1.0
┊
├──┐
│ │
│ ├─ Recieved Script: test
│ │ │
│ │ └─ test time taken: 29.265ms
│ │
│ ├─ Recieved Script: build
│ │ │
│ │ └─ build time taken: 29.711ms
│ │
│ └─ Recieved Script: start
│ │
│ └─ start time taken: 32.566ms
│
esbuild-scripts test: Done in 12.414ms
esbuild-scripts build: Done in 12.847ms
esbuild-scripts start: Done in 20.315ms
│
├─ @nathanjhood/esbuild-scripts time taken: 147.669ms
┊
Done in 8.66sWarnings and errors generated by any step are collected and reported after all steps have completed, and before the command line interface exits; failures should be graceful and do proper cleanup routines internally (remove any listeners, release any references, abort any pending tasks, and allow any pending async operations to safely complete before exiting), and can be reported to the terminal, written to a log file, and/or ignored.
Example where some unknown script names were passed in between some valid ones:
$ yarn esbuild-scripts build foo test bar build baz test
Starting @nathanjhood/esbuild-scripts v0.1.0
┊
├──┐
│ │
│ ├─ Recieved Script: test
│ │ │
│ │ └─ test test taken: 39.177ms
│ │
│ ├─ Recieved Script: build
│ │ │
│ │ └─ build time taken: 22.266ms
│ │
│ ├─ Recieved Script: test
│ │ │
│ │ └─ test time taken: 53.722ms
│ │
│ └─ Recieved Script: build
│ │
│ └─ build time taken: 58.527ms
│
├─ Finished with Warning:
│ ├─ Error Unknown script: foo
│ ├─ Error Unknown script: bar
│ ├─ Error Unknown script: baz
│ ├─ Perhaps you need to update @nathanjhood/esbuild-scripts?
│ └─ See: https://github.com/nathanjhood/esbuild-scripts
│
├─ @nathanjhood/esbuild-scripts time taken: 315.116ms
┊
Done in 8.26sThe above behaviour in which errors and/or warnings are collated and displayed upon completion of all tasks is guaranteed in both sync and non-sync modes.
It is possible to both ignoreWarnings and ignoreErrors.
It is also possible to treatWarningsAsErrors, as in optionally exit (gracefully) and abandon any pending tasks (safely) should any warnings/errors be generated:
$ yarn esbuild-scripts build foo test bar build baz test
Starting @nathanjhood/esbuild-scripts v0.1.0
┊
├──┐
│ │
│ ├─ Recieved Script: test
│ │ │
│ │ └─ test test taken: 39.177ms
Error: Unknown script: baz
at <anonymous> (/home/***/***/cli.ts:308:11)
error Command failed with exit code 1.Valid scripts may also generate their own warnings/errors and render these according to their respective configurations in consuming projects.
Environment variable file support is provided in a fashion that intentionally resembles dotenv, in which multiple cascading files are read in order of most-specific-first.
The convention mentioned exactly matches the React (and dotenv) documentation, where given the following set of .env files in the React projects' root directory, the upper-most file shall have the highest priority in the case of multiple definitions of any variable:
.env.${NODE_ENV}.local
.env.${NODE_ENV}
.env.local
.envimportant - in this convention, the files with the tag *.local in the name should be ignored from any version control systems (i.e., add all *.local files to .gitignore). Those represent variables which are local to your machine; the others, including .env itself, shall therefore be over-ruled by the *.local files, meaning they can be added to version control to serve as useful default fall-backs and/or example use cases.
For the time being while working towards a suitable v0.0.1 baseline, a fully-working first draft of the porting of react-scripts to ESBuild, including the four commands and react/react-native-web project templates, can be found at:
ts-esbuild-react- A react app template using esbuild and Typescript, with working version of all four scriptsts-esbuild-react-native-web- A react app template uing esbuild and Typescript and React Native Web, with working version of all four scriptsnathanjhood.github.io- my under-construction GitHub page, which is the intended final consumer ofesbuild-scripts, and was created from thets-esbuild-react-native-webtemplate; it shall mostly resemble the template but serve as an eventual landing page, linking together all of my individual GitHub Pages under one root URL
*this repository has been created as a means to centralize further extended development of the concepts demonstrated in the above-mentioned projects. In time, their script contents shall be replaced with esbuild-scripts.
Several features from react-dev-utils shall also be ported into this project, as and when need arises; others may be replaced with counterparts which correspond more closely to ESBuild, rather than WebPack (including plugins, where necessary).
The scripts and command-line interface shall be written Typescript-first (with UMD and Module Loader support) using only the NodeJS Javascript API (with Typescript support), developed with tsx, tested using NodeJS Test Runner, and transpiled then bundled with pkgroll; the package should not require any further dependencies, so that consumers should only have one additional package in their dependency lock files (pkgroll is a developer-only dependency, and thus not required for consumers).
GitHub Actions shall be used to run multi-platform, multi-architecture tests, builds, and deployment, to maintain a reliable interface and baseline of functionality across future changes. The workflows shall support a specified array of NodeJS versions, with an intention to provide compatibility as far back as possible, while referencing latest changes and deprecation warnings.
Please feel welcome to express some interest in the project; it might encourage me to allocate more time on it than I currently intend to, post-launch.
Thanks for reading.
- esbuild - minimal Javascript API example using React
- NodeJS - Javscript API documentation
react-scripts- the official, WebPack-flavoured implementation being ported to esbuildcreate-react-app- consumer ofreact-scripts init
{ "scripts": { "build": "esbuild-scripts build", // experimental... "start": "esbuild-scripts start", // experimental... "test": "esbuild-scripts test", // tbd... // etc... }, "dependencies": { "@nathanjhood/esbuild-scripts": "0.0.1", "esbuild": "0.24.0", "react": "18.2.0", "react-dom": "18.2.0", // etc... } }