oven-sh / bun Goto Github PK
View Code? Open in Web Editor NEWIncredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
Home Page: https://bun.sh
Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
Home Page: https://bun.sh
(I can put up a PR if you're welcoming PRs)
Requires react
version >17 because of the react/jsx-dev-runtime
dependency for the compiler
if working with an existing CRA, you need to update ./public/index.html
to:
%PUBLIC_URL%
<script src="/src/index.js" async type="module"></script>
to the document body
.I don't know if you have intentions to include support within bun
to handle this out of the box.
I'd imagine if bun is going to be only for development workflows, then you wouldn't want to mess with the index.html
file.
Bun does not emit code that runs in Node.js. It's very close to doing that, but does not yet.
Blockers:
require
shouldn't import the bundler runtimenode:fs
and other node:*
prefixes need to be marked as externalbun build
for performanceThe best approach might be a Node.js require
and/or ESM loader hook. This would involve using NP-API and writing C bindings. This would make the filesystem watcher work in Node.
This affects:
fetch()
console.log
Bun.readFileAsString
Bun.readFile
The fix is most likely auto-converting to UTF-8 when calling toZigString
, but having some way of tracking memory. Perhaps doing this where it is garbage collected rather than manually managed.
Importing either CommonJS or ES Modules should work at least as well as it does on Node.js and/or Webpack.
While the common case often works fine, there are many edgecases to consider:
@mdx-js/runtime
work correctly? Currently, it throws due to module.exports.default
being marked read only. This is a symptom of a larger issue. One possible fix here is to change all assignments to module.exports
to happen via Object.defineProperty
instead of an assignment. This change should happen in the JS parser and not the printer.default
to point to module.exports, i.e. module.exports.default === module.exports
. This solves many issues with CommonJS interop, but ultimately is too fragile to keep. A better solution is wrapping in a require
which checks for the existence of a Symbol
marked as non-enumerable.However, fixing one-off issues like these as they happen will not produce reliable software. These problems need to be fixed, but to ensure they stay fixed, an integration test suite that runs popular NPM packages and makes sure they successfully load/execute is a better plan. That should be run in an untrusted environment, like a GitHub actions runner and it should not have any permissions or secret keys. It should just have a bun
binary preinstalled.
Error seen when hot reloading code in Chrome:
Uncaught SyntaxError: Invalid or unexpected token
Using bun dev
using bun version 0.0.48. Code within an npm package included this expression:
parseFloat((0.0).toPrecision(precision) + '1')
The code hot-reloaded was:
parseFloat(0.toPrecision(precision) + '1')
It appears bun removed the parenthesis around the number, rendering the code syntactically invalid.
FWIW: adding a space would make it valid:
parseFloat(0 .toPrecision(precision) + '1')
The README and releases tab implies that Windows is not supported for this project.
Is this due to WebKit (JavaScriptCore) being exclusive to *nix platforms (Linux, macOS)?
Are there any plans to support Windows?
The project works great on linux btw 😀🚀
Example:
<img
// data-parent-fit="contain"
data-parent-container={`.${mediaSizerClassName}`}
onClick={onClick}
/>
Bun 0.44 shows an error when parsing a long array of strings:
Error: SyntaxError
warn: Please run `bun bun` from a directory containing a package.json.
error: Unterminated string literal
Found with a small project:
yarn add faker
Create index.js
:
require('faker');
This then errors:
bun bun ./index.js
Runtime for the bundler is 45kb which is stupidly big and most of that is peechy.
This can be feature detected in the install script
It’s really stupid for people to be unable to use Bun on older computers
Errors seen when invoking bun from a bash environment with exported functions (e.g. as used by nvs / nvm):
To reproduce, simple package.json:
{
"scripts": {
"invoke-ls": "ls"
}
}
Then in a bash instance:
# Define a function (details aren't important)
fn() { :; }
# The important bit: export the function
export -f fn
bun run invoke-ls
Error output seen:
$ ls
/usr/local/bin/bash: fn: line 1: syntax error: unexpected end of file
/usr/local/bin/bash: error importing function definition for `fn'
...followed by actual output of ls...
Need to set the minimum OS target in the build.zig
file for macOS x64.
Shouldn't be any other code changes.
Filing an issue so I remember
this is mostly stream of conscious
Why?
npm install
is too slow.npm install
faster.tar.gz
-> .tar
. cloudflare's zlib or https://github.com/ebiggers/libdeflateThe disk cache is a question I'm still thinking about.
npm install
on a package with a lockfile and no changes to dependencies is almost entirely constrained by syscall overhead."packages"
table. Store package names, last updated, then a blob which is a semver sorted array of versions that are known to exist in the registry. Don't bother to cache any of the rest of the package.json, reparse it each time.The purpose of this disk cache would solely be for preventing the extra network trip to the NPM registry to resolve package versions
Then, for storing the .tar.gz
files, I would try just sticking them all in a big folder. The problem with large folders is reading the directory entries gets slower. To fix that, I'd try an index file which would be a binary file with a default name like index.cache
that would effectively be a hash table stored on disk where the keys are filenames. I would test that this is faster in practice than just attempting to open the .tar.gz
which may not exist and handling the error. I would also test if using LMDB is worthwhile for this too.
npm clients & bundlers both have to traverse node_modules
. npm clients know the entire directory tree at package install time, but do not expose this information to other tooling.
Bun would do this differently.
A hypothetical bun install
would persist a lockfile with the entire node_modules directory tree metadata in one binary lockfile and a subset of each package.json relevant to bundling (along with resolved versions and the resolution method, such as whether it was a .tar.gz file or a URL import). This would dramatically reduce the number of syscalls necessary to resolve imports. Instead of calling getdents()
for nearly every directory in node_modules, bundlers could attempt to open file paths directly
URL imports could become "packages" via this lockfile as well.
The lockfile schema would be written using peechy, which would enable JavaScript and Go tooling to consume it as well.
For reviewability, this would be an executable file which on execution would print a human-readable version of the file (same as .bun
files). Assumption: in practice, engineers largely don't review lockfiles by reading them. github bots are fundamentally better suited to surfacing changes in lockfiles for humans to review
Like with .bun
files, the metadata would be numbers and pointers to byte offsets pointing to a single large combined string at the bottom of the file, which makes reading this potentially large file faster.
For symlinks and workspace packages, it wouldn't persist a directory tree. Those would quickly become outdated.
Right now, the bundler always transpiles effectively to ESNext
. This should be configurable, and a limited amount of backwards-compatibility should be possible. Don't need to go as far back as ES6, but perhaps specifically last 2 versions
for Safari.
Currently Bun doesn't escape spaces in paths which result in a truncated path & is causing module not found errors.
Example:
import { a, b, c } from "https://example.com/modules/some/module.js"
This is so you don't have to install it. Nobody is going to remember to install this package, and this seems safe to do because it very infrequently updates. Without react-refresh
, React Fast Refresh doesn't work.
https://github.com/facebook/react/commits/main/packages/react-refresh
That way you know exactly what files led to the error happening
Most likely it's assuming highlight.js
is a file path and not a package path.
Exported components correctly register with react-refresh/runtime
. But:
The current version may blow away state changes.
in:
class foo {
#private() {
this.#bar();
}
#bar() {}
}
current out:
❯ ./build/debug/macos-x86_64/esdev ./src/test/fixtures/nullish-coalesce.js
error: Unexpected private identifier. This is an internal error - not your fault.
}
src/test/fixtures/nullish-coalesce.js:6:2 62
thread 14325726 panic:
error: Unexpected private identifier. This is an internal error - not your fault.
}
src/test/fixtures/nullish-coalesce.js:6:2 62
/Users/jarred/Code/esdev/src/global.zig:343:28: 0x10ac5f8e0 in src.global.Global.panic (esdev)
std.debug.panic(fmt, args);
^
/Users/jarred/Code/esdev/src/js_parser/js_parser.zig:8992:25: 0x10aab30bb in src.js_parser.js_parser.NewParser((struct src.js_parser.js_parser.ParserFeatures constant)).panic (esdev)
Global.panic("{s}", .{panic_buffer});
^
/Users/jarred/Code/esdev/src/js_parser/js_parser.zig:10361:28: 0x10a7b47e8 in src.js_parser.js_parser.NewParser((struct src.js_parser.js_parser.ParserFeatures constant)).visitExprInOut (esdev)
p.panic("Unexpected private identifier. This is an internal error - not your fault.", .{});
^
/Users/jarred/Code/esdev/src/js_parser/js_parser.zig:10179:20: 0x10a7ae0a2 in src.js_parser.js_parser.NewParser((struct src.js_parser.js_parser.ParserFeatures constant)).visitExpr (esdev)
return @call(.{ .modifier = .always_inline }, P.visitExprInOut, .{ p, expr, ExprIn{} });
^
/Users/jarred/Code/esdev/src/js_parser/js_parser.zig:10862:47: 0x10a7b6871 in src.js_parser.js_parser.NewParser((struct src.js_parser.js_parser.ParserFeatures constant)).visitExprInOut (esdev)
e_.index = p.visitExpr(e_.index);
^
/Users/jarred/Code/esdev/src/js_parser/js_parser.zig:11216:49: 0x10a7b87ca in src.js_parser.js_parser.NewParser((struct src.js_parser.js_parser.ParserFeatures constant)).visitExprInOut (esdev)
e_.target = p.visitExprInOut(e_.target, ExprIn{
^
/Users/jarred/Code/esdev/src/js_parser/js_parser.zig:10179:20: 0x10a7ae0a2 in src.js_parser.js_parser.NewParser((struct src.js_parser.js_parser.ParserFeatures constant)).visitExpr (esdev)
return @call(.{ .modifier = .always_inline }, P.visitExprInOut, .{ p, expr, ExprIn{} });
^
/Users/jarred/Code/esdev/src/js_parser/js_parser.zig:12031:45: 0x10a7a76b0 in src.js_parser.js_parser.NewParser((struct src.js_parser.js_parser.ParserFeatures constant)).visitAndAppendStmt (esdev)
data.value = p.visitExpr(data.value);
^
/Users/jarred/Code/esdev/src/js_parser/js_parser.zig:13238:41: 0x10a7a4e0f in src.js_parser.js_parser.NewParser((struct src.js_parser.js_parser.ParserFeatures constant)).visitStmts (esdev)
try p.visitAndAppendStmt(list, stmt);
^
/Users/jarred/Code/esdev/src/js_parser/js_parser.zig:10153:29: 0x10a7a441a in src.js_parser.js_parser.NewParser((struct src.js_parser.js_parser.ParserFeatures constant)).visitStmtsAndPrependTempRefs (esdev)
try p.visitStmts(stmts, opts.kind);
^
/Users/jarred/Code/esdev/src/js_parser/js_parser.zig:10218:43: 0x10a7aca15 in src.js_parser.js_parser.NewParser((struct src.js_parser.js_parser.ParserFeatures constant)).visitFunc (esdev)
p.visitStmtsAndPrependTempRefs(&stmts, &temp_opts) catch unreachable;
^
/Users/jarred/Code/esdev/src/js_parser/js_parser.zig:11284:42: 0x10a7b8c54 in src.js_parser.js_parser.NewParser((struct src.js_parser.js_parser.ParserFeatures constant)).visitExprInOut (esdev)
e_.func = p.visitFunc(e_.func, expr.loc);
^
/Users/jarred/Code/esdev/src/js_parser/js_parser.zig:10179:20: 0x10a7ae0a2 in src.js_parser.js_parser.NewParser((struct src.js_parser.js_parser.ParserFeatures constant)).visitExpr (esdev)
return @call(.{ .modifier = .always_inline }, P.visitExprInOut, .{ p, expr, ExprIn{} });
^
/Users/jarred/Code/esdev/src/js_parser/js_parser.zig:13127:53: 0x10a7ad278 in src.js_parser.js_parser.NewParser((struct src.js_parser.js_parser.ParserFeatures constant)).visitClass (esdev)
property.value = p.visitExpr(val);
^
/Users/jarred/Code/esdev/src/js_parser/js_parser.zig:12331:52: 0x10a7a8a18 in src.js_parser.js_parser.NewParser((struct src.js_parser.js_parser.ParserFeatures constant)).visitAndAppendStmt (esdev)
const shadow_ref = p.visitClass(stmt.loc, &data.class);
^
/Users/jarred/Code/esdev/src/js_parser/js_parser.zig:13238:41: 0x10a7a4e0f in src.js_parser.js_parser.NewParser((struct src.js_parser.js_parser.ParserFeatures constant)).visitStmts (esdev)
try p.visitAndAppendStmt(list, stmt);
^
^C⏎
expected out:
class foo {
#private() {
this.#bar();
}
#bar() {}
}
Or transpile it using the WeakMap
technique. Probably transpile it since Safari support isn't great for all the syntax.
It should probably remove them from the output since browser support is scarce. A better plan, more broadly, is for decisions like this to be configurable instead of just me saying stuff.
in:
var hello = foo ?? "world";
current out:
var hello = foo;
expected out:
var hello = foo ?? "world";
Since we recycle source code buffers, if we don't immediately print error messages (most of the time we print later), the printed sourcecode is potentially garbage memory & often from the wrong file
While we're at it, we probably should implement the SourceLineTracker thing esbuild does to make generating the error location info faster
This breaks compiling Babel with Bun.
This:
import * as $bbcd215f from "http://localhost:3000/node_modules/react/index.js";
Should be:
import * as $bbcd215f from "http://localhost:3000/node_modules/react/index.js";
require($bbcd215f);
This will prevent errors when user A tries to load a persisted node_modules.bun
via @Vbitz https://discord.com/channels/876711213126520882/887787428973281300/905657075185639465
This code:
class Testing {
constructor(private hello: string) {}
toString() {
return this.hello;
}
}
Fails with:
error: Expected ")" but found hello
constructor(private hello: string) {}
It should transpile to:
class Testing {
constructor(hello) {}
toString() {
return this.hello;
}
}
Options.Platform.bun
should import what browsers doOptions.Platform.browser
should import what browsers doOptions.Platform.neutral
should import what browsers doOptions.Platform.node
should ignore itThese are good test cases:
import algoliasearch from 'algoliasearch/lite'
import { captureException, Severity } from '@sentry/nextjs'
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.