Improves ESBuild error visibility in development by logging errors to a file and displaying them in the browser when ESBuild fails. Includes a custom esbuild.config.mjs and an EsbuildErrorRendering concern. 🚀
Used 3 times
A
Alemaño
Usage
This template enhances Esbuild error handling in development mode by logging errors to a file and displaying them in the browser.
1. Update your package.json build script
Replace the existing build command inside package.json with:
Replace the existing build command inside package.json with:
"build": "node esbuild.config.mjs"
If you use a custom Esbuild setup, adjust the command accordingly.
2. Review and adapt esbuild.config.mjs
Modify the following settings inside esbuild.config.mjs based on your project’s structure:
Modify the following settings inside esbuild.config.mjs based on your project’s structure:
• entryPoints: Adjust the paths if your JavaScript files are located elsewhere.
• publicPath: Update if your asset serving path differs.
• outdir: Change if your build output is stored in a different directory.
Once set up, run:
Once set up, run:
yarn build
Or start watching for changes with:
yarn build --watch
🚀 Your Rails app will now catch Esbuild errors and display them directly in the browser!
For further information: https://www.dotruby.com/articles/enhancing-esbuild-error-handling-in-a-rails-app
Run this command in your Rails app directory in the terminal:
rails app:template LOCATION="https://railsbytes.com/script/XnJsOq"
Template Source
Review the code before running this template on your machine.
# Add `esbuild_error_*.txt` to .gitignore
append_to_file ".gitignore", "\nesbuild_error_*.txt\n"
# Create the EsbuildErrorRendering concern
create_file "app/controllers/concerns/esbuild_error_rendering.rb", <<~RUBY
module EsbuildErrorRendering
ESBUILD_ERROR = Rails.root.join("esbuild_error_\#{Rails.env}.txt")
def self.included(base)
base.before_action :render_esbuild_error, if: :render_esbuild_error?
end
private
def render_esbuild_error
heading, errors = ESBUILD_ERROR.read.split("\\n", 2)
render html: <<~HTML.html_safe, layout: false
<html>
<head></head>
<body>
<h1>\#{ERB::Util.html_escape(heading)}</h1>
<pre>\#{ERB::Util.html_escape(errors)}</pre>
</body>
</html>
HTML
end
def render_esbuild_error?
ESBUILD_ERROR.file? && !ESBUILD_ERROR.zero?
end
end
RUBY
# Include the concern in ApplicationController
insert_into_file "app/controllers/application_controller.rb",
"\n include EsbuildErrorRendering if Rails.env.development?",
after: "include Pagy::Backend"
# Create the esbuild config file
create_file "esbuild.config.mjs", <<~JAVASCRIPT
import esbuild from 'esbuild'
import fs from 'fs'
const watch = process.argv.includes('--watch')
const errorLogFile = `esbuild_error_\${process.env.RAILS_ENV}.txt`
const onEndPlugin = {
name: 'onEnd',
setup (build) {
build.onEnd((result) => {
if (result.errors.length > 0) {
console.log(result.errors)
const errors = result.errors.map(error => `\${error.location.file}:\${error.location.line}\\n\${error.text}`).join('\\n\\n')
fs.writeFileSync(
errorLogFile,
`esbuild ended with \${result.errors.length} error\${result.errors.length !== 1 ? 's' : ''}\\n\${errors}`
)
} else if (fs.existsSync(errorLogFile)) fs.truncate(errorLogFile, 0, () => {})
})
}
}
await esbuild
.context({
entryPoints: ['app/javascript/**/*.*'],
bundle: true,
sourcemap: true,
format: 'esm',
outdir: 'app/assets/builds',
publicPath: '/assets',
logLevel: 'info',
plugins: [onEndPlugin]
})
.then(context => {
if (watch) {
context.watch()
} else {
context.rebuild().then(result => {
context.dispose()
})
}
}).catch(() => process.exit(1))
JAVASCRIPT
say "Esbuild error handling setup complete!", :green