2023-03-31 17:19:07 +03:00
|
|
|
/** @file File watch and compile service. */
|
|
|
|
import * as path from 'node:path'
|
|
|
|
import * as url from 'node:url'
|
|
|
|
|
|
|
|
import * as esbuild from 'esbuild'
|
|
|
|
import chalk from 'chalk'
|
|
|
|
|
|
|
|
import * as bundler from './esbuild-config'
|
|
|
|
|
|
|
|
// =================
|
|
|
|
// === Constants ===
|
|
|
|
// =================
|
|
|
|
|
2023-05-11 18:11:03 +03:00
|
|
|
/** The path of this file. */
|
|
|
|
const THIS_PATH = path.resolve(path.dirname(url.fileURLToPath(import.meta.url)))
|
|
|
|
/** This must be port `8080` because it is defined as such in AWS. */
|
|
|
|
const PORT = 8080
|
2023-03-31 17:19:07 +03:00
|
|
|
const HTTP_STATUS_OK = 200
|
|
|
|
// `outputPath` does not have to be a real directory because `write` is `false`,
|
|
|
|
// meaning that files will not be written to the filesystem.
|
|
|
|
// However, the path should still be non-empty in order for `esbuild.serve` to work properly.
|
2023-04-11 09:04:27 +03:00
|
|
|
const ARGS: bundler.Arguments = { outputPath: '/', devMode: true }
|
2023-03-31 17:19:07 +03:00
|
|
|
const OPTS = bundler.bundlerOptions(ARGS)
|
2023-06-06 15:00:07 +03:00
|
|
|
OPTS.define.REDIRECT_OVERRIDE = JSON.stringify(`http://localhost:${PORT}`)
|
2023-03-31 17:19:07 +03:00
|
|
|
OPTS.entryPoints.push(
|
|
|
|
path.resolve(THIS_PATH, 'src', 'index.html'),
|
|
|
|
path.resolve(THIS_PATH, 'src', 'index.tsx'),
|
|
|
|
path.resolve(THIS_PATH, 'src', 'serviceWorker.ts')
|
|
|
|
)
|
2023-06-19 02:02:08 +03:00
|
|
|
OPTS.minify = false
|
2023-03-31 17:19:07 +03:00
|
|
|
OPTS.write = false
|
2023-04-11 09:04:27 +03:00
|
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
|
|
OPTS.loader = { '.html': 'copy' }
|
2023-06-19 02:02:08 +03:00
|
|
|
OPTS.pure.splice(OPTS.pure.indexOf('assert'), 1)
|
|
|
|
;(OPTS.inject = OPTS.inject ?? []).push(path.resolve(THIS_PATH, '..', '..', 'debugGlobals.ts'))
|
|
|
|
OPTS.plugins.push({
|
|
|
|
name: 'react-dom-profiling',
|
|
|
|
setup: build => {
|
|
|
|
build.onResolve({ filter: /^react-dom$/ }, args => {
|
|
|
|
if (args.kind === 'import-statement') {
|
|
|
|
return { path: 'react-dom/profiling' }
|
|
|
|
} else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
})
|
2023-03-31 17:19:07 +03:00
|
|
|
|
|
|
|
// ===============
|
|
|
|
// === Watcher ===
|
|
|
|
// ===============
|
|
|
|
|
2023-05-19 22:55:29 +03:00
|
|
|
/** Start the esbuild watcher. */
|
2023-03-31 17:19:07 +03:00
|
|
|
async function watch() {
|
|
|
|
const builder = await esbuild.context(OPTS)
|
|
|
|
await builder.watch()
|
|
|
|
await builder.serve({
|
|
|
|
port: PORT,
|
|
|
|
servedir: OPTS.outdir,
|
2023-05-19 22:55:29 +03:00
|
|
|
/** This function is called on every request.
|
|
|
|
* It is used here to show an error if the file to serve was not found. */
|
2023-03-31 17:19:07 +03:00
|
|
|
onRequest(args) {
|
|
|
|
if (args.status !== HTTP_STATUS_OK) {
|
|
|
|
console.error(
|
|
|
|
chalk.red(`HTTP error ${args.status} when serving path '${args.path}'.`)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
void watch()
|