-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add example esbuild config with esbuild-rails and watch / reload flags
- Loading branch information
Showing
1 changed file
with
97 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
#!/usr/bin/env node | ||
|
||
// Esbuild is configured with 3 modes: | ||
// | ||
// `yarn build` - Build JavaScript and exit | ||
// `yarn build --watch` - Rebuild JavaScript on change | ||
// `yarn build --reload` - Reloads page when views, JavaScript, or stylesheets change | ||
// | ||
// Minify is enabled when "RAILS_ENV=production" | ||
// Sourcemaps are enabled in non-production environments | ||
|
||
import * as esbuild from "esbuild" | ||
import path from "path" | ||
import rails from "esbuild-rails" | ||
import chokidar from "chokidar" | ||
import http from "http" | ||
import { setTimeout } from "timers/promises" | ||
|
||
const clients = [] | ||
const entryPoints = [ | ||
"application.js", | ||
"administrate.js" | ||
] | ||
const watchDirectories = [ | ||
"./app/javascript/**/*.js", | ||
"./app/views/**/*.html.erb", | ||
"./app/assets/builds/**/*.css", // Wait for cssbundling changes | ||
] | ||
const config = { | ||
absWorkingDir: path.join(process.cwd(), "app/javascript"), | ||
bundle: true, | ||
entryPoints: entryPoints, | ||
minify: process.env.RAILS_ENV == "production", | ||
outdir: path.join(process.cwd(), "app/assets/builds"), | ||
plugins: [rails()], | ||
sourcemap: process.env.RAILS_ENV != "production" | ||
} | ||
|
||
async function buildAndReload() { | ||
// Foreman & Overmind assign a separate PORT for each process | ||
const port = parseInt(process.env.PORT) | ||
const context = await esbuild.context({ | ||
...config, | ||
banner: { | ||
js: ` (() => new EventSource("http://localhost:${port}").onmessage = () => location.reload())();`, | ||
} | ||
}) | ||
|
||
// Reload uses an HTTP server as an even stream to reload the browser | ||
http | ||
.createServer((req, res) => { | ||
return clients.push( | ||
res.writeHead(200, { | ||
"Content-Type": "text/event-stream", | ||
"Cache-Control": "no-cache", | ||
"Access-Control-Allow-Origin": "*", | ||
Connection: "keep-alive", | ||
}) | ||
) | ||
}) | ||
.listen(port) | ||
|
||
await context.rebuild() | ||
console.log("[reload] initial build succeeded") | ||
|
||
let ready = false | ||
chokidar | ||
.watch(watchDirectories) | ||
.on("ready", () => { | ||
console.log("[reload] ready") | ||
ready = true | ||
}) | ||
.on("all", async (event, path) => { | ||
if (ready === false) return | ||
|
||
if (path.includes("javascript")) { | ||
try { | ||
await setTimeout(20) | ||
await context.rebuild() | ||
console.log("[reload] build succeeded") | ||
} catch (error) { | ||
console.error("[reload] build failed", error) | ||
} | ||
} | ||
clients.forEach((res) => res.write("data: update\n\n")) | ||
clients.length = 0 | ||
}) | ||
} | ||
|
||
if (process.argv.includes("--reload")) { | ||
buildAndReload() | ||
} else if (process.argv.includes("--watch")) { | ||
let context = await esbuild.context({...config, logLevel: 'info'}) | ||
context.watch() | ||
} else { | ||
esbuild.build(config) | ||
} |