Giter Club home page Giter Club logo

oven-sh / bun Goto Github PK

View Code? Open in Web Editor NEW
75.5K 586.0 2.9K 215.83 MB

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one

Home Page: https://bun.sh

License: Other

Zig 64.02% JavaScript 1.39% TypeScript 9.37% CSS 0.06% Makefile 0.26% C 2.55% C++ 20.81% HTML 0.04% Shell 0.34% Dockerfile 0.06% AMPL 0.01% Perl 0.09% Objective-C 0.12% CMake 0.38% PowerShell 0.08% Ruby 0.04% HCL 0.01% Rust 0.09% MDX 0.01% Python 0.27%
bun bundler javascript javascriptcore jsx nodejs npm react transpiler typescript zig ziglang

bun's Introduction

Logo

Bun

stars Bun speed

Documentation   •   Discord   •   Issues   •   Roadmap

What is Bun?

Bun is an all-in-one toolkit for JavaScript and TypeScript apps. It ships as a single executable called bun.

At its core is the Bun runtime, a fast JavaScript runtime designed as a drop-in replacement for Node.js. It's written in Zig and powered by JavaScriptCore under the hood, dramatically reducing startup times and memory usage.

bun run index.tsx             # TS and JSX supported out-of-the-box

The bun command-line tool also implements a test runner, script runner, and Node.js-compatible package manager. Instead of 1,000 node_modules for development, you only need bun. Bun's built-in tools are significantly faster than existing options and usable in existing Node.js projects with little to no changes.

bun test                      # run tests
bun run start                 # run the `start` script in `package.json`
bun install <pkg>             # install a package
bunx cowsay 'Hello, world!'   # execute a package

Install

Bun supports Linux (x64 & arm64), macOS (x64 & Apple Silicon) and Windows (x64).

Linux users — Kernel version 5.6 or higher is strongly recommended, but the minimum is 5.1.

# with install script (recommended)
curl -fsSL https://bun.sh/install | bash

# on windows
powershell -c "irm bun.sh/install.ps1 | iex"

# with npm
npm install -g bun

# with Homebrew
brew tap oven-sh/bun
brew install bun

# with Docker
docker pull oven/bun
docker run --rm --init --ulimit memlock=-1:-1 oven/bun

Upgrade

To upgrade to the latest version of Bun, run:

bun upgrade

Bun automatically releases a canary build on every commit to main. To upgrade to the latest canary build, run:

bun upgrade --canary

View canary build

Quick links

Guides

Contributing

Refer to the Project > Contributing guide to start contributing to Bun.

License

Refer to the Project > License page for information about Bun's licensing.

bun's People

Contributors

jarred-sumner avatar dylan-conway avatar paperclover avatar electroid avatar nektro avatar cirospaciari avatar colinhacks avatar alexlamsl avatar hanaasagi avatar zackradisic avatar gvilums avatar donisaac avatar hanford avatar thatonebro avatar zhuzilin avatar 190n avatar pfgithub avatar riskymh avatar xhyrom avatar liz3 avatar huseeiin avatar sno2 avatar zhiyuang avatar jwhear avatar github-actions[bot] avatar daleseo avatar michellbrito avatar alexkuz avatar trnxdev avatar snoglobe avatar

Stargazers

Angelo Oliveira Jr. avatar Julio Rafael avatar Yahya Messelmi avatar Ziyue Ink Zhang avatar Daniel Sam avatar Roham Hayedi avatar Krym avatar Chad avatar Ali avatar vitiacat avatar Tarek Badr avatar R Z avatar Bakhtiyar avatar Bill Kyriazopoulos avatar Alex Kichukov avatar David avatar Mikita avatar Edward Bramanti avatar Trent avatar ████ avatar Carlos Andreo avatar Cutty Robot avatar Andras Csizmadia avatar Victor Frye avatar  avatar Alan Pramil avatar T1ckbase avatar Shreyash avatar  avatar Niclas 🦆 avatar Javier Orfo avatar OpenByte avatar Tomas Lobato avatar Andrey Nering avatar Antoine avatar Dhruv garg avatar  avatar Senseless Sage avatar Bogdan Korshunov avatar  avatar Jack Wright avatar Fredy M. avatar Hyun avatar Zine Moualhi 🇵🇸 avatar destinyFvcker avatar Ragnar Lodbrok avatar Kadir Ince avatar werben avatar Adrien Carpentier avatar MrAngelos6 avatar Emilio Toledo avatar  Li Ying Jie avatar Dean Lofts avatar Jay Ma avatar JJDörig avatar mashroomash avatar Lê Quang Lâm avatar John Happy avatar Blake Wilson avatar eslco avatar Chanho Kim avatar Harish Kukreja avatar Thomas Pham avatar Pat Myron avatar Wembley Leach avatar Nhan Nguyen avatar  avatar ipruning avatar Filipe Ferreira Paulo avatar Hiroyuki Sano avatar Kevin Butler avatar Hatim avatar Carl Jackson avatar Samet avatar Yukee avatar KsaR avatar Yaroslav Augustus avatar zul rahmat avatar Niket Patel avatar Soomin Choi avatar Jake Ascher avatar Francisco Veiras avatar David Georgiyev avatar Nay Win avatar Nguyen Gia Huy avatar Sajid Ahmed avatar Yann MAGNIN avatar hibiki avatar Nikolay Bychkov avatar  avatar  avatar Roger Cruz avatar Albert Leng avatar Alan avatar Carlos Pinheiro avatar Vitalii Kozin avatar Jayanth Kumar avatar  avatar Gurarpit Singh avatar Pao Dayag avatar

Watchers

Luca G. Soave avatar Samuel MORELLO avatar Mathias Biilmann avatar Kyle Maxwell avatar Paul Chavard avatar Karl Jensen avatar Hugo Romano avatar Dejan Ranisavljević avatar Chris Mannes avatar azu avatar Weston avatar Travis Cooper avatar XdF avatar Abhik Khanra avatar Kamil Ronewicz avatar Bilgehan Zeki ÖZAYTAÇ avatar Leon Sorokin avatar  avatar Satoshi Yoshikawa avatar Eli Grey avatar Alberto Gimeno avatar 唐古拉山 avatar SHIN avatar Noam  V avatar Ivan Križnar avatar yuanhong avatar Alex Hayton avatar Sebastian Markbåge avatar Greg Rosen avatar Tobias Taurian Viana avatar Dhi Aurrahman avatar Stefan Ladwig avatar Rafał Kotusiewicz avatar Andrea Giammarchi avatar Matt Briggs avatar Li YuBei avatar Victor Lin avatar React avatar  avatar  avatar vancaem avatar Maurício Kishi avatar  avatar Trygve Lie avatar S.Y. Lee avatar John Whitson avatar parweb avatar Carlos Villuendas Zambrana avatar Chad Hietala avatar Paul H Howells avatar Jason Davis avatar 草色青青 avatar zicjin avatar  avatar Mark Qian avatar Helder Oliveira avatar Kaloyan Ivanov avatar Kim Slawson avatar send2vinnie avatar srobinson avatar Sriram Velamur avatar Allan Henderson avatar Prabin Varma avatar Alexandre Enkerli avatar Richard Hess avatar David O'Halloran avatar Benoit Marchant avatar hiroaqii avatar  avatar Thang Chung avatar Adelar da Silva Queiróz avatar Andrew Harper avatar David Oster aka George Pasparakis avatar Rene Skou avatar Franco Arza avatar Jackson Cooper avatar Jordan Gensler avatar Lance He avatar Javier Mandiola avatar Oleksiy Golovko avatar duansm avatar Noah Blon avatar Benedykt Dryl avatar Nick Dima avatar HoNooD avatar Xiaoyi Chen avatar David avatar  avatar  avatar Justin Vos avatar Marco.Pai avatar Robert Wawrzyniak avatar Craig Baker avatar Andrew Grosser avatar Andrej Badin avatar  avatar Matt avatar Henry Nguyen avatar Dima Khadorkin avatar Easter avatar

bun's Issues

documentation updates for react section to easily integrate with existing CRA

(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:

  1. remove %PUBLIC_URL%
  2. add a <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.

Improve reliability of CommonJS <> ESM interop

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:

  • Why doesn't @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.
  • Functions that recursively loop over the keys of an exported module/namespace eventually stack overflow. This happens because we currently set 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.

Support import assertions

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.

Allow spaces in paths

Currently Bun doesn't escape spaces in paths which result in a truncated path & is causing module not found errors.

Errors seen when environment exports functions

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...

error: Unterminated string literal

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

Fix unicode interop between JSC <> Zig

This affects:

  • fetch()
  • Macros
  • 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.

Fix ?? operator

in:

var hello = foo ?? "world";

current out:

var hello = foo;

expected out:

var hello = foo ?? "world";

Fix calling #private() functions in classes

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.

Fix Catalina support

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

Copy source lines when generating error messages

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

Add a fast `npm install` to Bun's CLI

this is mostly stream of conscious

Why?

  1. npm install is too slow.
  2. Resolving node_modules is too slow. This affects bundlers and Node.js (bun as well)

How to make npm install faster

  • Tooling written in Zig launches much faster than Node.js-based tooling by default
  • binary lockfile format
  • Use a faster zlib library to go from .tar.gz -> .tar. cloudflare's zlib or https://github.com/ebiggers/libdeflate
  • On Linux, use io_uring for I/O
  • Parsing semver versions & ranges should not use regex and allocate as little memory as possible. No copying strings around

The disk cache is a question I'm still thinking about.

  • Probably wouldn't do caching via many small files on disk. Many small files == a lot of syscall overhead and npm clients are performance constrained by (1) network latency to resolve dependent package versions, (2) downloading files and (3) syscall overhead. The common case of running npm install on a package with a lockfile and no changes to dependencies is almost entirely constrained by syscall overhead.
  • A memory-mapped database such as LMDB could be fast, but I worry about reliability and remote filesystems. It could detect, warn & disable the cache if the filesystem is remote.
  • SQLite is a safe bet, but writes aren't very fast. It would be interesting to try storing blobs inside a "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.

A lockfile format that makes other tooling faster

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.

Allow build to output code that runs on Node.js

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 runtime
  • node:fs and other node:* prefixes need to be marked as external
  • Parallelize bun build for performance
  • Output as CommonJS?

The 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.

Configurable feature map

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.

Windows Support

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 😀🚀

Finish implementing React Fast Refresh transforms

Exported components correctly register with react-refresh/runtime. But:

  • Non-exported components need to be registered
  • Hooks need to be registered
  • When building from websockets, the signature hashes need to be generated.

The current version may blow away state changes.

Fix `browser` map

  • Options.Platform.bun should import what browsers do
  • Options.Platform.browser should import what browsers do
  • Options.Platform.neutral should import what browsers do
  • Options.Platform.node should ignore it

These are good test cases:

import algoliasearch from 'algoliasearch/lite'
import { captureException, Severity } from '@sentry/nextjs'

Method calls on numeric literals

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')

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.