Skip to content

Commit

Permalink
fix #1863: make fs.writeSync work in the browser
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Feb 16, 2022
1 parent efe61ee commit 8debc09
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 4 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@

If you type Ctrl+C in a terminal when a script that uses esbuild's JS library is running, esbuild's child process may be killed before the parent process. In that case calls to the `write()` syscall may fail with an `EPIPE` error. Previously this resulted in an uncaught exception because esbuild didn't handle this case. Starting with this release, esbuild should now catch these errors and redirect them into a general `The service was stopped` error which should be returned from whatever top-level API calls were in progress.

* Better error message when browser WASM bugs are present ([#1863](https://github.com/evanw/esbuild/issues/1863))

Safari's WebAssembly implementation appears to be broken somehow, at least when running esbuild. Sometimes this manifests as a stack overflow and sometimes as a Go panic. Previously a Go panic resulted in the error message `Can't find variable: fs` but this should now result in the Go panic being printed to the console. Using esbuild's WebAssembly library in Safari is still broken but now there's a more helpful error message.

More detail: When Go panics, it prints a stack trace to stderr (i.e. file descriptor 2). Go's WebAssembly shim calls out to node's `fs.writeSync()` function to do this, and it converts calls to `fs.writeSync()` into calls to `console.log()` in the browser by providing a shim for `fs`. However, Go's shim code stores the shim on `window.fs` in the browser. This is undesirable because it pollutes the global scope and leads to brittle code that can break if other code also uses `window.fs`. To avoid this, esbuild shadows the global object by wrapping Go's shim. But that broke bare references to `fs` since the shim is no longer stored on `window.fs`. This release now stores the shim in a local variable named `fs` so that bare references to `fs` work correctly.

* Update to Go 1.17.7

The version of the Go compiler used to compile esbuild has been upgraded from Go 1.17.6 to Go 1.17.7, which contains a few [compiler and security bug fixes](https://github.com/golang/go/issues?q=milestone%3AGo1.17.7+label%3ACherryPickApproved).
Expand Down
13 changes: 9 additions & 4 deletions scripts/esbuild.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,13 @@ exports.buildWasmLib = async (esbuildPath) => {
fs.mkdirSync(esmDir, { recursive: true })

// Generate "npm/esbuild-wasm/wasm_exec.js"
const toReplace = 'global.fs = fs;';
const GOROOT = childProcess.execFileSync('go', ['env', 'GOROOT']).toString().trim();
let wasm_exec_js = fs.readFileSync(path.join(GOROOT, 'misc', 'wasm', 'wasm_exec.js'), 'utf8');
let index = wasm_exec_js.indexOf(toReplace);
if (index === -1) throw new Error(`Failed to find ${JSON.stringify(toReplace)} in Go JS shim code`);
wasm_exec_js = wasm_exec_js.replace(toReplace, `
const replace = (toReplace, replacement) => {
if (wasm_exec_js.indexOf(toReplace) === -1) throw new Error(`Failed to find ${JSON.stringify(toReplace)} in Go JS shim code`);
wasm_exec_js = wasm_exec_js.replace(toReplace, replacement);
}
replace('global.fs = fs;', `
global.fs = Object.assign({}, fs, {
// Hack around a Unicode bug in node: https://github.com/nodejs/node/issues/24550
write(fd, buf, offset, length, position, callback) {
Expand All @@ -130,6 +131,10 @@ exports.buildWasmLib = async (esbuildPath) => {
},
});
`);
replace('// End of polyfills for common API.', `
// Make sure Go sees the shadowed "fs" global
const { fs } = global;
`);
fs.writeFileSync(path.join(npmWasmDir, 'wasm_exec.js'), wasm_exec_js);

// Generate "npm/esbuild-wasm/lib/main.js"
Expand Down

0 comments on commit 8debc09

Please sign in to comment.