Compare commits

..

235 Commits

Author SHA1 Message Date
Jarred Sumner
406ffb9e19 wip treeshake nested namespace imports
It doesn't handle several important edgecases. I don't think this code is currently in the right place.
2023-04-29 16:28:27 -07:00
dave caruso
96e113f41c bundler tests: rest of default.test.ts and starting jsx tests (#2765) 2023-04-28 21:08:48 -07:00
Jarred Sumner
bc0c0f7d20 fix several memory issues related to plugins 2023-04-28 18:59:12 -07:00
Jarred Sumner
98583972df cargo cult some code from JSC 2023-04-28 18:57:00 -07:00
Jarred Sumner
994c715700 Fix race condition 2023-04-28 17:46:43 -07:00
Jarred Sumner
e3a0c4e06d Update bun-test.yml 2023-04-28 17:12:01 -07:00
Jarred Sumner
bc43d33be9 move this 2023-04-28 17:10:24 -07:00
Jarred Sumner
73d499ed22 Add a comment 2023-04-28 17:02:12 -07:00
Ashcon Partovi
912ae8d2b5 Improve test runner markdown 2023-04-28 14:58:16 -07:00
Jarred Sumner
26d81fc5ba [resolver] Propagate module type from package.json "exports" when possible 2023-04-28 14:21:18 -07:00
Jarred Sumner
396416a91f Fix crash with invalid input in fetch() 2023-04-28 13:54:22 -07:00
Ciro Spaciari
4515a6373e Improves Body.Value life cycle and Signal life cycle on server.zig (#2752)
* reestruct request body value and signal

* revert react-hello-world

* fix constructInto and test

* fmt

* fix body nullable

* Request can outlive RequestContext

* fmt

* BodyValue is now HiveRef

* hasDecl for Ref and HiveRef

* fix deinit call on Ref/HiveRef

* adds InlineBlob

* fix Bun.inspect when using InlineBlob

* revert InlineBlob

* Fix mimalloc-debug

* Add TODO note

* fix: make node:crypto Hash.copy work correctly (#2761)

This commit will also:
- add a CryptoHasher.copy function
- make CryptoHasher.digest reset the hasher so it can be reused

Resolves #2651

* 💅

* address unicode issue (#2763)

* Fix an oopsie

* Another oopsie

* use inline for

* Fixup

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>

* Request can outlive RequestContext

* fmt

* garantee to have the abort signnal attached to the server before abort the client on bun-server test

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Co-authored-by: Silver <14016168+silversquirl@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2023-04-28 13:40:44 -07:00
Jarred Sumner
c383638ddd Use global allocator tsconfig.json 2023-04-28 10:35:50 -07:00
Ashcon Partovi
af02b75f79 Use setup-bun instead 2023-04-28 10:13:36 -07:00
Ashcon Partovi
a06e90eec3 Fix path of bun in workflow, try 3 2023-04-28 09:58:56 -07:00
Ashcon Partovi
35d470d98a Fix path of bun in workflow, try 2 2023-04-28 09:54:31 -07:00
Ashcon Partovi
05abe8eabe Fix path of bun in workflow 2023-04-28 09:52:15 -07:00
Ashcon Partovi
48671b77be Use GITHUB_PATH instead of cp 2023-04-28 09:44:44 -07:00
Ashcon Partovi
b7c13f2ccc Maybe fix test runner on macOS 2023-04-28 09:41:36 -07:00
Ashcon Partovi
64b9967fe6 Improve test workflow 2023-04-28 09:35:44 -07:00
Ashcon Partovi
ef894c57cf Fix typo in runner 2023-04-28 09:17:06 -07:00
Ashcon Partovi
5734889cc7 Use bun x instead of bunx 2023-04-28 09:13:14 -07:00
Ashcon Partovi
59daabb6e7 Fix manual test workflow 2023-04-28 09:11:55 -07:00
Ashcon Partovi
36df170348 Use Node.js APIs for test runner 2023-04-28 09:07:48 -07:00
Ashcon Partovi
6cf4cabab1 New test runner with better Github integration 2023-04-28 08:42:25 -07:00
Colin McDonnell
1483d73c3a Bundler docs updates + support for naming string (#2767)
* Bundler docs updates

* Remove comments

* Updates

* Fix bunx usages

* Add info about metafile
2023-04-28 08:35:20 -07:00
Jarred Sumner
52c50e3737 address unicode issue (#2763)
* Fix an oopsie

* Another oopsie

* use inline for

* Fixup

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-04-27 08:37:37 -07:00
Jarred Sumner
3ee22065f0 💅 2023-04-27 07:51:30 -07:00
Silver
0060e49923 fix: make node:crypto Hash.copy work correctly (#2761)
This commit will also:
- add a CryptoHasher.copy function
- make CryptoHasher.digest reset the hasher so it can be reused

Resolves #2651
2023-04-27 07:45:32 -07:00
Jarred Sumner
87921520e4 Add TODO note 2023-04-27 05:35:11 -07:00
Jarred Sumner
73467a5736 Fix mimalloc-debug 2023-04-27 05:35:11 -07:00
B. Burt
5a8a418ef4 Remove extra word in docs/index.md (#2758) 2023-04-27 04:00:35 -07:00
Jarred Sumner
df59fe2843 Implement outdir in Bun.build 2023-04-27 03:45:49 -07:00
Jarred Sumner
990f53f986 Don't preallocate unless its profitable 2023-04-27 03:45:09 -07:00
Jarred Sumner
9383333799 Add microbenchmark 2023-04-27 03:44:23 -07:00
Jarred Sumner
4558ea712a very slightly faster open() and writeFileSync() (#2759)
* Make open() slightly faster on macOS

* Support using `writeFileSync` from native code

* Add `openat$NOCANCEL` symbol

* fixups for linux

* do benchmark

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-04-27 03:35:46 -07:00
Jarred Sumner
f1c1f556a3 more esbuild compat 2023-04-26 22:36:56 -07:00
Jarred Sumner
6142f6eb61 Wrap some things in minify_syntax flag 2023-04-26 22:32:48 -07:00
Jarred Sumner
316a75005b Inline spreads of array literals 2023-04-26 22:32:31 -07:00
dave caruso
5b76ee769e bundler tests! (#2741)
* bundler tests!

* tests
2023-04-26 21:57:49 -07:00
Silver
3a203abc10 Use Ninja to build mimalloc and gitignore test/bun.lockb (#2750)
* build: use ninja to build mimalloc

This is both faster than make, and ensures the same generator is
always used, even when CMAKE_GENERATOR exists in the environment.

* chore: gitignore test/bun.lockb
2023-04-26 21:57:25 -07:00
Dylan Conway
75e3546f3a ensure super() is not merged with adjacent statements (#2757)
* ensure `super()` is not merged with adjacent statements

* add TODO
2023-04-26 21:46:35 -07:00
Jarred Sumner
6c6118e210 Fixes #2746 (#2748)
* Fixes #2746

* add test

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-04-26 21:07:40 -07:00
dave caruso
55c05c0a1f fix (#2756) 2023-04-26 20:45:27 -07:00
dave caruso
7d7748f69f docs hotfix (#2755) 2023-04-26 20:27:24 -07:00
Colin McDonnell
8ba13f273c Add bundler documentation (#2753)
* WIP

* WIP

* WIP

* Document API

* Updates

* Polish bundler docs

* Tweaks

* Tweak
2023-04-26 20:07:30 -07:00
Colin McDonnell
68ab71eb13 Basic types for Bun.build (#2713)
* Basic types for Bun.build

* Tweaks

* Updates
2023-04-26 14:54:05 -07:00
Jarred Sumner
ab447e4ff7 Implement file loader in Bun.build (#2745)
* Update bundle_v2.zig

* Implement `file` loader

* Hash in parallel

* Implement `publicPath`

* simplify

* Update bundle_v2.zig

* Implement `#!`

* Remove unnecessary optional

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-04-26 07:22:29 -07:00
Jarred Sumner
149f097ffd Update outdated help 2023-04-25 22:21:40 -07:00
Jarred Sumner
3e374c0ee4 Fix assertion failure
reproduces if building Three.js 10 times in runtime
2023-04-25 22:21:24 -07:00
Jarred Sumner
f42663ce9a Avoid unnecessary copies 2023-04-25 22:11:15 -07:00
Jarred Sumner
c48f7e2663 Fix error with --jsx-production in runtime 2023-04-25 22:10:59 -07:00
dave caruso
0846a4fa80 bundler tests, testing plugins (#2740)
* add cjs2esm stuff

* tests

* plugin testing
2023-04-25 19:13:39 -07:00
Jarred Sumner
2256d43a32 now it works 2023-04-25 08:19:40 -07:00
Jarred Sumner
947634c9ed typo 2023-04-25 07:57:00 -07:00
Jarred Sumner
126885e1fe Implement onResolve plugins in Bun.build(), support multiple onLoad and onResolve plugins (#2739)
* its 2023

* WIP `onResolve` plugins

* more progress

* it compiles

* Lots of small fixes

* Seems to work excluding entry points

* Update BundlerPluginBuiltins.cpp

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-04-25 07:27:18 -07:00
Jarred Sumner
5353d41014 Fixes #2738 2023-04-25 07:25:00 -07:00
Alex Lam S.L
460563ee89 fix make setup (#2731)
- minor clean-ups
2023-04-25 15:13:57 +03:00
Jarred Sumner
3c4f0920b9 Log HTTP requests and responses by default when log level is debug or verbose 2023-04-25 04:01:26 -07:00
Alex Lam S.L
6e16bb67eb [install] fix bun add on non-aliased dependency (#2728) 2023-04-24 17:56:43 -07:00
Jarred Sumner
e9e7645048 In bun run, rewrite usages of npx to bun x instead of bunx to workaround missing symlink 2023-04-24 17:55:34 -07:00
dave caruso
f2112fc0de Continue bundler tests (#2691)
* start refine + skipping some packagejson tests

* some more tests

* stuff

* tests for minify branch

* pkgjson

* add minify/MergeAdjacentVars

* add test for #2699

* more tests!

* more tests

* finish splitting tests

* all but 2 import star tests are good

* test
2023-04-24 14:12:21 -07:00
Jarred Sumner
923ac39c0b Support plugins in Bun.build (#2720)
* wip

* Implement `onLoad` plugins

* Support exceptions and async `onLoad` plugins

* Fix filtering

* Handle empty files

* Fix JSON loader

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-04-24 14:11:59 -07:00
Plecra
98209b8e10 Reduce friction for building with npm (#2723)
This was the only dependency on bun that I encountered while building the
project, and the change to the gitignore ensures that it's easy to
make changes after an npm based build
2023-04-24 04:23:38 -07:00
Jarred Sumner
4b24bb464c Make Bun.build more reliable (#2718)
* One possible implementation to make `Bun.build` work better

* Pass allocator in

* Make our temporary buffers a little safer

* rename

* Fix memory corruption in symbol table

* Add support for deferred idle events in ThreadPool

* Free more memory

* Use a global allocator FS cache

* more `inline`

* Make duping keys optional in StringMap

* Close file handles more often

* Update router.zig

* wip possibly delete this commit

* Fix memory issues and reduce memory usage

* > 0.8

* Switch to AsyncIO.Waker and fix memory leak in JSBundleCompletionTask

* We don't need to clone this actually

* Fix error

* Format

* Fixup

* Fixup

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-04-22 19:44:23 -07:00
Jarred Sumner
7d6b5f5358 Fix minify: true not applying to identifiers 2023-04-21 18:03:27 -07:00
Jarred Sumner
9423693a6e [breaking] In Bun.Transpiler, don't wrap CommonJS modules in export default 2023-04-21 18:03:07 -07:00
Jarred Sumner
8b9462fde5 Add minify option to Bun.Transpiler 2023-04-21 18:02:29 -07:00
Colin McDonnell
caa90ba98e Update TS docs for bun-types changes (#2590)
* Update TS docs for bun-types changes

* Update typescript, remove extends guidance

* Updates

* Tweaks

* Tweaks
2023-04-21 11:35:42 -07:00
Colin McDonnell
55d50565a5 Add tsconfig.json to bun-types (#2587)
* Add tsconfig.json to bun-types. Document 'extends' pattern.

* Updates

* Update bun init to use extends:bun-types

* Update type:module recommendation

* Add note about transpilation. Closes #2553

* Make typescript a peer dep

* Revert changes to docs

* Revert tsconfig extends

* Update readme

* FMC

* Undo changed
2023-04-21 11:34:05 -07:00
Jarred Sumner
dc55e11714 Keep the node crypt otest 2023-04-21 07:25:51 -07:00
Jarred Sumner
613bb4822e Revert "use a lazyily initialized stream for node:crypto createHash (#2652)"
This reverts commit 3a2fd65f20.
2023-04-21 07:18:32 -07:00
Jarred Sumner
a4d0a1961a Revert "implement node:events in javascript (#2604)"
This reverts commit 96a2ed1040.
2023-04-21 07:16:23 -07:00
Jarred Sumner
143ccdbeb6 Fix order 2023-04-21 05:10:03 -07:00
Jarred Sumner
b98f90fc6e Bun.build() partial implementation 2023-04-21 01:04:55 -07:00
Jarred Sumner
281b810664 slightly better minified 2023-04-21 01:04:06 -07:00
Jarred Sumner
ffdac249ae Add comment 2023-04-21 00:52:31 -07:00
Jarred Sumner
541d16f8be Fix bug with merging adjacent vars 2023-04-20 23:57:44 -07:00
Emmanuel Vazquez
b609f9be28 chore(docs): add xcode runtime install to docs (#2706) 2023-04-20 20:03:12 -07:00
Jarred Sumner
b473a0022d Fix whitespace edgecase with export * from 2023-04-20 19:51:20 -07:00
Dylan Conway
94cd68d7a6 append if the previous part is not UTF8 (#2705) 2023-04-20 16:35:01 -07:00
Jarred Sumner
6d5378566a Fix template string folding test
@paperdave --minify-syntax now causes `true` to print as `!0` and `false` to print as `!1`

`undefined` is now `void 0`
2023-04-20 05:44:50 -07:00
Jarred Sumner
c33df9e99f Increase timeouts :( 2023-04-20 05:40:20 -07:00
Jarred Sumner
4dc0364201 Update runner.node.mjs 2023-04-20 05:40:11 -07:00
Jarred Sumner
aa4d47fe2d Improve error message when failing to read a file 2023-04-20 05:30:35 -07:00
Jarred Sumner
3a68ca775f Fix bug with invalid character at the end of comment path 2023-04-20 05:24:29 -07:00
Dylan Conway
d78ecc76c8 Symbol minification (#2695)
* minify

* Update renamer.zig

* --minify-whitespace

* Speed up minification a little

* handle private names

* 5% faster minification

* use helper function

* fix nested scope slots

* `bun build --minify` gets another +8% faster

* print semicolons afterwards

* print semicolon after checking error

* after all error checking

* Delete code for generating legacy bundes

* remove extra whitespace around if statements

* print space before import identifier

* Use `@constCast`

* Make `S.Local#decls` use `BabyList(Decl)`

* Add `fromSlice` helper to `BabyList`

* Remove unnecessary optional chains

* minify `undefined, true, false`

* Another @constCast

* Implement merge adjacent local var

* Support --minify in `bun build --transform`

* skip comments when counting character frequencies

* Don't wrap commonjs with --transform on (unless targeting bun)

* Support --minify in the runtime

* Fix edgecase with import * as

* don't infinite loop

* --trnasform shouldn't mess with require

* Only track comments when minifying

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-04-20 05:23:12 -07:00
Dylan Conway
9e7bfdec8c with body can be an expression 2023-04-20 01:03:38 -07:00
flakey5
f0dd5b8a43 Fix typo in benchmarking docs (#2702) 2023-04-19 19:16:45 -07:00
Jarred Sumner
ea47ed0ee5 Fix broken autocomplete 2023-04-19 00:01:27 -07:00
Alex Lam S.L
36f9fd607a fix make setup (#2693)
- properly reset `JSC_BASE_DIR` after installing `bun-webkit`
2023-04-19 04:55:00 +03:00
dave caruso
96a2ed1040 implement node:events in javascript (#2604)
* initial event emitter reimplementation

* implement most of node:events. tests passing

* work on emitter

* fix importing node:events

* work on event emitter tests

* event work

* event work

* event stuff and experimenting with a lazy createHash

* cleanup crypto stuff i had on this branch

* finish event stuff up

* fix error monitor

* validate listeners are functions

* changes requested
2023-04-18 14:59:51 -07:00
dave caruso
76deb51c29 clarify file io docs (#2689) 2023-04-18 11:09:41 -07:00
Dylan Conway
5712fbd5b9 use properties length instead of capacity (#2687) 2023-04-18 04:13:04 -07:00
Jarred Sumner
b5b4356d52 Prepare for JavaScript Bundler API 2023-04-18 01:01:48 -07:00
Jarred Sumner
d1de291b2a Fix the extremely annoying ./ requirement in bun build 2023-04-18 01:01:31 -07:00
Jarred Sumner
af96e8fcdd Remove spin loop in bun build 2023-04-17 23:03:58 -07:00
Jarred Sumner
9e1745ee1f Fixes #2676 2023-04-17 20:07:08 -07:00
Jarred Sumner
05cb5bb659 Make bun dev CLI flags only show in --help for bun dev --help
This impacts:

--disable-bun.js
--disable-react-fast-refresh
--bunfile <STR>
--server-bunfile <STR>
--public-dir <STR>
--disable-hmr
--use <STR>
2023-04-17 19:20:39 -07:00
Jarred Sumner
dec5b07782 Fix template string folding bug 2023-04-17 18:01:38 -07:00
Jarred Sumner
b758779c49 Fix missing should_fold_typescript_constant_expressions 2023-04-17 17:33:21 -07:00
Jarred Sumner
3a63fe457d Fix DCE bug with new Foo() when pure without arguments 2023-04-17 17:16:57 -07:00
Dylan Conway
a17624942e make sure with is parsed as a block (#2680) 2023-04-17 15:54:02 -07:00
Dylan Conway
1ce60275d0 fix typescript decorators with index and number keys (#2677)
* handle index property key case

* non-method number property

* tests for property keys
2023-04-17 15:26:18 -07:00
Simon Legner
93a43c8fc1 docs: fix code block (#2662) 2023-04-17 13:01:08 -07:00
Jarred Sumner
bffe5e820b more 2023-04-17 08:01:03 -07:00
Jarred Sumner
983d9428a6 Get axios working (#2673)
* Revive node:http tests

* Fix a couple bugs in node:http

* possibly breaking: use `"browser"` exports condition last

* Make URL validation error better

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-04-17 07:13:01 -07:00
Jarred Sumner
fc539c278e cleanup 2023-04-17 05:47:20 -07:00
Jarred Sumner
d19005aa76 Fix access of inactive union field 2023-04-17 05:46:44 -07:00
Jarred Sumner
d2c64300f6 Fixup options parsing 2023-04-17 05:46:29 -07:00
Jarred Sumner
4cb739a8c5 enable minify syntax by default in the runtime 2023-04-17 03:56:52 -07:00
Jarred Sumner
01a03bcce4 Prepare for Bun.build 2023-04-17 03:56:38 -07:00
Jarred Sumner
6b758c809f Fix dynamic require() 2023-04-17 03:45:54 -07:00
Jarred Sumner
746940d21e Fixes #2634 2023-04-17 01:20:38 -07:00
Jarred Sumner
07b4b4ced0 Don't record named exports for deoptimized CJS 2023-04-17 01:18:05 -07:00
Jarred Sumner
e624dd6d4d Deoptimize CJS more 2023-04-17 00:54:03 -07:00
Jarred Sumner
ed2f24e409 Update bun.zig 2023-04-17 00:34:54 -07:00
Jarred Sumner
c650b0b848 bun build should write to stdout instead of stderr
@paperdave this probably breaks all your tests
2023-04-17 00:34:49 -07:00
Jarred Sumner
0514f59288 DCE for some global constructor calls 2023-04-17 00:32:21 -07:00
Jarred Sumner
5a8cfd8390 Deoptimize CJS -> ESM transform on computed property access of exports object
Example:
```js
for (var k in constants) {
    exports[k] = constants[k];
}
```
2023-04-17 00:30:40 -07:00
Jarred Sumner
a2d5e7c570 Update bundle_v2.zig 2023-04-16 23:42:45 -07:00
Jarred Sumner
af0a4c5638 Mark builtins as external for node and bun 2023-04-16 22:48:32 -07:00
Jarred Sumner
eec1a07907 Attempt to automatically handle some cyclical import issues with ESM
Fixes https://github.com/kysely-org/kysely/issues/412
2023-04-16 22:20:22 -07:00
Jarred Sumner
30b0d006fe Fix for ReferenceError: Cannot access uninitialized variable. 2023-04-16 21:49:33 -07:00
Jarred Sumner
413ce0c7a5 Add some comments 2023-04-16 21:04:07 -07:00
Jarred Sumner
c916a55ead Lazily wrap 2023-04-16 20:15:47 -07:00
Jarred Sumner
31319c0177 Add temporary fix 2023-04-16 19:31:45 -07:00
Jarred Sumner
255a805e00 Fix some edgecases with CJS -> ESM unwrapping 2023-04-16 19:31:45 -07:00
dave caruso
eff48cd95c more bundler tests (#2670)
* tests!

* run formatters
2023-04-16 18:57:56 -07:00
Jarred Sumner
338565eea4 Fix test 2023-04-16 07:33:30 -07:00
Jozef Steinhübl
264f3b91b6 fix: replace unknown link with bun docs (#2669) 2023-04-16 07:13:08 -07:00
Jarred Sumner
06dab241ef Unwrap, but we broke code splitting 2023-04-16 06:51:07 -07:00
Jarred Sumner
29cacb7da7 Update cli.zig 2023-04-16 01:56:37 -07:00
Jarred Sumner
e05cc8db90 prepare for unwrapping 2023-04-16 01:56:14 -07:00
Jarred Sumner
09357f55f9 Fix bugs with loading jsxDEV when it should be jsx or vice versa 2023-04-16 01:31:01 -07:00
Jarred Sumner
33049fa6fd Rename E.Require -> E.RequireString and E.RequireOrRequireResolve -> E.RequireResolveString 2023-04-16 01:30:01 -07:00
Jarred Sumner
be5d21a4f1 Delete some legacy bundling code 2023-04-15 18:45:29 -07:00
dave caruso
2dc3f4e030 more work on bundler tests (#2667)
* Fix `make dev` reusing old .o file

* more bundler tests

* document capture

* bundler tests

* bundler tests

* bundler tests

* finish up

* remove bad thing to merge on main
2023-04-15 18:28:21 -07:00
Colin McDonnell
1a7c3cdf3b Add .txt loader docs 2023-04-15 11:52:39 -07:00
Will Richards 2
f1f7369897 toBeFalsy expect counter and test scope check (#2661) 2023-04-15 08:52:46 -07:00
Jarred Sumner
4b3c483cd4 Handle more cases in length 2023-04-15 05:17:37 -07:00
Jarred Sumner
df88b998d6 Mostly implement cross-module constant inlining, but disable it
There are some test failures
2023-04-15 05:17:12 -07:00
Jarred Sumner
b687c3ab88 Implement template string folding
@paperdave can you help write tests for this if not already covered?

example:
```js
if (
  `${1}-${2}-${3}-${null}-${undefined}-${true}-${false}` === "1-2-3-null-undefined-true-false"
) {
  if (
    "\uD83D\uDE0B \uD83D\uDCCB \uD83D\uDC4C".length === 8 &&
    "😋📋👌".length === 6
  ) {
    console.log(`such fold. very inline. wow.`);
  }
}
```
2023-04-15 05:15:46 -07:00
Jarred Sumner
d4436f278c Fix failing to log error with --transform 2023-04-15 02:41:32 -07:00
Jarred Sumner
530f5ef82c Add error for assigning to a constant 2023-04-15 02:32:11 -07:00
Jarred Sumner
9e5efe61a3 Add unset function 2023-04-15 02:31:01 -07:00
Jarred Sumner
82b2c5221b Update bun.zig 2023-04-14 23:09:20 -07:00
Jarred Sumner
e977bfb5a7 Implement --transform CLI flag 2023-04-14 23:09:14 -07:00
Jarred Sumner
81e11ae586 Include the error return trace 2023-04-14 23:08:29 -07:00
Jarred Sumner
0d248568f6 Fix string concat 2023-04-14 23:08:17 -07:00
Jarred Sumner
96d522a7db +6 more passing tests 2023-04-14 22:09:48 -07:00
Jarred Sumner
b4989a316b Support importing .txt files as strings (#2660)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-04-14 17:45:16 -07:00
Jarred Sumner
8b897e1a6b Fix bug with mjs 2023-04-14 04:16:38 -07:00
Kruithne
730074b75d [nit] minor typo in tcp.md (#2657) 2023-04-14 04:00:02 -07:00
Jarred Sumner
f6a4516d66 Upgrade Zig (#2656)
* Upgrade Zig

* Don't add `d` files in github actions

* Revert "Don't add `d` files in github actions"

This reverts commit 446e2dd674.

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-04-14 03:58:38 -07:00
Jarred Sumner
6c69c2b364 Implement @bun annotation 2023-04-14 03:44:41 -07:00
Jarred Sumner
ba057e50c3 Update bun.zig 2023-04-14 03:12:40 -07:00
Jarred Sumner
1e6dcef0c5 fixup pragma parsing 2023-04-14 03:12:33 -07:00
Jarred Sumner
889462a891 Support @jsx, @jsxRuntime, @jsxImportSource, and @jsxFragment pragmas (#2655)
* Support parsing @pragma comments

* Support `@jsx`, `@jsxRuntime`, `@jsxImportSource`, `@jsxFragment`

* Fix bug where NODE_ENV would be development in certain places and production in others

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-04-14 01:49:29 -07:00
dave caruso
3a2fd65f20 use a lazyily initialized stream for node:crypto createHash (#2652)
* lazy hash

* finish up crypto stuff

* remove lockfiles

* ok

* add pipe test

* update this lockfile

* remove unrelated crypto benchmark from this file
2023-04-13 21:55:01 -07:00
Colin McDonnell
267a38f6fc Remove Bun.dns docs 2023-04-13 18:32:22 -07:00
Colin McDonnell
011e157cac Docs restructuring (#2638)
* Restructure

* Update nav

* Reorg

* Reshuffle ecosystem pages

* Split up runtime/runtime

* Back to runtime/index

* Fix issue

* Split up runtime/index

* Add Writing Tests page

* Prettier matcher table

* More updates
2023-04-13 18:26:45 -07:00
Jarred Sumner
0cc56e8efc Update default.test.ts 2023-04-13 18:02:49 -07:00
Jarred Sumner
54ef58db48 Fix default/ReExportDefaultExternalES6 2023-04-13 18:00:39 -07:00
Dylan Conway
476ab24081 fix ambiguous import (#2654)
* check all files before

* better error/warning

* update todo
2023-04-13 17:41:07 -07:00
Jarred Sumner
8a2545a172 Fix default/ReExportCommonJSAsES6 2023-04-13 17:00:24 -07:00
Jarred Sumner
e9016415bc Only set is_web_browser_navigation in debug mode server 2023-04-13 16:33:11 -07:00
Dylan Conway
242aa0be12 Update import-meta.test.js 2023-04-13 16:03:11 -07:00
Ciro Spaciari
041231d7ca fix node-net-test hang (#2649)
* fix tests

* fix fmt

* fix fmt
2023-04-13 15:14:58 -07:00
Ciro Spaciari
bee743fd61 fix(server) fixes UAF of uWS headers (#2648)
* fixes UAF of uWS headers

* fix transfer encoding condition
2023-04-13 15:14:34 -07:00
Jarred Sumner
d7a8037899 Fixes #2645 2023-04-13 14:42:35 -07:00
Nilan Marktanner
d226a054ae Update development.md (#2647) 2023-04-13 09:07:44 -07:00
Jarred Sumner
aeb3bb949b Upgrade WebKit (#2643)
* Missing export

* Regenerate builtins

* Fix crash in require()

* Various breaking JSC changes

* hopefully speed up C++ compilation a little

* Skip failing test fo rnow

* Update WebKit

* Add a comment

* Fix error in postinstall

* Update WebKit

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-04-13 04:11:12 -07:00
Dylan Conway
db15a23a63 import file path and fix disabled browser require (#2642)
* print disabled `require`

* bundle file paths

* update tests
2023-04-13 00:20:59 -07:00
dave caruso
1cc4eb0e3f fix expectBundled precheck (#2641) 2023-04-12 19:30:55 -07:00
Dylan Conway
a03ee18262 fix bundling many entry points (#2640)
* fix going out of bounds when length is over 8

* remove
2023-04-12 19:25:39 -07:00
Ciro Spaciari
108c54134c fix types and add more reliable tests (#2621) 2023-04-12 18:41:40 -07:00
dave caruso
73216b10ce bundler tests (#2635) 2023-04-12 18:41:04 -07:00
Dylan Conway
ff5c522712 bundler bug fixes (#2637)
* append import to outer wrapper prefix

* print space

* require text loader

* import empty esm and cjs

* add text to schema
2023-04-12 18:40:21 -07:00
hiroki osame
14f87156a2 fix(fs): remove readfile (#2630) 2023-04-12 18:40:02 -07:00
Dylan Conway
d8d4abb58e don't increment i if escaped (#2639) 2023-04-12 17:42:56 -07:00
Dylan Conway
4b9b648f8a could include /private/ on macos 2023-04-12 15:22:04 -07:00
dave caruso
519f9aac80 finish refining bundler tests (#2623)
* bundler tests

* test refining, 257/847

* bundler tests, 298/849

* more bundler tests

* finish dce
2023-04-11 18:18:49 -07:00
Ryan Morey
a744f5369d Update development.md (#2625)
* Update development.md

adds the `bash` language specifier to `which clang-15` so that when you click the copy button, it doesn't include the `$`

* Update development.md

* Update development.md

* Update development.md
2023-04-11 13:19:24 -07:00
hiroki osame
14c6023e15 docs: remove dev container section (#2610) 2023-04-11 01:52:54 -07:00
Ciro Spaciari
f91dc8c0d3 always safe deinit socket context (#2611) 2023-04-10 15:05:16 -07:00
Dylan Conway
f4ab79d6bb add original name to list (#2613) 2023-04-10 15:03:27 -07:00
Jarred Sumner
373248ce9c Implement TOML & JSON support in Bun's new bundler (#2609)
* Implement JSON & TOML support in the bundler

* Fix failing to bind namespace imports

* Support namespace exports better

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-04-10 06:35:41 -07:00
Jarred Sumner
5c37d0f2a5 Parse import attributes
https://github.com/tc39/proposal-import-attributes#import-attributes
2023-04-09 07:49:08 -07:00
Jarred Sumner
7bd6a1f86d Remove usages of void{} in favor of {}
See https://github.com/ziglang/zig/issues/15213
2023-04-09 05:39:05 -07:00
Jarred Sumner
1e717dd941 Add some test coverage for instantiation expressions
Related to #2203
2023-04-09 05:07:44 -07:00
Jarred Sumner
e9d6a4042f Fix another case with instantiation expressions
Related to #2203
2023-04-09 05:07:28 -07:00
Jarred Sumner
c97cb4ec1e Lower for-in variable initializers 2023-04-09 05:07:07 -07:00
Jarred Sumner
21acc50d88 Fixes #2594 (#2600)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-04-09 03:43:04 -07:00
Jarred Sumner
b34f0da499 Fixes #2599 2023-04-09 03:18:26 -07:00
Jarred Sumner
eb18101d84 Update TypeScript parsing to 5.0 (#2593)
* update syntax

* seems to work, needs tests

* This test wasn't supposed to be added

* Many bugfixes to TypeScript parser

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-04-09 03:16:11 -07:00
dave caruso
2117723642 Fix callout tag on development docs (#2595)
* fix callout tag on development docs

* add notes on cmakeconfig.h

* Update Makefile
2023-04-08 20:05:05 -07:00
dave caruso
461ae27d31 Rewrite Developer Docs, Improve DX for new users, moving away from Devcontainer (#2588)
* new docs starting point. missing alot of information

* very experimental idea: make setup

* run on ubuntu 20

* builds on ubuntu 20 (wsl) now

* add release instructions

* add valgrind note from jarred/new-bundler branch, just in case it gets lost when rebasing

* changes requested
2023-04-08 02:23:11 -07:00
Jarred Sumner
ba7a8a9cb5 Fix node: prefix when --platform=node 2023-04-07 23:15:19 -07:00
Jarred Sumner
c764543af5 Fix sort 2023-04-07 22:33:33 -07:00
Jarred Sumner
60fc80d4c4 Workaround crash
https://github.com/ziglang/zig/issues/15204
2023-04-07 22:12:19 -07:00
Jarred Sumner
6362414d65 Bun gets a new bundler (#2312)
* alright now just gotta try running it

* fix a gajillion compiler errors

* even more code

* okay i fixed more errors

* wip

* Update launch.json

* Update string_builder.zig

* `fast_debug_build_mode` makes debug build 2x faster

* Update bundle_v2.zig

* more code!

* It bundles!

* Rename `Bun.Transpiler` to `Bun.Bundler`

* `import()` expressions almost work

* wip attempt to get import() expr to work

* Bundle namespace imports

* Attempt to fix the issue with import() unsuccessfully

* consider current working directory when resolving relative paths (#2313)

* consider current working directory when resolving relative paths

fixes #2298

* comment test

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>

* support `expect().toThrow(/pattern/)` (#2314)

- fix time-zone-dependent test failure

* fix missing `Blob` error messages on Linux (#2315)

* fix & clean up tests (#2318)

- skip flaky tests when running as `root`
- use `expect().toThrow()`
- clean up temporary files after tests

* feat(tty): add some `tty.WriteStream` methods to `process.{stdout, stderr}` (#2320)

* feat(stdio): add some `tty.WriteStream` methods

* chore(builtins): add process builtin gen'd code

* Fix docker install command

* `bun test` on macOS in GitHub Actions (#2322)

* Fixes #2323

* throw invalid parameter errors in `crypto.scryptSync` (#2331)

* throw invalid parameter errors

* remove comptime, add empty buffer function

* remove error_name comptime

* Add reference documentation for bun:test (#2327)

* Reorganize tests (#2332)

* Fix html-rewriter.test.js

* fix the wrong thing being incremented in hmr example (#2334)

* Add more test harness

* Improve Benchmarking page, small fixes (#2339)

* Improve benchmarking page

* WIP

* Add typescript instructions to hot

* Document preload in Plugins. Fix loader in plugin types.

* Fix typo

* Fix links

* run prettier

* Document openInEditor

* improve `Buffer` compatibility with Node.js (#2341)

* improve `Buffer` compatibility with Node.js

* use `memmove()`
allow `encoding` to be `undefined`

* run `bun test` after macOS builds (#2343)

* "binary" is an alias of "latin1"

Fixes https://github.com/oven-sh/bun/issues/2110

* More spec compliant `Blob.prototype.type` (#2340)

* Make `Blob.prototype. type` more spec compliant

* Add a few more checks for isNumber()

* Fix `make headers`

* Safer JSValue.isString()

* More tests for blob.slice

* Make `Blob.prototype.type` more spec compliant

* Add isASCII check

* Fix types

* Fix failing type test

* Update blob.zig

* Update blob.zig

* Fix .eql check on empty values

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>

* Fix bug in test runner

* Support `import()` expressions

* Implement `require()`

* clean up bit_set.zig slightly

* Move some things around

* misc cleanup

* Cleanup some things

* Fix a lot of stuff

* Fix `module.exports.fn = fn;` in ESM entry point

* Fix crash due when printing file

* Fix issue with class names

* Fix issue with `export default identifier`

* Update js_parser.zig

* optimization: inline single-property object acceses and arrays

* Fix undefined memory in renamed symbols list

* Handle call target

* wip

* Inline it

* Fix undefined memory issue when reclaiming blocks in ast

* Halt linking on any parse errors

* alias

* Rename `enable_bundling` to `enable_legacy_bundling`

* Workaround anonymous struct literal zig bug

* Use slower approach (without bitset) because it doesn't break after 8 symbols

* Fix incorrectly-renaming statically defined symbols

* Handle more edgecases in our bit_set fork

* Reduce number of allocations for `define`

* Do not rename unbound symbols

* Clean up dot defines a little more

* Make the generated names prettier

* Workaround runtime symbol missing issue

* Fail the build on errors

* Support export * from

* Support `--outfile`

* partially fix renaming

* fanicer symbol renaming impl

* misc, extremely revertible cleanup

* Fix up some bugs with symbol renaming

* formatting

* Update launch.json

* Parse `__PURE__` comments

* clean up simd code for pure comments

* changes to merge

* workaround runtime issue

* Fix issue with `export * as` not propagating correctly

* Make all top-level declarations `var` when bundling

* Fix missing prefix

* Fix assigning to stack copy

* Fix missing runtime symbol

* Fix bug with namespace exports

* Dramatically reduce allocations

* Update launch.json

* Add missing flags

* Update js_parser.zig

* small cleanup

* Make the export name better

* Fix unnecessary `var foo = foo`

* Implement CommonJS -> ESM conversion

* Implement module redirects

* Port esbuild bundler tests for new bundler (#2380)

* started porting esbuild tests

* clean up test names and api before moving on

* port tests using a program i wrote

* replace todo generated comment

* fix generated tests not including some files

* work on tests

* [github web editor] add define, external, inject, minifySyntax, minifyWhitespace options.

* get most of the todo comments out of the way, but expectBundled does not handle most of the cases

* continue working on esbuild tests

* use test.skip for unsupported tests

* Fixups for test runner

* Hoist imports & exports

* Fix test

* Hoist classes

* bundler test refining, 51/835

* Fix runtime require

* bundler test refining, 81/835

* bundler test refining, 93/835

* Make the test work in any timezone

* feat(expect): update toBeInstanceOf (#2396)

* feat: update instanceof binding

* fix: according to PR comments

* Rename `expectObjectTypeCount` to `expectMaxObjectTypeCount`

* Fix socket tests with connection errors (#2403)

* release pending activity with connection error handler

* unref poll_ref

* remove trailing comma

* Organize Dockerfiles for official status

* Remove test Dockerfile

* Remove old Docker workflow

* Feat(test): add toMatch (#2404)

* Fix various fetch/response/request tests (#2416)

* fix most fetch tests, skip a few

* fastGet, toValueGC, and invalid init

* bigint unreachable, range error, log process as process

* remove extra fetch_headers

* remove js_type parameter, check isObject()

* throw invalid mime type error, use enum literal

* switch back to promise rejection

* RangeError pascal case

* Fix several bugs (#2418)

* utf16 codepoint with replacement character

* Fix test failure with `TextEncoder("ascii')`

* Add missing type

* Fix Response.prototype.bodyUsed and Request.prototype.bodyUsed

* Fix bug with scrypt error not clearing

* Update server.zig

* oopsie

* 💅

* docs: Use correct url in the 'Issues' link in README header (#2420)

* Fix crash when rendering error page and the server or network is slow

* [fetch] Make the default body value `null` when unspecified

This is better aligned with the fetch spec

* Make node-net tests less flaky

* [node:net] Fix issue with `listen` callback firing before it's listening

* Always clear timers in node test harness

* Fix out of bounds access

Repro'd in Buffer tests

* Update UWS

cc @cirospaciari

* Make this test more thorough

* Hanging abort test

* 0 length body is a null stream

* Several bug fixes (#2427)

* Fix test

* Fix segfault when unexpected type is passed in `expect().toThrow`

* Fix issues with request constructor

* Don't bother cloning headers when its empty

* woops

* more tests

* fix incorrect test

* Make the fetch error messages better

* Update response.zig

* Fix test that failed on macOS

* Fix test

* Remove extra hash table lookups

* Support running dummy registry directly

cc @alexlamsl

* Update test

* Update test

* fixup

* Workaround crash in test runner

* Fixup test

* Fixup test

* Update os.test.js

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>

* Remove usages of port numbers in tests

* Set -O2 and -fno-rtti

* Remove -g

* Prevent undefined memory access

* [bun test] Implement `--rerun-each` flag to run each test N times

* Reduce number of module scopes created

* add some extra abort checks into streams (#2430)

* add some checks to avoid UAF

* avoid multiple calls to finalize if endFromJS is called more than once

* fix no-op comment

* mark as requested_end on abort

* remove requested_end from abort

* remove unnecessary check (#2432)

* Fix bug with scoped aliased dependencies in bun install on macOS

* remove `addLog`, remove `--prominent-compile-errors`

* Finish the upgrade

* Optional chaining flag

* Implement same_target_becomes_destructuring optimization

* bundler test refining, 109/835

* Reset bindings

* Support multiple entry points

* Implement `--entry-names` flag

* Use a tempdir with a better name

* prettier

* Log file name

* Update js_parser.zig

* Mark all bun builtins as external

* Make resolve errors actually errors

* Update bundler_default.test.ts

* Fix `await import(foo)`

* WIP react server components

* Do more stuff at runtime

* ✂️

* Support automatic JSX imports

* Use a module cache for now

* Update tsconfig.base.json

* Fix ThisOutsideFunctionNotRenamed

* woopsie

* moar cpu

* clamp it

* fixup

* Add a bunch of assertions

* Bun uses automatic runtime by default

* Parse Import Attributes

* Add a note about Valgrind

* Update developing.md

* Fix up code splitting for React Server Components

* Implement client component manifest

* Fix crash with --react-server-components and no client components

* Backport 4d31e3c917

* Update launch.json

* Fix for latest zig

* Workaround bug with ?[]const string

Occasionally saw alignment errors in this code

Workaround https://github.com/ziglang/zig/issues/15085

related: https://github.com/ziglang/zig/pull/15089

* switch to regular slice

* Avoid initializing named_imports and named_exports as undefined

* Reduce usages of `undefined`

* Add more assertions

* --watch wip

* Update javascript.zig

* Possibly fix the race condition

* Faster `do`

* bump allocator

* Reduce the size of `Symbol` slightly

* Alphabetically sort runtime import symbols, for determinism

* Prepare for code splitting

* handle overlapping stdout

* pure

* clean up some things

* Fix bug with `$$typeof`

* Address CommonJS -> ESM hoisting bug

* Support `"use server"` in manifest

* Implement `"use server"`

* Fix importing bun builtins when bundling

* Make `commonjs_to_esm` a feature flag, fix some splitting bugs

* ✂️

* fixme remove this

* Fix crash in longestCommonPath

* Chunking! Just need to do import paths now.

* Import paths work...now trying to figure out how to make runtime symbols work

* add workaround

* Replace `bun bun` with `bun build`

* Fix crash with dual package hazard

* Fix many CommonJS <> ESM interop bugs

* Support package.json `"sideEffects"`

also skip loading unnecessary package.json data in `bun run`

* add a not good --watch implementation

* bundler test refining, 140/831

* remove accidentally committed file

* do not return status code 1 on successful bundles

* bundler test refining, 159/830

* pass exit code to exitOrWatch

* clean up help menu

-remove two spaces to line up bun build
-moved all <r> tags to the end of the text they are colorizing
-moved other colors to the start of the text they colorize
-removed unneeded <r> tags, keeping only one at the start of the block

* importstar is fully ported

* wip

* you can run code in this branch now

* Disable this transform

* organize and document bundler tests

* Fix double import

* Fix sloppy mode function declarations

* Disable our CommonJS transform for now

* add `assertNotPresent` to make splitting cases easier

* Bump!

* Update bun.d.ts

* use import.meta.require in runtime code

* Disable this again

* Fix dirname

* Fix ESM -> CJS wrapper

* 💅

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Co-authored-by: Alex Lam S.L <alexlamsl@gmail.com>
Co-authored-by: Derrick Farris <mr.dcfarris@gmail.com>
Co-authored-by: Ashcon Partovi <ashcon@partovi.net>
Co-authored-by: Dylan Conway <35280289+dylan-conway@users.noreply.github.com>
Co-authored-by: pfg <pfg@pfg.pw>
Co-authored-by: Colin McDonnell <colinmcd94@gmail.com>
Co-authored-by: dave caruso <me@paperdave.net>
Co-authored-by: zhiyuan <32867472+zhiyuang@users.noreply.github.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
Co-authored-by: Kamil Ogórek <kamil.ogorek@gmail.com>
Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com>
2023-04-07 20:08:01 -07:00
Ashcon Partovi
c0c5f07218 Fix trailing slash bug in upload script 2023-04-07 16:05:47 -07:00
Ashcon Partovi
0a91dd9f71 Fix environment variables in workflow 2023-04-07 15:42:41 -07:00
Ashcon Partovi
bed56ab406 Upload releases to S3 2023-04-07 15:38:38 -07:00
Jake Boone
4978a6b74d Add TSConfig object type to TranspilerOptions interface (#2545) 2023-04-07 15:16:21 -07:00
hiroki osame
35b279a4bb chore: simplify prettier command and cache (#2589) 2023-04-07 09:11:23 -07:00
Colin McDonnell
c8e09f563f FileBlob -> BunFile, add BunFile.lastModified (#2581)
* Improve BunPlugin types

* FileBlob -> BunFile

* Update Bun.env types. Fixes #2481

* Add lastModified to BunFile
2023-04-07 04:03:06 -07:00
Ciro Spaciari
6baedd27bc feat(tls.Server) basic support (cert, key, rejectUnauthorized, requestCert, ca) #2412 (#2552)
* cherry picked

* add StringOrBuffer parameter

* Format and adds types

* update uws

* fix tests

* more types

* fix typing

* add timeouts, clean some stuff

* move tests to describe

* fixes SSL hostname when Host is provided

* cleanup on tests

* change 127.0.0.1 to 0.0.0.0

* try another listening parameter

* test timings and update uws

* remove unnecessary comment

* move listening event around

* always await Bun.connect

* do not fail if the tests already passed when using Bun.connect

* regenerate classes

* undo generated classes

* generate classes

* fix merge

---------

Co-authored-by: cirospaciari <cirospaciari@MiWiFi-RA82-srv.cirospaciari>
2023-04-07 04:02:05 -07:00
Jarred Sumner
5465a3980a Proactively add these to the list 2023-04-06 19:30:50 -07:00
Jarred Sumner
b6bd7e24d7 Bump 2023-04-06 19:30:38 -07:00
dave caruso
e4e81bc49e fix: export constants from fs/promises (#2567)
* fix: export `constants` from `fs/promises`

* fix type tests

* third time's the charm fixing the typedef

* run fmt

* remove injected constant from fs, re-exporting from fs/promises
2023-04-06 15:55:23 -07:00
dave caruso
b8aca35b76 docs: add a section on uninstalling bun (#2560) 2023-04-06 15:12:59 -07:00
Jozef Steinhübl
68670eeb7b docs(cli/bunx): add notice (#2574)
* docs(cli/bunx): add notice bunx alias bun x

* docs: grammar
2023-04-06 15:09:20 -07:00
Dylan Conway
2b170c9d13 Fix toEqual when the second array has extra array holes (#2580)
* iterate through remaining indexes, keep prop identifier

* tests

* format
2023-04-06 14:49:07 -07:00
Zhongwei Yao
1d138057cb Add last modify field "mtime" for FileBlob (#1431) (#2491)
* Add lastModified field for FileBlob (#1431)

lastModified value is epoch timestamp in millisecond unit.

* update according to review comment.
2023-04-06 14:01:49 -07:00
dave caruso
f788519263 bun-types: infer strict Subprocess from Bun.spawn() options, part 2 (#2573) 2023-04-06 13:59:06 -07:00
Dylan Conway
8a73c2a453 cache needs to update, move to another process (#2578) 2023-04-06 13:58:01 -07:00
hiroki osame
21978dabe5 fix(ws): export Server (#2575) 2023-04-06 04:18:17 -07:00
hiroki osame
aa4c4a9b22 docs(CONTRIBUTING): referece development guide (#2576) 2023-04-06 04:18:02 -07:00
dave caruso
569d4940bb rebase (#1501) 2023-04-05 19:15:06 -07:00
Colin McDonnell
4af78c7d5a Update typecheck (#2572)
* Update typecheck

* Test ci

* Test ci

* Prettify files
2023-04-05 18:31:13 -07:00
Jarred Sumner
cfb1c661d5 prepend 2023-04-05 18:29:41 -07:00
Jake Boone
864302a634 Add tests for bun test with preload scripts (#2566)
* Use zsh-compatible syntax in cowsay example

zsh interprets the string !" differently than bash or sh, but we can use single quotes in all of them. See https://unix.stackexchange.com/a/497335/548905.

* Add tests for bun:test with preload scripts

* Look at `stderr` in `bun test --preload` tests
2023-04-05 18:28:41 -07:00
Jarred Sumner
b50f3d3f6f Disable buffering when we clear terminal
hopefully fixes an issue reported in Discord
2023-04-05 18:27:43 -07:00
Jarred Sumner
65d646bc68 Prettier 2023-04-05 18:27:02 -07:00
Ciro Spaciari
d8c467be42 fix(fetch.proxy) fix proxy authentication (#2554)
* fix proxy authentication

* add auth tests

* remove unused
2023-04-05 17:48:18 -07:00
hiroki osame
fd680d6c1d fix: build warnings (#2562) 2023-04-05 17:38:47 -07:00
Lawlzer
f7d0eee0ac In Documentation, move --watch before the script name (#2569)
Related message by Jarred: https://discord.com/channels/876711213126520882/876711213126520885/1093286199369682944
If you put `--watch` after the script name, it will not work.
2023-04-05 15:02:08 -07:00
Dylan Conway
ac092a1e04 fix deepEquals with array holes and accessors (#2557)
* `deepEqual` handles slow array indexes

* another test

* oops

* remove bad test

* compare indexes in non-strict mode

* more tests
2023-04-05 13:39:51 -07:00
hiroki osame
fd5bb6b201 fix: modules to have null prototype (#2561) 2023-04-05 00:31:58 -07:00
Jarred Sumner
d8360ab3cf 🕐 🕑 🕒 2023-04-04 16:50:03 -07:00
Jarred Sumner
a369fc8c89 Implement import.meta.main (#2556)
* Implement `import.meta.main`

* Update main-test-1.js

* Update fs.test.ts

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-04-04 16:49:33 -07:00
Jarred Sumner
54d6f95f43 Dylan/fix some failing tests (#2544)
* handle `umask()` invalid arguments

* move `bktree-fast` to test root, fix postinstall

* fix fs test

* could be baseline

* handle different timezones

* accidentally deleted tests

* fix hang in `AbortSignal.timeout`

* bring abort tests back

* Revert "bring abort tests back"

This reverts commit 0ff2ad5bf4.

* bunx node-gyp

* bun x

* fix typecheck

* test

* Update inspect.test.js

---------

Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2023-04-04 16:47:57 -07:00
Colin McDonnell
76adc5be8a Add npm benchmark (#2555)
* Add install bench

* Update scripts and readme

* remove lockfiles

* Format bench

* Add dev instructions
2023-04-04 16:26:40 -07:00
497 changed files with 63333 additions and 13038 deletions

View File

@@ -1,28 +0,0 @@
# Bun's Dev Container
To get started, login to GitHub and clone bun's GitHub repo into `/build/bun`
# First time setup
```bash
gh auth login # if it fails to open a browser, use Personal Access Token instead
gh repo clone oven-sh/bun . -- --depth=1 --progress -j8
```
# Compile bun dependencies (zig is already compiled)
```bash
make devcontainer
```
# Build bun for development
```bash
make dev
```
# Run bun
```bash
bun-debug help
```

View File

@@ -1,70 +0,0 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.209.6/containers/docker-existing-dockerfile
{
"name": "bun (Ubuntu)",
// Sets the run context to one level up instead of the .devcontainer folder.
"context": "..",
"hostRequirements": { "memory": "16gb" },
// Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
"dockerFile": "../Dockerfile.devcontainer",
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": "/bin/zsh",
"zigLanguageClient.path": "/home/ubuntu/zls/zig-out/bin/zls",
"zig.zigPath": "/build/zig/zig",
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"AugusteRame.zls-vscode",
"ms-vscode.cpptools",
"/home/ubuntu/vscode-zig.vsix",
"vadimcn.vscode-lldb",
"esbenp.prettier-vscode",
"xaver.clang-format"
],
"postCreateCommand": "cd /build/bun; bash /build/getting-started.sh; cat /build/README.md",
"build": {
"target": "bun.devcontainer",
"cacheFrom": ["ghcr.io/oven-sh/bun.devcontainer:latest"],
"args": {
"BUILDARCH": "${localEnv:DOCKER_BUILDARCH:amd64}",
"--platform": "linux/${localEnv:DOCKER_BUILDARCH:amd64}",
"--tag": "ghcr.io/oven-sh/bun.devcontainer:latest"
}
},
"runArgs": [
"--ulimit",
"memlock=-1:-1",
"--ulimit",
"nofile=65536:65536",
"--cap-add=SYS_PTRACE",
"--security-opt",
"seccomp=unconfined"
],
"workspaceMount": "source=bun,target=/build/bun,type=volume",
"workspaceFolder": "/build/bun",
"mounts": [
"source=bun-install,target=/home/ubuntu/.bun,type=volume",
"source=bun-config,target=/home/ubuntu/.config,type=volume"
],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [3000, 8081, 8080]
// Uncomment the next line to run commands after the container is created - for example installing curl.
// "postCreateCommand": "apt-get update && apt-get install -y curl",
// Uncomment when using a ptrace-based debugger like C++, Go, and Rust
// Uncomment to use the Docker CLI from inside the container. See https://aka.ms/vscode-remote/samples/docker-from-docker.
// "mounts": [ "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" ],
// Uncomment to connect as a non-root user if you've added one. See https://aka.ms/vscode-remote/containers/non-root.
// "remoteUser": "vscode"
}

View File

@@ -1,61 +0,0 @@
# /etc/security/limits.conf
#
#Each line describes a limit for a user in the form:
#
#<domain> <type> <item> <value>
#
#Where:
#<domain> can be:
# - a user name
# - a group name, with @group syntax
# - the wildcard *, for default entry
# - the wildcard %, can be also used with %group syntax,
# for maxlogin limit
# - NOTE: group and wildcard limits are not applied to root.
# To apply a limit to the root user, <domain> must be
# the literal username root.
#
#<type> can have the two values:
# - "soft" for enforcing the soft limits
# - "hard" for enforcing hard limits
#
#<item> can be one of the following:
# - core - limits the core file size (KB)
# - data - max data size (KB)
# - fsize - maximum filesize (KB)
# - memlock - max locked-in-memory address space (KB)
# - nofile - max number of open file descriptors
# - rss - max resident set size (KB)
# - stack - max stack size (KB)
# - cpu - max CPU time (MIN)
# - nproc - max number of processes
# - as - address space limit (KB)
# - maxlogins - max number of logins for this user
# - maxsyslogins - max number of logins on the system
# - priority - the priority to run user process with
# - locks - max number of file locks the user can hold
# - sigpending - max number of pending signals
# - msgqueue - max memory used by POSIX message queues (bytes)
# - nice - max nice priority allowed to raise to values: [-20, 19]
# - rtprio - max realtime priority
# - chroot - change root to directory (Debian-specific)
#
#<domain> <type> <item> <value>
#
* soft memlock 33554432
* hard memlock 33554432
* soft nofile 33554432
* hard nofile 33554432
#* soft core 0
#root hard core 100000
#* hard rss 10000
#@student hard nproc 20
#@faculty soft nproc 20
#@faculty hard nproc 50
#ftp hard nproc 0
#ftp - chroot /ftp
#@student - maxlogins 4
# End of file

View File

@@ -1,454 +0,0 @@
#!/usr/bin/env bash
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
#
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/common.md
# Maintainer: The VS Code and Codespaces Teams
#
# Syntax: ./common-debian.sh [install zsh flag] [username] [user UID] [user GID] [upgrade packages flag] [install Oh My Zsh! flag] [Add non-free packages]
set -e
INSTALL_ZSH=${1:-"true"}
USERNAME=${2:-"automatic"}
USER_UID=${3:-"automatic"}
USER_GID=${4:-"automatic"}
UPGRADE_PACKAGES=${5:-"true"}
INSTALL_OH_MYS=${6:-"true"}
ADD_NON_FREE_PACKAGES=${7:-"false"}
SCRIPT_DIR="$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)"
MARKER_FILE="/usr/local/etc/vscode-dev-containers/common"
if [ "$(id -u)" -ne 0 ]; then
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
exit 1
fi
# Ensure that login shells get the correct path if the user updated the PATH using ENV.
rm -f /etc/profile.d/00-restore-env.sh
echo "export PATH=${PATH//$(sh -lc 'echo $PATH')/\$PATH}" > /etc/profile.d/00-restore-env.sh
chmod +x /etc/profile.d/00-restore-env.sh
# If in automatic mode, determine if a user already exists, if not use vscode
if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then
USERNAME=""
POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)")
for CURRENT_USER in ${POSSIBLE_USERS[@]}; do
if id -u ${CURRENT_USER} > /dev/null 2>&1; then
USERNAME=${CURRENT_USER}
break
fi
done
if [ "${USERNAME}" = "" ]; then
USERNAME=vscode
fi
elif [ "${USERNAME}" = "none" ]; then
USERNAME=root
USER_UID=0
USER_GID=0
fi
# Load markers to see which steps have already run
if [ -f "${MARKER_FILE}" ]; then
echo "Marker file found:"
cat "${MARKER_FILE}"
source "${MARKER_FILE}"
fi
# Ensure apt is in non-interactive to avoid prompts
export DEBIAN_FRONTEND=noninteractive
# Function to call apt-get if needed
apt_get_update_if_needed()
{
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
echo "Running apt-get update..."
apt-get update
else
echo "Skipping apt-get update."
fi
}
# Run install apt-utils to avoid debconf warning then verify presence of other common developer tools and dependencies
if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then
package_list="apt-utils \
openssh-client \
gnupg2 \
dirmngr \
iproute2 \
procps \
lsof \
htop \
net-tools \
psmisc \
curl \
wget \
rsync \
ca-certificates \
unzip \
zip \
nano \
vim-tiny \
less \
jq \
lsb-release \
apt-transport-https \
dialog \
libc6 \
libgcc1 \
libkrb5-3 \
libgssapi-krb5-2 \
libicu[0-9][0-9] \
liblttng-ust[0-9] \
libstdc++6 \
zlib1g \
locales \
sudo \
ncdu \
man-db \
strace \
manpages \
manpages-dev \
init-system-helpers"
# Needed for adding manpages-posix and manpages-posix-dev which are non-free packages in Debian
if [ "${ADD_NON_FREE_PACKAGES}" = "true" ]; then
# Bring in variables from /etc/os-release like VERSION_CODENAME
. /etc/os-release
sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list
sed -i -E "s/deb-src http:\/\/(deb|httredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list
sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list
sed -i -E "s/deb-src http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list
sed -i "s/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list
sed -i "s/deb-src http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list
sed -i "s/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list
sed -i "s/deb-src http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list
# Handle bullseye location for security https://www.debian.org/releases/bullseye/amd64/release-notes/ch-information.en.html
sed -i "s/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main contrib non-free/" /etc/apt/sources.list
sed -i "s/deb-src http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main contrib non-free/" /etc/apt/sources.list
echo "Running apt-get update..."
apt-get update
package_list="${package_list} manpages-posix manpages-posix-dev"
else
apt_get_update_if_needed
fi
# Install libssl1.1 if available
if [[ ! -z $(apt-cache --names-only search ^libssl1.1$) ]]; then
package_list="${package_list} libssl1.1"
fi
# Install appropriate version of libssl1.0.x if available
libssl_package=$(dpkg-query -f '${db:Status-Abbrev}\t${binary:Package}\n' -W 'libssl1\.0\.?' 2>&1 || echo '')
if [ "$(echo "$LIlibssl_packageBSSL" | grep -o 'libssl1\.0\.[0-9]:' | uniq | sort | wc -l)" -eq 0 ]; then
if [[ ! -z $(apt-cache --names-only search ^libssl1.0.2$) ]]; then
# Debian 9
package_list="${package_list} libssl1.0.2"
elif [[ ! -z $(apt-cache --names-only search ^libssl1.0.0$) ]]; then
# Ubuntu 18.04, 16.04, earlier
package_list="${package_list} libssl1.0.0"
fi
fi
echo "Packages to verify are installed: ${package_list}"
apt-get -y install --no-install-recommends ${package_list} 2> >( grep -v 'debconf: delaying package configuration, since apt-utils is not installed' >&2 )
# Install git if not already installed (may be more recent than distro version)
if ! type git > /dev/null 2>&1; then
apt-get -y install --no-install-recommends git
fi
PACKAGES_ALREADY_INSTALLED="true"
fi
# Get to latest versions of all packages
if [ "${UPGRADE_PACKAGES}" = "true" ]; then
apt_get_update_if_needed
apt-get -y upgrade --no-install-recommends
apt-get autoremove -y
fi
# Ensure at least the en_US.UTF-8 UTF-8 locale is available.
# Common need for both applications and things like the agnoster ZSH theme.
if [ "${LOCALE_ALREADY_SET}" != "true" ] && ! grep -o -E '^\s*en_US.UTF-8\s+UTF-8' /etc/locale.gen > /dev/null; then
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
locale-gen
LOCALE_ALREADY_SET="true"
fi
# Create or update a non-root user to match UID/GID.
group_name="${USERNAME}"
if id -u ${USERNAME} > /dev/null 2>&1; then
# User exists, update if needed
if [ "${USER_GID}" != "automatic" ] && [ "$USER_GID" != "$(id -g $USERNAME)" ]; then
group_name="$(id -gn $USERNAME)"
groupmod --gid $USER_GID ${group_name}
usermod --gid $USER_GID $USERNAME
fi
if [ "${USER_UID}" != "automatic" ] && [ "$USER_UID" != "$(id -u $USERNAME)" ]; then
usermod --uid $USER_UID $USERNAME
fi
else
# Create user
if [ "${USER_GID}" = "automatic" ]; then
groupadd $USERNAME
else
groupadd --gid $USER_GID $USERNAME
fi
if [ "${USER_UID}" = "automatic" ]; then
useradd -s /bin/bash --gid $USERNAME -m $USERNAME
else
useradd -s /bin/bash --uid $USER_UID --gid $USERNAME -m $USERNAME
fi
fi
# Add sudo support for non-root user
if [ "${USERNAME}" != "root" ] && [ "${EXISTING_NON_ROOT_USER}" != "${USERNAME}" ]; then
echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME
chmod 0440 /etc/sudoers.d/$USERNAME
EXISTING_NON_ROOT_USER="${USERNAME}"
fi
# ** Shell customization section **
if [ "${USERNAME}" = "root" ]; then
user_rc_path="/root"
else
user_rc_path="/home/${USERNAME}"
fi
# Restore user .bashrc defaults from skeleton file if it doesn't exist or is empty
if [ ! -f "${user_rc_path}/.bashrc" ] || [ ! -s "${user_rc_path}/.bashrc" ] ; then
cp /etc/skel/.bashrc "${user_rc_path}/.bashrc"
fi
# Restore user .profile defaults from skeleton file if it doesn't exist or is empty
if [ ! -f "${user_rc_path}/.profile" ] || [ ! -s "${user_rc_path}/.profile" ] ; then
cp /etc/skel/.profile "${user_rc_path}/.profile"
fi
# .bashrc/.zshrc snippet
rc_snippet="$(cat << 'EOF'
if [ -z "${USER}" ]; then export USER=$(whoami); fi
if [[ "${PATH}" != *"$HOME/.local/bin"* ]]; then export PATH="${PATH}:$HOME/.local/bin"; fi
# Display optional first run image specific notice if configured and terminal is interactive
if [ -t 1 ] && [[ "${TERM_PROGRAM}" = "vscode" || "${TERM_PROGRAM}" = "codespaces" ]] && [ ! -f "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed" ]; then
if [ -f "/usr/local/etc/vscode-dev-containers/first-run-notice.txt" ]; then
cat "/usr/local/etc/vscode-dev-containers/first-run-notice.txt"
elif [ -f "/workspaces/.codespaces/shared/first-run-notice.txt" ]; then
cat "/workspaces/.codespaces/shared/first-run-notice.txt"
fi
mkdir -p "$HOME/.config/vscode-dev-containers"
# Mark first run notice as displayed after 10s to avoid problems with fast terminal refreshes hiding it
((sleep 10s; touch "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed") &)
fi
# Set the default git editor if not already set
if [ -z "$(git config --get core.editor)" ] && [ -z "${GIT_EDITOR}" ]; then
if [ "${TERM_PROGRAM}" = "vscode" ]; then
if [[ -n $(command -v code-insiders) && -z $(command -v code) ]]; then
export GIT_EDITOR="code-insiders --wait"
else
export GIT_EDITOR="code --wait"
fi
fi
fi
EOF
)"
# code shim, it fallbacks to code-insiders if code is not available
cat << 'EOF' > /usr/local/bin/code
#!/bin/sh
get_in_path_except_current() {
which -a "$1" | grep -A1 "$0" | grep -v "$0"
}
code="$(get_in_path_except_current code)"
if [ -n "$code" ]; then
exec "$code" "$@"
elif [ "$(command -v code-insiders)" ]; then
exec code-insiders "$@"
else
echo "code or code-insiders is not installed" >&2
exit 127
fi
EOF
chmod +x /usr/local/bin/code
# systemctl shim - tells people to use 'service' if systemd is not running
cat << 'EOF' > /usr/local/bin/systemctl
#!/bin/sh
set -e
if [ -d "/run/systemd/system" ]; then
exec /bin/systemctl "$@"
else
echo '\n"systemd" is not running in this container due to its overhead.\nUse the "service" command to start services instead. e.g.: \n\nservice --status-all'
fi
EOF
chmod +x /usr/local/bin/systemctl
# Codespaces bash and OMZ themes - partly inspired by https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/robbyrussell.zsh-theme
codespaces_bash="$(cat \
<<'EOF'
# Codespaces bash prompt theme
__bash_prompt() {
local userpart='`export XIT=$? \
&& [ ! -z "${GITHUB_USER}" ] && echo -n "\[\033[0;32m\]@${GITHUB_USER} " || echo -n "\[\033[0;32m\]\u " \
&& [ "$XIT" -ne "0" ] && echo -n "\[\033[1;31m\]➜" || echo -n "\[\033[0m\]➜"`'
local gitbranch='`\
if [ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ]; then \
export BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || git rev-parse --short HEAD 2>/dev/null); \
if [ "${BRANCH}" != "" ]; then \
echo -n "\[\033[0;36m\](\[\033[1;31m\]${BRANCH}" \
&& if git ls-files --error-unmatch -m --directory --no-empty-directory -o --exclude-standard ":/*" > /dev/null 2>&1; then \
echo -n " \[\033[1;33m\]✗"; \
fi \
&& echo -n "\[\033[0;36m\]) "; \
fi; \
fi`'
local lightblue='\[\033[1;34m\]'
local removecolor='\[\033[0m\]'
PS1="${userpart} ${lightblue}\w ${gitbranch}${removecolor}\$ "
unset -f __bash_prompt
}
__bash_prompt
EOF
)"
codespaces_zsh="$(cat \
<<'EOF'
# Codespaces zsh prompt theme
__zsh_prompt() {
local prompt_username
if [ ! -z "${GITHUB_USER}" ]; then
prompt_username="@${GITHUB_USER}"
else
prompt_username="%n"
fi
PROMPT="%{$fg[green]%}${prompt_username} %(?:%{$reset_color%}➜ :%{$fg_bold[red]%}➜ )" # User/exit code arrow
PROMPT+='%{$fg_bold[blue]%}%(5~|%-1~/…/%3~|%4~)%{$reset_color%} ' # cwd
PROMPT+='$([ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ] && git_prompt_info)' # Git status
PROMPT+='%{$fg[white]%}$ %{$reset_color%}'
unset -f __zsh_prompt
}
ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg_bold[cyan]%}(%{$fg_bold[red]%}"
ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%} "
ZSH_THEME_GIT_PROMPT_DIRTY=" %{$fg_bold[yellow]%}✗%{$fg_bold[cyan]%})"
ZSH_THEME_GIT_PROMPT_CLEAN="%{$fg_bold[cyan]%})"
__zsh_prompt
EOF
)"
# Add RC snippet and custom bash prompt
if [ "${RC_SNIPPET_ALREADY_ADDED}" != "true" ]; then
echo "${rc_snippet}" >> /etc/bash.bashrc
echo "${codespaces_bash}" >> "${user_rc_path}/.bashrc"
echo 'export PROMPT_DIRTRIM=4' >> "${user_rc_path}/.bashrc"
if [ "${USERNAME}" != "root" ]; then
echo "${codespaces_bash}" >> "/root/.bashrc"
echo 'export PROMPT_DIRTRIM=4' >> "/root/.bashrc"
fi
chown ${USERNAME}:${group_name} "${user_rc_path}/.bashrc"
RC_SNIPPET_ALREADY_ADDED="true"
fi
# Optionally install and configure zsh and Oh My Zsh!
if [ "${INSTALL_ZSH}" = "true" ]; then
if ! type zsh > /dev/null 2>&1; then
apt_get_update_if_needed
apt-get install -y zsh
fi
if [ "${ZSH_ALREADY_INSTALLED}" != "true" ]; then
echo "${rc_snippet}" >> /etc/zsh/zshrc
ZSH_ALREADY_INSTALLED="true"
fi
# Adapted, simplified inline Oh My Zsh! install steps that adds, defaults to a codespaces theme.
# See https://github.com/ohmyzsh/ohmyzsh/blob/master/tools/install.sh for official script.
oh_my_install_dir="${user_rc_path}/.oh-my-zsh"
if [ ! -d "${oh_my_install_dir}" ] && [ "${INSTALL_OH_MYS}" = "true" ]; then
template_path="${oh_my_install_dir}/templates/zshrc.zsh-template"
user_rc_file="${user_rc_path}/.zshrc"
umask g-w,o-w
mkdir -p ${oh_my_install_dir}
git clone --depth=1 \
-c core.eol=lf \
-c core.autocrlf=false \
-c fsck.zeroPaddedFilemode=ignore \
-c fetch.fsck.zeroPaddedFilemode=ignore \
-c receive.fsck.zeroPaddedFilemode=ignore \
"https://github.com/ohmyzsh/ohmyzsh" "${oh_my_install_dir}" 2>&1
echo -e "$(cat "${template_path}")\nDISABLE_AUTO_UPDATE=true\nDISABLE_UPDATE_PROMPT=true" > ${user_rc_file}
sed -i -e 's/ZSH_THEME=.*/ZSH_THEME="codespaces"/g' ${user_rc_file}
mkdir -p ${oh_my_install_dir}/custom/themes
echo "${codespaces_zsh}" > "${oh_my_install_dir}/custom/themes/codespaces.zsh-theme"
# Shrink git while still enabling updates
cd "${oh_my_install_dir}"
git repack -a -d -f --depth=1 --window=1
# Copy to non-root user if one is specified
if [ "${USERNAME}" != "root" ]; then
cp -rf "${user_rc_file}" "${oh_my_install_dir}" /root
chown -R ${USERNAME}:${group_name} "${user_rc_path}"
fi
fi
fi
# Persist image metadata info, script if meta.env found in same directory
meta_info_script="$(cat << 'EOF'
#!/bin/sh
. /usr/local/etc/vscode-dev-containers/meta.env
# Minimal output
if [ "$1" = "version" ] || [ "$1" = "image-version" ]; then
echo "${VERSION}"
exit 0
elif [ "$1" = "release" ]; then
echo "${GIT_REPOSITORY_RELEASE}"
exit 0
elif [ "$1" = "content" ] || [ "$1" = "content-url" ] || [ "$1" = "contents" ] || [ "$1" = "contents-url" ]; then
echo "${CONTENTS_URL}"
exit 0
fi
#Full output
echo
echo "Development container image information"
echo
if [ ! -z "${VERSION}" ]; then echo "- Image version: ${VERSION}"; fi
if [ ! -z "${DEFINITION_ID}" ]; then echo "- Definition ID: ${DEFINITION_ID}"; fi
if [ ! -z "${VARIANT}" ]; then echo "- Variant: ${VARIANT}"; fi
if [ ! -z "${GIT_REPOSITORY}" ]; then echo "- Source code repository: ${GIT_REPOSITORY}"; fi
if [ ! -z "${GIT_REPOSITORY_RELEASE}" ]; then echo "- Source code release/branch: ${GIT_REPOSITORY_RELEASE}"; fi
if [ ! -z "${BUILD_TIMESTAMP}" ]; then echo "- Timestamp: ${BUILD_TIMESTAMP}"; fi
if [ ! -z "${CONTENTS_URL}" ]; then echo && echo "More info: ${CONTENTS_URL}"; fi
echo
EOF
)"
if [ -f "${SCRIPT_DIR}/meta.env" ]; then
mkdir -p /usr/local/etc/vscode-dev-containers/
cp -f "${SCRIPT_DIR}/meta.env" /usr/local/etc/vscode-dev-containers/meta.env
echo "${meta_info_script}" > /usr/local/bin/devcontainer-info
chmod +x /usr/local/bin/devcontainer-info
fi
# Write marker file
mkdir -p "$(dirname "${MARKER_FILE}")"
echo -e "\
PACKAGES_ALREADY_INSTALLED=${PACKAGES_ALREADY_INSTALLED}\n\
LOCALE_ALREADY_SET=${LOCALE_ALREADY_SET}\n\
EXISTING_NON_ROOT_USER=${EXISTING_NON_ROOT_USER}\n\
RC_SNIPPET_ALREADY_ADDED=${RC_SNIPPET_ALREADY_ADDED}\n\
ZSH_ALREADY_INSTALLED=${ZSH_ALREADY_INSTALLED}" > "${MARKER_FILE}"
echo "Done!"

View File

@@ -1,16 +0,0 @@
#!/bin/bash
echo "To get started, login to GitHub and clone bun's GitHub repo into /build/bun"
echo "If it fails to open a browser, login with a Personal Access Token instead"
echo "# First time setup"
echo "gh auth login"
echo "gh repo clone oven-sh/bun . -- --depth=1 --progress -j8"
echo ""
echo "# Compile bun dependencies (zig is already compiled)"
echo "make devcontainer"
echo ""
echo "# Build bun for development"
echo "make dev"
echo ""
echo "# Run bun"
echo "bun-debug"

View File

@@ -1,207 +0,0 @@
#!/usr/bin/env bash
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
#
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/github.md
# Maintainer: The VS Code and Codespaces Teams
#
# Syntax: ./github-debian.sh [version]
CLI_VERSION=${1:-"latest"}
GITHUB_CLI_ARCHIVE_GPG_KEY=C99B11DEB97541F0
GPG_KEY_SERVERS="keyserver hkp://keyserver.ubuntu.com:80
keyserver hkps://keys.openpgp.org
keyserver hkp://keyserver.pgp.com"
set -e
if [ "$(id -u)" -ne 0 ]; then
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
exit 1
fi
# Get central common setting
get_common_setting() {
if [ "${common_settings_file_loaded}" != "true" ]; then
curl -sfL "https://aka.ms/vscode-dev-containers/script-library/settings.env" -o /tmp/vsdc-settings.env 2>/dev/null || echo "Could not download settings file. Skipping."
common_settings_file_loaded=true
fi
if [ -f "/tmp/vsdc-settings.env" ]; then
local multi_line=""
if [ "$2" = "true" ]; then multi_line="-z"; fi
local result="$(grep ${multi_line} -oP "$1=\"?\K[^\"]+" /tmp/vsdc-settings.env | tr -d '\0')"
if [ ! -z "${result}" ]; then declare -g $1="${result}"; fi
fi
echo "$1=${!1}"
}
# Import the specified key in a variable name passed in as
receive_gpg_keys() {
get_common_setting $1
local keys=${!1}
get_common_setting GPG_KEY_SERVERS true
# Use a temporary locaiton for gpg keys to avoid polluting image
export GNUPGHOME="/tmp/tmp-gnupg"
mkdir -p ${GNUPGHOME}
chmod 700 ${GNUPGHOME}
echo -e "disable-ipv6\n${GPG_KEY_SERVERS}" >${GNUPGHOME}/dirmngr.conf
# GPG key download sometimes fails for some reason and retrying fixes it.
local retry_count=0
local gpg_ok="false"
set +e
until [ "${gpg_ok}" = "true" ] || [ "${retry_count}" -eq "5" ]; do
echo "(*) Downloading GPG key..."
(echo "${keys}" | xargs -n 1 gpg --recv-keys) 2>&1 && gpg_ok="true"
if [ "${gpg_ok}" != "true" ]; then
echo "(*) Failed getting key, retring in 10s..."
((retry_count++))
sleep 10s
fi
done
set -e
if [ "${gpg_ok}" = "false" ]; then
echo "(!) Failed to get gpg key."
exit 1
fi
}
# Figure out correct version of a three part version number is not passed
find_version_from_git_tags() {
local variable_name=$1
local requested_version=${!variable_name}
if [ "${requested_version}" = "none" ]; then return; fi
local repository=$2
local prefix=${3:-"tags/v"}
local separator=${4:-"."}
local last_part_optional=${5:-"false"}
if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then
local escaped_separator=${separator//./\\.}
local last_part
if [ "${last_part_optional}" = "true" ]; then
last_part="(${escaped_separator}[0-9]+)?"
else
last_part="${escaped_separator}[0-9]+"
fi
local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${last_part}$"
local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)"
if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then
declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)"
else
set +e
declare -g ${variable_name}="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")"
set -e
fi
fi
if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" >/dev/null 2>&1; then
echo -e "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2
exit 1
fi
echo "${variable_name}=${!variable_name}"
}
# Import the specified key in a variable name passed in as
receive_gpg_keys() {
get_common_setting $1
local keys=${!1}
get_common_setting GPG_KEY_SERVERS true
local keyring_args=""
if [ ! -z "$2" ]; then
keyring_args="--no-default-keyring --keyring $2"
fi
# Use a temporary locaiton for gpg keys to avoid polluting image
export GNUPGHOME="/tmp/tmp-gnupg"
mkdir -p ${GNUPGHOME}
chmod 700 ${GNUPGHOME}
echo -e "disable-ipv6\n${GPG_KEY_SERVERS}" >${GNUPGHOME}/dirmngr.conf
# GPG key download sometimes fails for some reason and retrying fixes it.
local retry_count=0
local gpg_ok="false"
set +e
until [ "${gpg_ok}" = "true" ] || [ "${retry_count}" -eq "5" ]; do
echo "(*) Downloading GPG key..."
(echo "${keys}" | xargs -n 1 gpg -q ${keyring_args} --recv-keys) 2>&1 && gpg_ok="true"
if [ "${gpg_ok}" != "true" ]; then
echo "(*) Failed getting key, retring in 10s..."
((retry_count++))
sleep 10s
fi
done
set -e
if [ "${gpg_ok}" = "false" ]; then
echo "(!) Failed to get gpg key."
exit 1
fi
}
# Function to run apt-get if needed
apt_get_update_if_needed() {
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
echo "Running apt-get update..."
apt-get update
else
echo "Skipping apt-get update."
fi
}
# Checks if packages are installed and installs them if not
check_packages() {
if ! dpkg -s "$@" >/dev/null 2>&1; then
apt_get_update_if_needed
apt-get -y install --no-install-recommends "$@"
fi
}
# Fall back on direct download if no apt package exists
# Fetches .deb file to be installed with dpkg
install_deb_using_github() {
check_packages wget
arch=$(dpkg --print-architecture)
find_version_from_git_tags CLI_VERSION https://github.com/cli/cli
cli_filename="gh_${CLI_VERSION}_linux_${arch}.deb"
mkdir -p /tmp/ghcli
pushd /tmp/ghcli
wget https://github.com/cli/cli/releases/download/v${CLI_VERSION}/${cli_filename}
dpkg -i /tmp/ghcli/${cli_filename}
popd
rm -rf /tmp/ghcli
}
export DEBIAN_FRONTEND=noninteractive
# Install curl, apt-transport-https, curl, gpg, or dirmngr, git if missing
check_packages curl ca-certificates apt-transport-https dirmngr gnupg2
if ! type git >/dev/null 2>&1; then
apt_get_update_if_needed
apt-get -y install --no-install-recommends git
fi
# Soft version matching
if [ "${CLI_VERSION}" != "latest" ] && [ "${CLI_VERSION}" != "lts" ] && [ "${CLI_VERSION}" != "stable" ]; then
find_version_from_git_tags CLI_VERSION "https://github.com/cli/cli"
version_suffix="=${CLI_VERSION}"
else
version_suffix=""
fi
# Install the GitHub CLI
echo "Downloading github CLI..."
install_deb_using_github
# Method below does not work until cli/cli#6175 is fixed
# # Import key safely (new method rather than deprecated apt-key approach) and install
# . /etc/os-release
# receive_gpg_keys GITHUB_CLI_ARCHIVE_GPG_KEY /usr/share/keyrings/githubcli-archive-keyring.gpg
# echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" >/etc/apt/sources.list.d/github-cli.list
# apt-get update
# apt-get -y install "gh${version_suffix}"
# rm -rf "/tmp/gh/gnupg"
echo "Done!"

View File

@@ -1,7 +0,0 @@
#!/bin/bash
chsh -s $(which zsh)
sh -c "$(curl -fsSL https://starship.rs/install.sh) -- --platform linux_musl" -- --yes
echo "eval \"$(starship init zsh)\"" >>~/.zshrc
curl https://github.com/Jarred-Sumner/vscode-zig/releases/download/march18/zig-0.2.5.vsix >/home/ubuntu/vscode-zig.vsix

View File

@@ -1,7 +0,0 @@
#!/bin/bash
git clone https://github.com/zigtools/zls /home/ubuntu/zls
cd /home/ubuntu/zls
git checkout 30869d7d8741656448e46fbf14f14da9ca7e5a21
git submodule update --init --recursive --progress --depth=1
zig build -Doptimize=ReleaseFast

View File

@@ -1,9 +0,0 @@
{
"folders": [
{
// Source code
"name": "bun",
"path": "bun"
},
]
}

View File

@@ -1,9 +0,0 @@
{
"zig_exe_path": "/build/zig/zig",
"enable_snippets": true,
"warn_style": false,
"enable_semantic_tokens": true,
"operator_completions": true,
"include_at_in_builtins": false,
"max_detail_length": 1048576
}

1
.github/scripts/get-revision.js vendored Normal file
View File

@@ -0,0 +1 @@
console.log(Bun.revision);

3
.github/scripts/package.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"type": "module"
}

684
.github/scripts/test-runner.ts vendored Normal file
View File

@@ -0,0 +1,684 @@
// Dear reader
//
// The existence of this file is temporary, a hack.
import { join, basename } from "node:path";
import { readdirSync, writeSync, fsyncSync, appendFileSync } from "node:fs";
import { spawn, spawnSync } from "node:child_process";
export { parseTest, runTest, formatTest };
export type ParseTestOptions = {
cwd?: string;
paths?: string[];
};
export type ParseTestResult = {
info: TestInfo;
files: TestFile[];
summary: TestSummary;
};
export type RunTestOptions = ParseTestOptions & {
args?: string[];
timeout?: number;
isolate?: boolean;
};
export type RunTestResult = ParseTestResult & {
exitCode: number | null;
stdout: string;
stderr: string;
};
export type TestInfo = {
name: string;
version: string;
revision: string;
os: string;
arch: string;
};
export type TestFile = {
file: string;
status: TestStatus;
tests: Test[];
summary: TestSummary;
errors?: TestError[];
};
export type TestError = {
name: string;
message: string;
stack?: TestErrorStack[];
};
export type TestErrorStack = {
file: string;
function?: string;
line: number;
column?: number;
};
export type TestStatus = "pass" | "fail" | "skip";
export type Test = {
name: string;
status: TestStatus;
errors?: TestError[];
};
export type TestSummary = {
pass: number;
fail: number;
skip: number;
tests: number;
files: number;
duration: number;
};
function parseTest(lines: string[], options?: ParseTestOptions): ParseTestResult {
let i = 0;
const isDone = () => {
return i >= lines.length;
};
const readLine = () => {
return lines[i++];
};
function readUntil<V>(cb: (line: string) => V | undefined): V | undefined {
while (!isDone()) {
const line = readLine();
const result = cb(line);
if (result) {
return result;
}
}
}
const { cwd, paths = cwd ? Array.from(listFiles(cwd, "")) : [] } = options ?? {};
const info = readUntil(parseInfo);
if (!info) {
throw new Error("No tests found");
}
const files: TestFile[] = [];
let file: TestFile | undefined;
let test: Test | undefined;
let error: TestError | undefined;
let errorStart: number | undefined;
let summary: TestSummary | undefined;
const reset = () => {
if (error) {
if (file) {
if (test) {
if (!test?.errors) {
test.errors = [error];
} else {
test.errors.push(error);
}
} else {
if (!file.errors) {
file.errors = [error];
} else {
file.errors.push(error);
}
}
}
error = undefined;
errorStart = undefined;
}
};
while (!isDone()) {
const line = readLine();
if (error) {
const newStack = parseStack(line, cwd);
if (newStack) {
if (errorStart !== undefined) {
for (let j = errorStart; j < i - 1; j++) {
error.message += `\n${lines[j]}`;
}
errorStart = undefined;
}
if (!error.stack) {
error.stack = [newStack];
} else {
error.stack.push(newStack);
}
continue;
}
}
const newFile = parseFile(line, paths);
if (newFile) {
reset();
file = newFile;
files.push(file);
continue;
}
const newTest = parseStatus(line);
if (newTest) {
if (newTest.status === "skip" && error) {
continue;
}
test = newTest;
if (file) {
file.tests.push(test);
file.summary[test.status]++;
file.summary.tests++;
if (test.status === "fail") {
file.status = "fail";
}
}
file?.tests.push(test);
reset();
continue;
}
const newError = parseError(line);
if (newError) {
reset();
error = newError;
errorStart = i;
continue;
}
const newSkip = parseSkip(line);
if (newSkip) {
reset();
i += parseSkip(line);
continue;
}
const newSummary = parseSummary(line);
if (newSummary) {
summary = newSummary;
break;
}
}
summary = {
tests: files.reduce((n, file) => n + file.tests.length, 0),
files: files.length,
duration: 0,
...summary,
pass: files.reduce((n, file) => n + file.tests.filter(test => test.status === "pass").length, 0),
fail: files.reduce((n, file) => n + file.tests.filter(test => test.status === "fail").length, 0),
skip: files.reduce((n, file) => n + file.tests.filter(test => test.status === "skip").length, 0),
};
if (files.length === 1) {
files[0].summary = summary;
}
return {
info,
files,
summary,
};
}
function getRevision(): string {
if ("Bun" in globalThis) {
return Bun.revision;
}
const { stdout } = spawnSync("bun", ["get-revision.js"], {
cwd: new URL(".", import.meta.url),
stdio: "pipe",
encoding: "utf-8",
});
return stdout.trim();
}
function parseInfo(line: string): TestInfo | undefined {
const match = /^(bun (?:wip)?test) v([0-9\.]+) \(([0-9a-z]+)\)$/.exec(line);
if (!match) {
return undefined;
}
const [, name, version, sha] = match;
return {
name,
version,
revision: getRevision(),
os: process.platform,
arch: process.arch,
};
}
function parseFile(line: string, paths?: string[]): TestFile | undefined {
const match = /^([a-z0-9_-]+\.(?:test|spec)\.(?:c|m)?(?:j|t)sx?)\:$/.exec(line);
if (!match) {
return undefined;
}
let [, file] = match;
for (const path of paths ?? []) {
if (path.endsWith(file)) {
file = path;
break;
}
}
return {
file,
tests: [],
status: "pass",
summary: {
files: 1,
tests: 0,
pass: 0,
fail: 0,
skip: 0,
duration: 0,
},
};
}
function parseStatus(line: string): Test | undefined {
const match = /^(✓|✗|-) (.*)$/.exec(line);
if (!match) {
return undefined;
}
const [, icon, name] = match;
return {
name,
status: icon === "✓" ? "pass" : icon === "✗" ? "fail" : "skip",
};
}
function parseError(line: string): TestError | undefined {
const match = /^(.*error)\: (.*)$/i.exec(line);
if (!match) {
return undefined;
}
const [, name, message] = match;
return {
name: name === "error" ? "Error" : name,
message,
};
}
function parseStack(line: string, cwd?: string): TestErrorStack | undefined {
let match = /^\s*at (.*) \((.*)\:([0-9]+)\:([0-9]+)\)$/.exec(line);
if (!match) {
match = /^\s*at (.*)\:([0-9]+)\:([0-9]+)$/.exec(line);
if (!match) {
return undefined;
}
}
const [columnNo, lineNo, path, func] = match.reverse();
let file = path;
if (cwd && path.startsWith(cwd)) {
file = path.slice(cwd.length);
if (file.startsWith("/")) {
file = file.slice(1);
}
}
return {
file,
function: func !== line ? func : undefined,
line: parseInt(lineNo),
column: parseInt(columnNo),
};
}
function parseSkip(line: string): number {
const match = /^([0-9]+) tests (?:skipped|failed)\:$/.exec(line);
if (match) {
return parseInt(match[1]);
}
return 0;
}
function parseSummary(line: string): TestSummary | undefined {
const match = /^Ran ([0-9]+) tests across ([0-9]+) files \[([0-9]+\.[0-9]+)(m?s)\]$/.exec(line);
if (!match) {
return undefined;
}
const [, tests, files, duration, unit] = match;
return {
pass: 0,
fail: 0,
skip: 0,
tests: parseInt(tests),
files: parseInt(files),
duration: parseFloat(duration) * (unit === "s" ? 1000 : 1),
};
}
function* listFiles(cwd: string, dir: string): Generator<string> {
const dirents = readdirSync(join(cwd, dir), { withFileTypes: true });
for (const dirent of dirents) {
const { name } = dirent;
if (name === "node_modules" || name.startsWith(".")) {
continue;
}
const path = join(dir, name);
if (dirent.isDirectory()) {
yield* listFiles(cwd, path);
} else if (dirent.isFile()) {
yield path;
}
}
}
function stripAnsi(string: string): string {
return string.replace(/\x1b\[[0-9;]*m/g, "");
}
function print(buffer: string | Uint8Array) {
if (typeof buffer === "string") {
buffer = new TextEncoder().encode(buffer);
}
let offset = 0;
let length = buffer.byteLength;
while (offset < length) {
try {
const n = writeSync(1, buffer);
offset += n;
if (offset < length) {
try {
fsyncSync(1);
} catch {}
buffer = buffer.slice(n);
}
} catch (error) {
// @ts-ignore
if (error.code === "EAGAIN") {
continue;
}
throw error;
}
}
}
// FIXME: there is a bug that causes annotations to be duplicated
const seen = new Set<string>();
function annotate(type: string, arg?: string, args?: Record<string, unknown>): void {
let line = `::${type}`;
if (args) {
line += " ";
line += Object.entries(args)
.map(([key, value]) => `${key}=${value}`)
.join(",");
}
line += "::";
if (arg) {
line += arg;
}
line = line.replace(/\n/g, "%0A");
if (seen.has(line)) {
return;
}
seen.add(line);
print(`\n${line}\n`);
}
async function* runTest(options: RunTestOptions): AsyncGenerator<RunTestResult, ParseTestResult> {
const {
cwd = process.cwd(),
args = [],
timeout = 60_000, // 1 min
isolate = false,
} = options;
const paths: string[] = Array.from(listFiles(cwd, ""));
const files: string[] = [];
for (const path of paths) {
if (!path.includes(".test.")) {
continue;
}
if (!args.length) {
files.push(path);
continue;
}
for (const arg of args) {
if (
(arg.endsWith("/") && path.startsWith(arg)) ||
(arg.includes(".") && path.endsWith(arg)) ||
(!arg.endsWith("/") && !arg.includes(".") && path.includes(arg))
) {
files.push(path);
break;
}
}
}
const runSingleTest = async (args: string[]) => {
const runner = spawn("bun", ["test", ...args], {
cwd,
env: {
...process.env,
"FORCE_COLOR": "1",
},
stdio: "pipe",
timeout,
});
let stderr = "";
let stdout = "";
const exitCode = await new Promise<number | null>(resolve => {
runner.stdout.on("data", (data: Buffer) => {
stdout += data.toString("utf-8");
});
runner.stderr.on("data", (data: Buffer) => {
stderr += data.toString("utf-8");
});
runner.on("error", ({ name, message }) => {
stderr += `${name}: ${message}`;
resolve(null);
});
runner.on("exit", exitCode => {
resolve(exitCode);
});
});
const lines = stderr.split("\n").map(stripAnsi);
const result = parseTest(lines, { cwd, paths });
return {
exitCode,
stdout,
stderr,
...result,
};
};
if (!isolate) {
const result = await runSingleTest(args);
yield result;
return result;
}
const tests = files.map(file => runSingleTest([file]));
const results: RunTestResult[] = [];
for (const test of tests) {
const result = await test;
results.push(result);
yield result;
}
if (!results.length) {
throw new Error("No tests found");
}
return {
info: results.map(result => result.info).pop()!,
files: results.flatMap(result => result.files),
summary: results
.map(result => result.summary)
.reduce((summary, result) => {
summary.pass += result.pass;
summary.fail += result.fail;
summary.skip += result.skip;
summary.tests += result.tests;
summary.files += result.files;
summary.duration += result.duration;
return summary;
}),
};
}
export type FormatTestOptions = {
debug?: boolean;
baseUrl?: string;
};
function formatTest(result: ParseTestResult, options?: FormatTestOptions): string {
const { debug, baseUrl } = options ?? {};
const count = (n: number, label?: string) => {
return n ? (label ? `${n} ${label}` : `${n}`) : "";
};
const code = (content: string, lang?: string) => {
return `\`\`\`${lang ?? ""}\n${content}\n\`\`\`\n`;
};
const link = (title: string, href?: string) => {
if (href && baseUrl) {
href = `${new URL(href, baseUrl)}`;
}
return href ? `[${title}](${href})` : title;
};
const table = (headers: string[], rows: unknown[][]) => {
return [headers, headers.map(() => "-"), ...rows].map(row => `| ${row.join(" | ")} |`).join("\n");
};
const header = (level: number, content: string) => {
return `${"#".repeat(level)} ${content}\n`;
};
const icon = {
pass: "✅",
fail: "❌",
skip: "⏭️",
};
const files = table(
["File", "Status", "Pass", "Fail", "Skip", "Tests", "Duration"],
result.files
.filter(({ status }) => debug || status !== "pass")
.sort((a, b) => {
if (a.status === b.status) {
return a.file.localeCompare(b.file);
}
return a.status.localeCompare(b.status);
})
.map(({ file, status, summary }) => [
link(basename(file), file),
icon[status],
count(summary.pass),
count(summary.fail),
count(summary.skip),
count(summary.tests),
count(summary.duration, "ms"),
]),
);
const errors = result.files
.filter(({ status }) => status === "fail")
.sort((a, b) => a.file.localeCompare(b.file))
.flatMap(({ file, tests }) => {
return [
header(2, link(basename(file), file)),
...tests
.filter(({ status }) => status === "fail")
.map(({ name, errors }) => {
let content = header(3, name);
if (errors) {
content += errors
.map(({ name, message, stack }) => {
let preview = code(`${name}: ${message}`, "diff");
if (stack?.length && baseUrl) {
const { file, line } = stack[0];
if (!is3rdParty(file)) {
const { href } = new URL(`${file}?plain=1#L${Math.max(1, line - 5)}-L${line}`, baseUrl);
preview += `\n${href}\n`;
}
}
return preview;
})
.join("\n");
} else {
content += code("See logs for details");
}
return content;
}),
];
})
.join("\n");
return `${header(1, "Files")}
${files}
${header(1, "Errors")}
${errors}`;
}
function is3rdParty(file?: string): boolean {
return !file || file.startsWith("/") || file.includes(":") || file.includes("..") || file.includes("node_modules/");
}
function printTest(result: RunTestResult): void {
const isAction = process.env["GITHUB_ACTIONS"] === "true";
const isSingle = result.files.length === 1;
if (isSingle) {
const { file, status } = result.files[0];
if (isAction) {
annotate("group", `${status.toUpperCase()} - ${file}`);
} else {
print(`\n${file}:\n`);
}
}
print(result.stderr);
print(result.stdout);
if (!isAction) {
return;
}
result.files
.filter(({ status }) => status === "fail")
.flatMap(({ tests }) => tests)
.filter(({ status }) => status === "fail")
.flatMap(({ name: title, errors }) =>
errors?.forEach(({ name, message, stack }) => {
const { file, line } = stack?.[0] ?? {};
if (is3rdParty(file)) {
return;
}
annotate("error", `${name}: ${message}`, {
file,
line,
title,
});
}),
);
if (isSingle) {
annotate("endgroup");
}
}
async function main() {
let args = [...process.argv.slice(2)];
let timeout;
let isolate;
let quiet;
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg.startsWith("--timeout=")) {
timeout = parseInt(arg.split("=").pop()!);
} else if (arg.startsWith("--isolate")) {
isolate = true;
} else if (arg.startsWith("--quiet")) {
quiet = true;
}
}
args = args.filter(arg => !arg.startsWith("--"));
const results = runTest({
args,
timeout,
isolate,
});
let result: ParseTestResult;
while (true) {
const { value, done } = await results.next();
if (done) {
result = value;
break;
} else if (!quiet) {
printTest(value);
}
}
const summaryPath = process.env["GITHUB_STEP_SUMMARY"];
if (!summaryPath) {
return;
}
const sha = process.env["GITHUB_SHA"] ?? result.info.revision;
const repo = process.env["GITHUB_REPOSITORY"] ?? "oven-sh/bun";
const serverUrl = process.env["GITHUB_SERVER_URL"] ?? "https://github.com";
const summary = formatTest(result, {
debug: process.env["ACTIONS_STEP_DEBUG"] === "true",
baseUrl: `${serverUrl}/${repo}/blob/${sha}/`,
});
appendFileSync(summaryPath, summary, "utf-8");
process.exit(0);
}
function isMain() {
return import.meta.main || import.meta.url === `file://${process.argv[1]}`;
}
if (isMain()) {
await main();
}

View File

@@ -30,7 +30,7 @@ jobs:
arch: aarch64
build_arch: arm64
runner: linux-arm64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-linux-arm64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-linux-arm64-lto.tar.gz"
webkit_basename: "bun-webkit-linux-arm64-lto"
build_machine_arch: aarch64

View File

@@ -40,7 +40,7 @@ jobs:
arch: x86_64
build_arch: amd64
runner: big-ubuntu
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-linux-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-linux-amd64-lto.tar.gz"
webkit_basename: "bun-webkit-linux-amd64-lto"
build_machine_arch: x86_64
- cpu: nehalem
@@ -48,7 +48,7 @@ jobs:
arch: x86_64
build_arch: amd64
runner: big-ubuntu
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-linux-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-linux-amd64-lto.tar.gz"
webkit_basename: "bun-webkit-linux-amd64-lto"
build_machine_arch: x86_64
@@ -152,7 +152,7 @@ jobs:
runs-on: ubuntu-latest
needs: [linux]
if: github.event_name == 'pull_request'
timeout-minutes: 10
timeout-minutes: 20
outputs:
failing_tests: ${{ steps.test.outputs.failing_tests }}
failing_tests_count: ${{ steps.test.outputs.failing_tests_count }}

View File

@@ -110,7 +110,7 @@ jobs:
# obj: bun-obj-darwin-x64-baseline
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: true
# compile_obj: false
# - cpu: haswell
@@ -119,7 +119,7 @@ jobs:
# obj: bun-obj-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: true
# compile_obj: false
# - cpu: nehalem
@@ -128,7 +128,7 @@ jobs:
# obj: bun-obj-darwin-x64-baseline
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: false
# compile_obj: true
# - cpu: haswell
@@ -137,7 +137,7 @@ jobs:
# obj: bun-obj-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: false
# compile_obj: true
- cpu: native
@@ -145,7 +145,7 @@ jobs:
tag: bun-darwin-aarch64
obj: bun-obj-darwin-aarch64
artifact: bun-obj-darwin-aarch64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-arm64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-arm64-lto.tar.gz"
runner: macos-arm64
dependencies: true
compile_obj: true
@@ -249,7 +249,7 @@ jobs:
# package: bun-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
# - cpu: haswell
# arch: x86_64
# tag: bun-darwin-x64
@@ -257,14 +257,14 @@ jobs:
# package: bun-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
- cpu: native
arch: aarch64
tag: bun-darwin-aarch64
obj: bun-obj-darwin-aarch64
package: bun-darwin-aarch64
artifact: bun-obj-darwin-aarch64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-arm64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-arm64-lto.tar.gz"
runner: macos-arm64
steps:
- uses: actions/checkout@v3

View File

@@ -110,7 +110,7 @@ jobs:
obj: bun-obj-darwin-x64-baseline
runner: macos-11
artifact: bun-obj-darwin-x64-baseline
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
dependencies: true
compile_obj: false
# - cpu: haswell
@@ -119,7 +119,7 @@ jobs:
# obj: bun-obj-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: true
# compile_obj: false
- cpu: nehalem
@@ -128,7 +128,7 @@ jobs:
obj: bun-obj-darwin-x64-baseline
runner: macos-11
artifact: bun-obj-darwin-x64-baseline
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
dependencies: false
compile_obj: true
# - cpu: haswell
@@ -137,7 +137,7 @@ jobs:
# obj: bun-obj-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: false
# compile_obj: true
# - cpu: native
@@ -145,7 +145,7 @@ jobs:
# tag: bun-darwin-aarch64
# obj: bun-obj-darwin-aarch64
# artifact: bun-obj-darwin-aarch64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
# runner: macos-arm64
# dependencies: true
# compile_obj: true
@@ -250,7 +250,7 @@ jobs:
package: bun-darwin-x64
runner: macos-11
artifact: bun-obj-darwin-x64-baseline
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
# - cpu: haswell
# arch: x86_64
# tag: bun-darwin-x64
@@ -258,14 +258,14 @@ jobs:
# package: bun-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
# - cpu: native
# arch: aarch64
# tag: bun-darwin-aarch64
# obj: bun-obj-darwin-aarch64
# package: bun-darwin-aarch64
# artifact: bun-obj-darwin-aarch64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
# runner: macos-arm64
steps:
- uses: actions/checkout@v3
@@ -393,7 +393,7 @@ jobs:
runs-on: ${{ matrix.runner }}
needs: [macOS]
if: github.event_name == 'pull_request'
timeout-minutes: 10
timeout-minutes: 30
outputs:
failing_tests: ${{ steps.test.outputs.failing_tests }}
failing_tests_count: ${{ steps.test.outputs.failing_tests_count }}

View File

@@ -110,7 +110,7 @@ jobs:
# obj: bun-obj-darwin-x64-baseline
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: true
# compile_obj: false
- cpu: haswell
@@ -119,7 +119,7 @@ jobs:
obj: bun-obj-darwin-x64
runner: macos-11
artifact: bun-obj-darwin-x64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
dependencies: true
compile_obj: false
# - cpu: nehalem
@@ -128,7 +128,7 @@ jobs:
# obj: bun-obj-darwin-x64-baseline
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: false
# compile_obj: true
- cpu: haswell
@@ -137,7 +137,7 @@ jobs:
obj: bun-obj-darwin-x64
runner: macos-11
artifact: bun-obj-darwin-x64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
dependencies: false
compile_obj: true
# - cpu: native
@@ -145,7 +145,7 @@ jobs:
# tag: bun-darwin-aarch64
# obj: bun-obj-darwin-aarch64
# artifact: bun-obj-darwin-aarch64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-arm64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-arm64-lto.tar.gz"
# runner: macos-arm64
# dependencies: true
# compile_obj: true
@@ -252,7 +252,7 @@ jobs:
# package: bun-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
- cpu: haswell
arch: x86_64
tag: bun-darwin-x64
@@ -260,14 +260,14 @@ jobs:
package: bun-darwin-x64
runner: macos-11
artifact: bun-obj-darwin-x64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-amd64-lto.tar.gz"
# - cpu: native
# arch: aarch64
# tag: bun-darwin-aarch64
# obj: bun-obj-darwin-aarch64
# package: bun-darwin-aarch64
# artifact: bun-obj-darwin-aarch64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-macos-arm64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/apr12-23/bun-webkit-macos-arm64-lto.tar.gz"
# runner: macos-arm64
steps:
- uses: actions/checkout@v3
@@ -395,7 +395,7 @@ jobs:
runs-on: ${{ matrix.runner }}
needs: [macOS]
if: github.event_name == 'pull_request'
timeout-minutes: 10
timeout-minutes: 30
outputs:
failing_tests: ${{ steps.test.outputs.failing_tests }}
failing_tests_count: ${{ steps.test.outputs.failing_tests_count }}

View File

@@ -39,6 +39,7 @@ jobs:
npm:
name: Release to NPM
runs-on: ubuntu-latest
needs: sign
defaults:
run:
working-directory: packages/bun-release
@@ -144,3 +145,31 @@ jobs:
labels: ${{ steps.metadata.outputs.labels }}
build-args: |
BUN_VERSION=canary
s3:
name: Upload to S3
runs-on: ubuntu-latest
needs: sign
defaults:
run:
working-directory: packages/bun-release
steps:
- id: checkout
name: Checkout
uses: actions/checkout@v3
- id: setup-bun
name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: canary
- id: bun-install
name: Install Dependencies
run: bun install
- id: bun-run
name: Release
run: bun upload-s3 -- canary
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY}}
AWS_ENDPOINT: ${{ secrets.AWS_ENDPOINT }}
AWS_BUCKET: bun

View File

@@ -52,6 +52,7 @@ jobs:
npm:
name: Release to NPM
runs-on: ubuntu-latest
needs: sign
defaults:
run:
working-directory: packages/bun-release
@@ -83,6 +84,7 @@ jobs:
npm-types:
name: Release types to NPM
runs-on: ubuntu-latest
needs: sign
defaults:
run:
working-directory: packages/bun-types
@@ -174,6 +176,7 @@ jobs:
homebrew:
name: Release to Homebrew
runs-on: ubuntu-latest
needs: sign
steps:
- id: checkout
name: Checkout
@@ -211,3 +214,38 @@ jobs:
commit_user_name: robobun
commit_user_email: robobun@oven.sh
commit_author: robobun <robobun@oven.sh>
s3:
name: Upload to S3
runs-on: ubuntu-latest
needs: sign
defaults:
run:
working-directory: packages/bun-release
steps:
- id: checkout
name: Checkout
uses: actions/checkout@v3
- id: setup-env
name: Setup Environment
run: |
TAG="${{ github.event.inputs.tag }}"
TAG="${TAG:-"${{ github.event.release.tag_name }}"}"
echo "Setup tag: ${TAG}"
echo "TAG=${TAG}" >> ${GITHUB_ENV}
- id: setup-bun
name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: canary
- id: bun-install
name: Install Dependencies
run: bun install
- id: bun-run
name: Release
run: bun upload-s3 -- "${{ env.TAG }}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY}}
AWS_ENDPOINT: ${{ secrets.AWS_ENDPOINT }}
AWS_BUCKET: bun

58
.github/workflows/bun-test.yml vendored Normal file
View File

@@ -0,0 +1,58 @@
name: Test
on:
workflow_dispatch:
inputs:
version:
description: "The version of Bun to run"
required: true
default: "canary"
type: string
path:
description: "The path to the test files"
required: true
default: "test/"
type: string
timeout:
description: "The timeout per file in milliseconds"
required: true
default: "15000"
type: number
jobs:
test:
name: ${{ matrix.tag }}
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
tag: linux-x64
url: linux/x64?avx2=true
- os: ubuntu-latest
tag: linux-x64-baseline
url: linux/x64?baseline=true
- os: macos-latest
tag: darwin-x64
url: darwin/x64?avx2=true
- os: macos-latest
tag: darwin-x64-baseline
url: darwin/x64?baseline=true
steps:
- id: checkout
name: Checkout
uses: actions/checkout@v3
with:
submodules: false
- id: setup
name: Setup
uses: oven-sh/setup-bun@v1
with:
bun-download-url: https://bun.sh/download/${{ github.event.inputs.version }}/${{ matrix.url }}
- id: test
name: Test
run: |
bun install
bun install --cwd test
bun x ts-node --esm .github/scripts/test-runner.ts ${{ github.event.inputs.path }} --isolated --timeout=${{ github.event.inputs.timeout }}

View File

@@ -7,6 +7,8 @@ on:
- "test/**"
pull_request:
branches:
- main
paths:
- "packages/bun-types/**"
- "test/**"
@@ -15,9 +17,7 @@ jobs:
tests:
name: check-tests
runs-on: ubuntu-latest
defaults:
run:
working-directory: test
steps:
- name: Checkout repo
uses: actions/checkout@v3
@@ -27,5 +27,8 @@ jobs:
bun-version: canary
- name: Install dependencies
run: bun install
- name: Install dependencies
run: bun install
working-directory: test
- name: Typecheck tests
run: bun run typecheck

View File

@@ -1,59 +0,0 @@
name: Run Tests Manually
on:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
inputs:
version:
description: "Version"
required: true
default: "canary"
type: string
use_bun:
description: "Use Bun?"
required: true
default: true
type: boolean
jobs:
linux-test:
name: Tests ${{matrix.tag}} ${{github.event.inputs.version}}
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
include:
- tag: linux-x64
- tag: linux-x64-baseline
steps:
- id: checkout
name: Checkout
uses: actions/checkout@v3
with:
submodules: false
- id: install-npm
name: Install (npm)
run: |
npm install @oven/bun-${{matrix.tag}}@${{github.event.inputs.version}}
chmod +x node_modules/@oven/bun-${{matrix.tag}}/bin/bun
sudo cp node_modules/@oven/bun-${{matrix.tag}}/bin/bun /usr/bin/bun
- id: test
name: Test
if: ${{github.event.inputs.use_bun == 'true'}}
run: |
bun install
bun install --cwd test/bun.js
bun install --cwd test/bun.js/third-party/body-parser-test
cd packages/bun-internal-test
bun install
bun run test
- id: test-node-runner
name: Test (node runner)
if: ${{github.event.inputs.use_bun == 'false'}}
run: |
bun install
bun install --cwd test/bun.js
bun install --cwd test/bun.js/third-party/body-parser-test
cd packages/bun-internal-test
bun install
node src/runner.node.mjs

View File

@@ -1,7 +1,7 @@
name: zig-fmt
env:
ZIG_VERSION: 0.11.0-dev.1783+436e99d13
ZIG_VERSION: 0.11.0-dev.2571+31738de28
on:
pull_request:

3
.gitignore vendored
View File

@@ -13,7 +13,7 @@ dist
*.log
*.out.js
*.out.refresh.js
/package-lock.json
**/package-lock.json
build
*.wat
zig-out
@@ -45,6 +45,7 @@ outcss
txt.js
.idea
.vscode/cpp*
.vscode/clang*
node_modules_*
*.jsb

View File

@@ -7,3 +7,7 @@ if [ -d ./node_modules/bun-webkit ]; then
# get the first matching bun-webkit-* directory name
ln -s ./node_modules/$(ls ./node_modules | grep bun-webkit- | head -n 1) ./bun-webkit
fi
# sets up vscode C++ intellisense
rm -f .vscode/clang++
ln -s $(which clang++-15 || which clang++) .vscode/clang++ 2>/dev/null

View File

@@ -2,9 +2,7 @@
"configurations": [
{
"name": "Mac",
"forcedInclude": [
"${workspaceFolder}/src/bun.js/bindings/root.h"
],
"forcedInclude": ["${workspaceFolder}/src/bun.js/bindings/root.h"],
"includePath": [
"${workspaceFolder}/../webkit-build/include/",
"${workspaceFolder}/bun-webkit/include/",
@@ -57,7 +55,7 @@
"DU_DISABLE_RENAMING=1"
],
"macFrameworkPath": [],
"compilerPath": "/opt/homebrew/opt/llvm/bin/clang++",
"compilerPath": "${workspaceFolder}/.vscode/clang++",
"cStandard": "c17",
"cppStandard": "c++20"
}

View File

@@ -1,3 +1,10 @@
{
"recommendations": ["ziglang.vscode-zig", "esbenp.prettier-vscode", "xaver.clang-format", "vadimcn.vscode-lldb"]
"recommendations": [
"ziglang.vscode-zig",
"esbenp.prettier-vscode",
"xaver.clang-format",
"vadimcn.vscode-lldb",
"bierner.comment-tagged-templates",
"ms-vscode.cpptools"
]
}

91
.vscode/launch.json generated vendored
View File

@@ -138,13 +138,100 @@
"request": "launch",
"name": "bun build debug",
"program": "bun-debug",
"args": ["build", "--platform=bun", "--outdir=/tmp/testout", "${file}"],
"cwd": "${file}/../../",
"args": ["bun", "./test/fixtures/bundle/trivial/index.js"],
"cwd": "${workspaceFolder}",
"console": "internalConsole",
"env": {
"BUN_CONFIG_MINIFY_WHITESPACE": "1"
}
},
{
"type": "lldb",
"request": "launch",
"name": "bun build debug out.js",
"program": "bun-debug",
"args": ["--outfile=out.js", "bun", "${file}"],
"cwd": "${file}/../",
"console": "internalConsole",
"env": {
"BUN_CONFIG_MINIFY_WHITESPACE": "1"
}
},
{
"type": "lldb",
"request": "launch",
"name": "bun build debug STDOUT",
"program": "bun-debug",
"args": ["bun", "${file}"],
"cwd": "${file}/../",
"console": "internalConsole",
"env": {}
},
{
"type": "lldb",
"request": "launch",
"name": "bun build debug (no splitting, browser entry)",
"program": "bun-debug",
"args": [
"--entry-names=./[name].[ext]",
"--outdir=/Users/jarred/Code/bun-rsc/.rsc-no-split",
"--platform=browser",
"bun",
"./quick.tsx"
],
"cwd": "/Users/jarred/Code/bun-rsc",
"console": "internalConsole",
"env": {
"NODE_ENV": "production"
// "BUN_DEBUG_QUIET_LOGS": "1"
// "BUN_DUMP_SYMBOLS": "1"
}
},
{
"type": "lldb",
"request": "launch",
"name": "bun build debug (splitting, rsc)",
"program": "bun-debug",
"args": [
"--entry-names=./[name].[ext]",
"--outdir=/Users/jarred/Code/bun-rsc/.rsc-split",
"--server-components",
"--platform=bun",
"--splitting",
"bun",
"/Users/jarred/Code/bun-rsc/components/Message.tsx",
"/Users/jarred/Code/bun-rsc/components/Button.tsx",
],
"cwd": "/Users/jarred/Code/bun-rsc",
"console": "internalConsole",
"env": {
"NODE_ENV": "production"
// "BUN_DEBUG_QUIET_LOGS": "1"
// "BUN_DUMP_SYMBOLS": "1"
}
},
{
"type": "lldb",
"request": "launch",
"name": "bun build debug (NO splitting, rsc)",
"program": "bun-debug",
"args": [
"--entry-names=./[name].[ext]",
"--outdir=/Users/jarred/Code/bun-rsc/.rsccheck",
"--server-components",
"--platform=bun",
"bun",
"/Users/jarred/Code/bun-rsc/pages/index.js"
],
"cwd": "/Users/jarred/Code/bun-rsc",
"console": "internalConsole",
"env": {
"NODE_ENV": "production"
// "BUN_DEBUG_QUIET_LOGS": "1"
// "BUN_DUMP_SYMBOLS": "1"
}
},
{
"type": "lldb",
"request": "launch",

19
.vscode/settings.json vendored
View File

@@ -7,10 +7,7 @@
"search.followSymlinks": false,
"search.useIgnoreFiles": true,
"zig.buildOnSave": false,
"zig.buildArgs": [
"obj",
"-Dfor-editor"
],
"zig.buildArgs": ["obj", "-Dfor-editor"],
"zig.buildOption": "build",
"zig.buildFilePath": "${workspaceFolder}/build.zig",
"[zig]": {
@@ -27,6 +24,8 @@
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"zig.zls.enableInlayHints": false,
"[jsx]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
@@ -44,7 +43,7 @@
"editor.unicodeHighlight.ambiguousCharacters": false,
"editor.unicodeHighlight.invisibleCharacters": false,
"diffEditor.ignoreTrimWhitespace": false,
"editor.defaultFormatter": "yzhang.markdown-all-in-one",
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.wordWrap": "on",
"editor.quickSuggestions": {
@@ -208,9 +207,7 @@
"__verbose_abort": "cpp"
},
"cmake.configureOnOpen": false,
"C_Cpp.errorSquiggles": "Enabled",
"eslint.workingDirectories": [
"packages/bun-types"
],
"files.insertFinalNewline": true
}
"C_Cpp.errorSquiggles": "enabled",
"eslint.workingDirectories": ["packages/bun-types"],
"typescript.tsdk": "node_modules/typescript/lib"
}

View File

@@ -1,6 +1,6 @@
# Contributing to Bun
All contributions need test coverage. If you are adding a new feature, please add a test. If you are fixing a bug, please add a test that fails before your fix and passes after your fix.
> **Important:** All contributions need test coverage. If you are adding a new feature, please add a test. If you are fixing a bug, please add a test that fails before your fix and passes after your fix.
## Bun's codebase
@@ -16,6 +16,10 @@ Today (February 2023), Bun's codebase has five distinct parts:
The JavaScript transpiler & module resolver is mostly independent from the runtime. It predates the runtime and is entirely in Zig. The JavaScript parser is mostly in [`src/js_parser.zig`](src/js_parser.zig). The JavaScript AST data structures are mostly in [`src/js_ast.zig`](src/js_ast.zig). The JavaScript lexer is in [`src/js_lexer.zig`](src/js_lexer.zig). A lot of this code started as a port of esbuild's equivalent code from Go to Zig, but has had many small changes since then.
## Getting started
Please refer to [Bun's Development Guide](https://bun.sh/docs/project/development) to get your dev environment setup!
## Memory management in Bun
For the Zig code, please:

View File

@@ -12,7 +12,7 @@ ARG TRIPLET=${ARCH}-linux-gnu
ARG BUILDARCH=amd64
ARG WEBKIT_TAG=feb9
ARG ZIG_TAG=jul1
ARG ZIG_VERSION="0.11.0-dev.1783+436e99d13"
ARG ZIG_VERSION="0.11.0-dev.2571+31738de28"
ARG WEBKIT_BASENAME="bun-webkit-linux-$BUILDARCH"
ARG ZIG_FOLDERNAME=zig-linux-${BUILD_MACHINE_ARCH}-${ZIG_VERSION}
@@ -20,7 +20,7 @@ ARG ZIG_FILENAME=${ZIG_FOLDERNAME}.tar.xz
ARG WEBKIT_URL="https://github.com/oven-sh/WebKit/releases/download/$WEBKIT_TAG/${WEBKIT_BASENAME}.tar.gz"
ARG ZIG_URL="https://ziglang.org/builds/${ZIG_FILENAME}"
ARG GIT_SHA=""
ARG BUN_BASE_VERSION=0.5
ARG BUN_BASE_VERSION=0.6
FROM bitnami/minideb:bullseye as bun-base

View File

@@ -1,126 +0,0 @@
ARG DEBIAN_FRONTEND=noninteractive
ARG GITHUB_WORKSPACE=/build
ARG BUILDARCH=amd64
ARG ARCH=x86_64
ARG ZIG_PATH=${GITHUB_WORKSPACE}/zig
ARG WEBKIT_DIR=${GITHUB_WORKSPACE}/bun-webkit
ARG BUN_RELEASE_DIR=${GITHUB_WORKSPACE}/bun-release
ARG BUN_DEPS_OUT_DIR=${GITHUB_WORKSPACE}/bun-deps
ARG BUN_DIR=${GITHUB_WORKSPACE}/bun
ARG BUN_PACKAGES_DIR=${BUN_DIR}/packages
ARG ZIG_VERSION="0.11.0-dev.1783+436e99d13"
ARG ZIG_FOLDERNAME=zig-linux-${ARCH}-${ZIG_VERSION}
ARG ZIG_FILENAME=${ZIG_FOLDERNAME}.tar.xz
ARG ZIG_URL="https://ziglang.org/builds/${ZIG_FILENAME}"
FROM --platform=linux/${BUILDARCH} ubuntu:22.04 as bun.devcontainer
ARG DEBIAN_FRONTEND
ARG GITHUB_WORKSPACE
ARG BUILDARCH
ARG ZIG_PATH
ARG WEBKIT_DIR
ARG BUN_RELEASE_DIR
ARG BUN_DEPS_OUT_DIR
ARG BUN_DIR
ARG BUN_PACKAGES_DIR
ENV WEBKIT_OUT_DIR ${WEBKIT_DIR}
ENV PATH "$ZIG_PATH:$PATH"
ENV JSC_BASE_DIR $WEBKIT_OUT_DIR
ENV LIB_ICU_PATH ${WEBKIT_OUT_DIR}/lib
ENV BUN_RELEASE_DIR ${BUN_RELEASE_DIR}
ENV PATH "${BUN_PACKAGES_DIR}/bun-linux-x64:${BUN_PACKAGES_DIR}/bun-linux-aarch64:${BUN_PACKAGES_DIR}/debug-bun-linux-x64:${BUN_PACKAGES_DIR}/debug-bun-linux-aarch64:$PATH"
ENV PATH "/home/ubuntu/zls/zig-out/bin:$PATH"
ENV BUN_INSTALL /home/ubuntu/.bun
ENV XDG_CONFIG_HOME /home/ubuntu/.config
WORKDIR ${GITHUB_WORKSPACE}
RUN apt-get update && \
apt-get install --no-install-recommends -y wget gnupg2 curl lsb-release wget software-properties-common && \
add-apt-repository ppa:longsleep/golang-backports && \
wget https://apt.llvm.org/llvm.sh --no-check-certificate && \
chmod +x llvm.sh && \
./llvm.sh 15 && \
curl -fsSL https://deb.nodesource.com/setup_16.x | bash - && \
apt-get update && \
apt-get install --no-install-recommends -y \
ca-certificates \
curl \
gnupg2 \
software-properties-common \
cmake \
build-essential \
git \
libssl-dev \
ruby \
liblld-15-dev \
libclang-15-dev \
nodejs \
gcc \
g++ \
clang-15 \
clang-format-15 \
libc++-15-dev \
libc++abi-15-dev \
lld-15 \
libicu-dev \
wget \
rustc \
cargo \
unzip \
tar \
golang-go ninja-build pkg-config automake autoconf libtool curl && \
update-alternatives --install /usr/bin/cc cc /usr/bin/clang-15 90 && \
update-alternatives --install /usr/bin/cpp cpp /usr/bin/clang++-15 90 && \
update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-15 90 && \
npm install -g esbuild
ENV CC=clang-15
ENV CXX=clang++-15
ENV ZIG "${ZIG_PATH}/zig"
WORKDIR $GITHUB_WORKSPACE
RUN cd / && mkdir -p $BUN_RELEASE_DIR $BUN_DEPS_OUT_DIR ${BUN_DIR} ${BUN_DEPS_OUT_DIR}
WORKDIR $GITHUB_WORKSPACE
ARG ZIG_FOLDERNAME
ARG ZIG_FILENAME
ARG ZIG_URL
ADD $ZIG_URL .
RUN tar -xf ${ZIG_FILENAME} && \
rm ${ZIG_FILENAME} && \
mv ${ZIG_FOLDERNAME} ${ZIG_PATH};
RUN cd $GITHUB_WORKSPACE && \
curl -o bun-webkit-linux-$BUILDARCH.tar.gz -L https://github.com/oven-sh/WebKit/releases/download/feb25/bun-webkit-linux-$BUILDARCH.tar.gz && \
tar -xzf bun-webkit-linux-$BUILDARCH.tar.gz && \
rm bun-webkit-linux-$BUILDARCH.tar.gz && \
cat $WEBKIT_OUT_DIR/include/cmakeconfig.h > /dev/null
RUN apt-get -y update && update-alternatives --install /usr/bin/lldb lldb /usr/bin/lldb-15 90
COPY .devcontainer/workspace.code-workspace $GITHUB_WORKSPACE/workspace.code-workspace
COPY .devcontainer/zls.json $GITHUB_WORKSPACE/workspace.code-workspace
COPY .devcontainer/limits.conf /etc/security/limits.conf
COPY ".devcontainer/scripts/" /scripts/
COPY ".devcontainer/scripts/getting-started.sh" $GITHUB_WORKSPACE/getting-started.sh
COPY ".devcontainer/README.md" $GITHUB_WORKSPACE/README.md
ENV JSC_BASE_DIR=$WEBKIT_DIR
ENV WEBKIT_RELEASE_DIR=$WEBKIT_DIR
ENV WEBKIT_DEBUG_DIR=$WEBKIT_DIR
ENV WEBKIT_RELEASE_DIR_LTO=$WEBKIT_DIR
RUN mkdir -p /home/ubuntu/.bun /home/ubuntu/.config $GITHUB_WORKSPACE/bun && \
bash /scripts/common-debian.sh && \
bash /scripts/github.sh && \
bash /scripts/nice.sh && \
bash /scripts/zig-env.sh
COPY .devcontainer/zls.json /home/ubuntu/.config/zls.json

135
Makefile
View File

@@ -1,4 +1,4 @@
SHELL := $(shell which bash) # Use bash syntax to be consistent
SHELL := $(shell which bash) # Use bash syntax to be consistent
OS_NAME := $(shell uname -s | tr '[:upper:]' '[:lower:]')
ARCH_NAME_RAW := $(shell uname -m)
@@ -39,11 +39,11 @@ NATIVE_OR_OLD_MARCH = -march=nehalem
endif
MIN_MACOS_VERSION ?= $(DEFAULT_MIN_MACOS_VERSION)
BUN_BASE_VERSION = 0.5
BUN_BASE_VERSION = 0.6
AR=
BUN_OR_NODE = $(shell which bun || which node)
BUN_OR_NODE = $(shell which bun 2>/dev/null || which node 2>/dev/null)
CXX_VERSION=c++2a
TRIPLET = $(OS_NAME)-$(ARCH_NAME)
@@ -52,30 +52,31 @@ PACKAGES_REALPATH = $(realpath packages)
PACKAGE_DIR = $(PACKAGES_REALPATH)/$(PACKAGE_NAME)
DEBUG_PACKAGE_DIR = $(PACKAGES_REALPATH)/debug-$(PACKAGE_NAME)
RELEASE_BUN = $(PACKAGE_DIR)/bun
DEBUG_BIN = $(DEBUG_PACKAGE_DIR)/
DEBUG_BIN = $(DEBUG_PACKAGE_DIR)
DEBUG_BUN = $(DEBUG_BIN)/bun-debug
BUILD_ID = $(shell cat ./src/build-id)
PACKAGE_JSON_VERSION = $(BUN_BASE_VERSION).$(BUILD_ID)
BUN_BUILD_TAG = bun-v$(PACKAGE_JSON_VERSION)
BUN_RELEASE_BIN = $(PACKAGE_DIR)/bun
PRETTIER ?= $(shell which prettier || echo "./node_modules/.bin/prettier")
DSYMUTIL ?= $(shell which dsymutil || which dsymutil-15)
PRETTIER ?= $(shell which prettier 2>/dev/null || echo "./node_modules/.bin/prettier")
ESBUILD = $(shell which esbuild 2>/dev/null || echo "./node_modules/.bin/esbuild")
DSYMUTIL ?= $(shell which dsymutil 2>/dev/null || which dsymutil-15 2>/dev/null)
WEBKIT_DIR ?= $(realpath src/bun.js/WebKit)
WEBKIT_RELEASE_DIR ?= $(WEBKIT_DIR)/WebKitBuild/Release
WEBKIT_DEBUG_DIR ?= $(WEBKIT_DIR)/WebKitBuild/Debug
WEBKIT_RELEASE_DIR_LTO ?= $(WEBKIT_DIR)/WebKitBuild/ReleaseLTO
NPM_CLIENT ?= $(shell which bun || which npm)
ZIG ?= $(shell which zig || echo -e "error: Missing zig. Please make sure zig is in PATH. Or set ZIG=/path/to-zig-executable")
NPM_CLIENT ?= $(shell which bun 2>/dev/null || which npm 2>/dev/null)
ZIG ?= $(shell which zig 2>/dev/null || echo -e "error: Missing zig. Please make sure zig is in PATH. Or set ZIG=/path/to-zig-executable")
# We must use the same compiler version for the JavaScriptCore bindings and JavaScriptCore
# If we don't do this, strange memory allocation failures occur.
# This is easier to happen than you'd expect.
# Using realpath here causes issues because clang uses clang++ as a symlink
# so if that's resolved, it won't build for C++
REAL_CC = $(shell which clang-15 || which clang)
REAL_CXX = $(shell which clang++-15 || which clang++)
REAL_CC = $(shell which clang-15 2>/dev/null || which clang 2>/dev/null)
REAL_CXX = $(shell which clang++-15 2>/dev/null || which clang++ 2>/dev/null)
CC = $(REAL_CC)
CXX = $(REAL_CXX)
@@ -85,7 +86,7 @@ CCACHE_PATH := $(shell which ccache 2>/dev/null)
CCACHE_CC_FLAG = CC=$(CCACHE_CC_OR_CC)
ifeq (,$(findstring,$(shell which ccache),ccache))
ifeq (,$(findstring,$(shell which ccache 2>/dev/null),ccache))
CMAKE_CXX_COMPILER_LAUNCHER_FLAG := -DCMAKE_CXX_COMPILER_LAUNCHER=$(CCACHE_PATH) -DCMAKE_C_COMPILER_LAUNCHER=$(CCACHE_PATH)
CCACHE_CC_OR_CC := "$(CCACHE_PATH) $(REAL_CC)"
export CCACHE_COMPILERTYPE = clang
@@ -117,7 +118,7 @@ ifeq ($(OS_NAME),darwin)
endif
# macOS sed is different
SED = $(shell which gsed || which sed)
SED = $(shell which gsed 2>/dev/null || which sed 2>/dev/null)
BUN_DIR ?= $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
BUN_DEPS_DIR ?= $(shell pwd)/src/deps
@@ -146,7 +147,7 @@ CMAKE_FLAGS_WITHOUT_RELEASE = -DCMAKE_C_COMPILER=$(CC) \
-DCMAKE_OSX_DEPLOYMENT_TARGET=$(MIN_MACOS_VERSION) \
$(CMAKE_CXX_COMPILER_LAUNCHER_FLAG) \
-DCMAKE_AR=$(AR) \
-DCMAKE_RANLIB=$(which llvm-15-ranlib || which llvm-ranlib)
-DCMAKE_RANLIB=$(which llvm-15-ranlib 2>/dev/null || which llvm-ranlib 2>/dev/null)
@@ -168,7 +169,7 @@ endif
ifeq ($(OS_NAME),linux)
LIBICONV_PATH =
AR = $(shell which llvm-ar-15 || which llvm-ar || which ar)
AR = $(shell which llvm-ar-15 2>/dev/null || which llvm-ar 2>/dev/null || which ar 2>/dev/null)
endif
OPTIMIZATION_LEVEL=-O3 $(MARCH_NATIVE)
@@ -184,14 +185,13 @@ DEFAULT_USE_BMALLOC := 1
USE_BMALLOC ?= DEFAULT_USE_BMALLOC
# Set via postinstall
AUTO_JSX_BASE_DIR ?= $(realpath $(firstword $(wildcard bun-webkit)))
ifeq (,$(AUTO_JSX_BASE_DIR))
AUTO_JSX_BASE_DIR ?= $(HOME)/webkit-build
ifeq (,$(realpath $(JSC_BASE_DIR)))
JSC_BASE_DIR = $(realpath $(firstword $(wildcard bun-webkit)))
ifeq (,$(JSC_BASE_DIR))
JSC_BASE_DIR = $(HOME)/webkit-build
endif
endif
JSC_BASE_DIR ?= $(AUTO_JSX_BASE_DIR)
DEFAULT_JSC_LIB :=
DEFAULT_JSC_LIB_DEBUG :=
@@ -266,7 +266,7 @@ STRIP=/usr/bin/strip
endif
ifeq ($(OS_NAME),linux)
STRIP=$(shell which llvm-strip || which llvm-strip-15 || which strip || echo "Missing strip")
STRIP=$(shell which llvm-strip 2>/dev/null || which llvm-strip-15 2>/dev/null || which strip 2>/dev/null || echo "Missing strip")
endif
@@ -518,6 +518,11 @@ bun:
npm-install:
$(NPM_CLIENT) install --ignore-scripts --production
npm-install-dev:
$(NPM_CLIENT) install
cd test && $(NPM_CLIENT) install
cd packages/bun-types && $(NPM_CLIENT) install --production
print-% : ; @echo $* = $($*)
get-% : ; @echo $($*)
print-version:
@@ -540,13 +545,16 @@ tinycc:
make -j10 && \
cp $(TINYCC_DIR)/*.a $(BUN_DEPS_OUT_DIR)
PYTHON=$(shell which python 2>/dev/null || which python3 2>/dev/null || which python2 2>/dev/null)
.PHONY: builtins
builtins: ## to generate builtins
@if [ -z "$(WEBKIT_DIR)" ] || [ ! -d "$(WEBKIT_DIR)/Source" ]; then echo "WebKit is not cloned. Please run make init-submodules"; exit 1; fi
rm -f src/bun.js/bindings/*Builtin*.cpp src/bun.js/bindings/*Builtin*.h src/bun.js/bindings/*Builtin*.cpp
rm -rf src/bun.js/builtins/cpp
mkdir -p src/bun.js/builtins/cpp
$(shell which python || which python2) $(realpath $(WEBKIT_DIR)/Source/JavaScriptCore/Scripts/generate-js-builtins.py) -i $(realpath src)/bun.js/builtins/js -o $(realpath src)/bun.js/builtins/cpp --framework WebCore --force
$(shell which python || which python2) $(realpath $(WEBKIT_DIR)/Source/JavaScriptCore/Scripts/generate-js-builtins.py) -i $(realpath src)/bun.js/builtins/js -o $(realpath src)/bun.js/builtins/cpp --framework WebCore --wrappers-only
$(PYTHON) $(realpath $(WEBKIT_DIR)/Source/JavaScriptCore/Scripts/generate-js-builtins.py) -i $(realpath src)/bun.js/builtins/js -o $(realpath src)/bun.js/builtins/cpp --framework WebCore --force
$(PYTHON) $(realpath $(WEBKIT_DIR)/Source/JavaScriptCore/Scripts/generate-js-builtins.py) -i $(realpath src)/bun.js/builtins/js -o $(realpath src)/bun.js/builtins/cpp --framework WebCore --wrappers-only
rm -rf /tmp/1.h src/bun.js/builtins/cpp/WebCoreJSBuiltinInternals.h.1
echo -e '// clang-format off\nnamespace Zig { class GlobalObject; }\n#include "root.h"\n' >> /tmp/1.h
cat /tmp/1.h src/bun.js/builtins/cpp/WebCoreJSBuiltinInternals.h > src/bun.js/builtins/cpp/WebCoreJSBuiltinInternals.h.1
@@ -665,7 +673,8 @@ require:
@echo "Checking if the required utilities are available..."
@if [ $(CLANG_VERSION) -lt "15" ]; then echo -e "ERROR: clang version >=15 required, found: $(CLANG_VERSION). Install with:\n\n $(POSIX_PKG_MANAGER) install llvm@15"; exit 1; fi
@cmake --version >/dev/null 2>&1 || (echo -e "ERROR: cmake is required."; exit 1)
@esbuild --version >/dev/null 2>&1 || (echo -e "ERROR: esbuild is required."; exit 1)
@$(PYTHON) --version >/dev/null 2>&1 || (echo -e "ERROR: python is required."; exit 1)
@$(ESBUILD) --version >/dev/null 2>&1 || (echo -e "ERROR: esbuild is required."; exit 1)
@$(NPM_CLIENT) --version >/dev/null 2>&1 || (echo -e "ERROR: NPM client (bun or npm) is required."; exit 1)
@go version >/dev/null 2>&1 || (echo -e "ERROR: go is required."; exit 1)
@which aclocal > /dev/null || (echo -e "ERROR: automake is required. Install with:\n\n $(POSIX_PKG_MANAGER) install automake"; exit 1)
@@ -674,7 +683,7 @@ require:
@echo "You have the dependencies installed! Woo"
init-submodules:
git submodule update --init --recursive --progress --depth=1
git submodule update --init --recursive --progress --depth=1 --checkout
.PHONY: build-obj
build-obj:
@@ -720,10 +729,10 @@ wasm: api build-obj-wasm-small
@cp src/api/schema.d.ts packages/bun-wasm/schema.d.ts
@cp src/api/schema.js packages/bun-wasm/schema.js
@cd packages/bun-wasm && $(NPM_CLIENT) run tsc -- -p .
@esbuild --sourcemap=external --external:fs --define:process.env.NODE_ENV='"production"' --outdir=packages/bun-wasm --target=esnext --bundle packages/bun-wasm/index.ts --format=esm --minify 2> /dev/null
@$(ESBUILD) --sourcemap=external --external:fs --define:process.env.NODE_ENV='"production"' --outdir=packages/bun-wasm --target=esnext --bundle packages/bun-wasm/index.ts --format=esm --minify 2> /dev/null
@mv packages/bun-wasm/index.js packages/bun-wasm/index.mjs
@mv packages/bun-wasm/index.js.map packages/bun-wasm/index.mjs.map
@esbuild --sourcemap=external --external:fs --define:process.env.NODE_ENV='"production"' --outdir=packages/bun-wasm --target=esnext --bundle packages/bun-wasm/index.ts --format=cjs --minify --platform=node 2> /dev/null
@$(ESBUILD) --sourcemap=external --external:fs --define:process.env.NODE_ENV='"production"' --outdir=packages/bun-wasm --target=esnext --bundle packages/bun-wasm/index.ts --format=cjs --minify --platform=node 2> /dev/null
@mv packages/bun-wasm/index.js packages/bun-wasm/index.cjs
@mv packages/bun-wasm/index.js.map packages/bun-wasm/index.cjs.map
@rm -rf packages/bun-wasm/*.tsbuildinfo
@@ -806,21 +815,21 @@ node-fallbacks:
.PHONY: fallback_decoder
fallback_decoder:
@esbuild --target=esnext --bundle src/fallback.ts --format=iife --platform=browser --minify > src/fallback.out.js
@$(ESBUILD) --target=esnext --bundle src/fallback.ts --format=iife --platform=browser --minify > src/fallback.out.js
.PHONY: runtime_js
runtime_js:
@NODE_ENV=production esbuild --define:process.env.NODE_ENV="production" --target=esnext --bundle src/runtime/index.ts --format=iife --platform=browser --global-name=BUN_RUNTIME --minify --external:/bun:* > src/runtime.out.js; cat src/runtime.footer.js >> src/runtime.out.js
@NODE_ENV=production esbuild --define:process.env.NODE_ENV="production" --target=esnext --bundle src/runtime/index-with-refresh.ts --format=iife --platform=browser --global-name=BUN_RUNTIME --minify --external:/bun:* > src/runtime.out.refresh.js; cat src/runtime.footer.with-refresh.js >> src/runtime.out.refresh.js
@NODE_ENV=production esbuild --define:process.env.NODE_ENV="production" --target=esnext --bundle src/runtime/index-without-hmr.ts --format=iife --platform=node --global-name=BUN_RUNTIME --minify --external:/bun:* > src/runtime.node.pre.out.js; cat src/runtime.node.pre.out.js src/runtime.footer.node.js > src/runtime.node.out.js
@NODE_ENV=production esbuild --define:process.env.NODE_ENV="production" --target=esnext --bundle src/runtime/index-without-hmr.ts --format=iife --platform=node --global-name=BUN_RUNTIME --minify --external:/bun:* > src/runtime.bun.pre.out.js; cat src/runtime.bun.pre.out.js src/runtime.footer.bun.js > src/runtime.bun.out.js
@NODE_ENV=production $(ESBUILD) --define:process.env.NODE_ENV="production" --target=esnext --bundle src/runtime/index.ts --format=iife --platform=browser --global-name=BUN_RUNTIME --minify --external:/bun:* > src/runtime.out.js; cat src/runtime.footer.js >> src/runtime.out.js
@NODE_ENV=production $(ESBUILD) --define:process.env.NODE_ENV="production" --target=esnext --bundle src/runtime/index-with-refresh.ts --format=iife --platform=browser --global-name=BUN_RUNTIME --minify --external:/bun:* > src/runtime.out.refresh.js; cat src/runtime.footer.with-refresh.js >> src/runtime.out.refresh.js
@NODE_ENV=production $(ESBUILD) --define:process.env.NODE_ENV="production" --target=esnext --bundle src/runtime/index-without-hmr.ts --format=iife --platform=node --global-name=BUN_RUNTIME --minify --external:/bun:* > src/runtime.node.pre.out.js; cat src/runtime.node.pre.out.js src/runtime.footer.node.js > src/runtime.node.out.js
@NODE_ENV=production $(ESBUILD) --define:process.env.NODE_ENV="production" --target=esnext --bundle src/runtime/index-without-hmr.ts --format=iife --platform=node --global-name=BUN_RUNTIME --minify --external:/bun:* > src/runtime.bun.pre.out.js; cat src/runtime.bun.pre.out.js src/runtime.footer.bun.js > src/runtime.bun.out.js
.PHONY: runtime_js_dev
runtime_js_dev:
@NODE_ENV=development esbuild --define:process.env.NODE_ENV="development" --target=esnext --bundle src/runtime/index.ts --format=iife --platform=browser --global-name=BUN_RUNTIME --external:/bun:* > src/runtime.out.js; cat src/runtime.footer.js >> src/runtime.out.js
@NODE_ENV=development esbuild --define:process.env.NODE_ENV="development" --target=esnext --bundle src/runtime/index-with-refresh.ts --format=iife --platform=browser --global-name=BUN_RUNTIME --external:/bun:* > src/runtime.out.refresh.js; cat src/runtime.footer.with-refresh.js >> src/runtime.out.refresh.js
@NODE_ENV=development esbuild --define:process.env.NODE_ENV="development" --target=esnext --bundle src/runtime/index-without-hmr.ts --format=iife --platform=node --global-name=BUN_RUNTIME --external:/bun:* > src/runtime.node.pre.out.js; cat src/runtime.node.pre.out.js src/runtime.footer.node.js > src/runtime.node.out.js
@NODE_ENV=development esbuild --define:process.env.NODE_ENV="development" --target=esnext --bundle src/runtime/index-without-hmr.ts --format=iife --platform=node --global-name=BUN_RUNTIME --external:/bun:* > src/runtime.bun.pre.out.js; cat src/runtime.bun.pre.out.js src/runtime.footer.bun.js > src/runtime.bun.out.js
@NODE_ENV=development $(ESBUILD) --define:process.env.NODE_ENV="development" --target=esnext --bundle src/runtime/index.ts --format=iife --platform=browser --global-name=BUN_RUNTIME --external:/bun:* > src/runtime.out.js; cat src/runtime.footer.js >> src/runtime.out.js
@NODE_ENV=development $(ESBUILD) --define:process.env.NODE_ENV="development" --target=esnext --bundle src/runtime/index-with-refresh.ts --format=iife --platform=browser --global-name=BUN_RUNTIME --external:/bun:* > src/runtime.out.refresh.js; cat src/runtime.footer.with-refresh.js >> src/runtime.out.refresh.js
@NODE_ENV=development $(ESBUILD) --define:process.env.NODE_ENV="development" --target=esnext --bundle src/runtime/index-without-hmr.ts --format=iife --platform=node --global-name=BUN_RUNTIME --external:/bun:* > src/runtime.node.pre.out.js; cat src/runtime.node.pre.out.js src/runtime.footer.node.js > src/runtime.node.out.js
@NODE_ENV=development $(ESBUILD) --define:process.env.NODE_ENV="development" --target=esnext --bundle src/runtime/index-without-hmr.ts --format=iife --platform=node --global-name=BUN_RUNTIME --external:/bun:* > src/runtime.bun.pre.out.js; cat src/runtime.bun.pre.out.js src/runtime.footer.bun.js > src/runtime.bun.out.js
.PHONY: bun_error
bun_error:
@@ -829,7 +838,7 @@ bun_error:
.PHONY: generate-install-script
generate-install-script:
@rm -f $(PACKAGES_REALPATH)/bun/install.js
@esbuild --log-level=error --define:BUN_VERSION="\"$(PACKAGE_JSON_VERSION)\"" --define:process.env.NODE_ENV="\"production\"" --platform=node --format=cjs $(PACKAGES_REALPATH)/bun/install.ts > $(PACKAGES_REALPATH)/bun/install.js
@$(ESBUILD) --log-level=error --define:BUN_VERSION="\"$(PACKAGE_JSON_VERSION)\"" --define:process.env.NODE_ENV="\"production\"" --platform=node --format=cjs $(PACKAGES_REALPATH)/bun/install.ts > $(PACKAGES_REALPATH)/bun/install.js
.PHONY: fetch
fetch: $(IO_FILES)
@@ -911,25 +920,6 @@ jsc-bindings: headers bindings
clone-submodules:
git -c submodule."src/bun.js/WebKit".update=none submodule update --init --recursive --depth=1 --progress
.PHONY: devcontainer
devcontainer: $(OBJ_DIR) $(DEBUG_OBJ_DIR) clone-submodules mimalloc zlib libarchive boringssl picohttp identifier-cache node-fallbacks npm-install api analytics bun_error fallback_decoder bindings uws lolhtml usockets tinycc c-ares runtime_js_dev sqlite
.PHONY: devcontainer-build
devcontainer-build:
DOCKER_BUILDARCH="$(DOCKER_BUILDARCH)" devcontainer build --workspace-folder .
.PHONY: devcontainer-up
devcontainer-up:
DOCKER_BUILDARCH="$(DOCKER_BUILDARCH)" devcontainer up --workspace-folder .
.PHONY: devcontainer-rebuild
devcontainer-rebuild:
DOCKER_BUILDARCH="$(DOCKER_BUILDARCH)" devcontainer up --workspace-folder . --remove-existing-container
.PHONY: devcontainer-sh
devcontainer-sh:
DOCKER_BUILDARCH="$(DOCKER_BUILDARCH)" devcontainer exec --workspace-folder . zsh
CLANG_FORMAT := $(shell command -v clang-format 2> /dev/null)
.PHONY: headers
@@ -1098,7 +1088,7 @@ dev-obj-linux:
dev: mkdir-dev dev-obj bun-link-lld-debug
mkdir-dev:
mkdir -p $(DEBUG_PACKAGE_DIR)/bin
mkdir -p $(DEBUG_PACKAGE_DIR)
test-all:
$(RELEASE_BUN) test
@@ -1121,10 +1111,10 @@ jsc-copy-headers:
cp $(WEBKIT_DIR)/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/JSModuleNamespaceObject.h
cp $(WEBKIT_DIR)/Source/JavaScriptCore/jit/JIT.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/JIT.h
cp $(WEBKIT_DIR)/Source/JavaScriptCore/bytecode/StructureStubInfo.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/StructureStubInfo.h
cp $(WEBKIT_DIR)/Source/JavaScriptCore/bytecode/PolymorphicAccess.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/PolymorphicAccess.h
cp $(WEBKIT_DIR)/Source/JavaScriptCore/bytecode/AccessCase.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/AccessCase.h
cp $(WEBKIT_DIR)/Source/JavaScriptCore/bytecode/ObjectPropertyConditionSet.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/ObjectPropertyConditionSet.h
cp $(WEBKIT_DIR)/Source/JavaScriptCore/bytecode/PolyProtoAccessChain.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/PolyProtoAccessChain.h
cp $(WEBKIT_DIR)/Source/JavaScriptCore/bytecode/InlineCacheCompiler.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/InlineCacheCompiler.h
cp $(WEBKIT_DIR)/Source/JavaScriptCore/bytecode/PutKind.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/PutKind.h
cp $(WEBKIT_DIR)/Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/StructureStubClearingWatchpoint.h
cp $(WEBKIT_DIR)/Source/JavaScriptCore/bytecode/AdaptiveInferredPropertyValueWatchpointBase.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/AdaptiveInferredPropertyValueWatchpointBase.h
@@ -1330,8 +1320,9 @@ mimalloc-debug:
-DMI_OVERRIDE=OFF \
-DCMAKE_C_FLAGS="$(CFLAGS)" \
-DCMAKE_CXX_FLAGS="$(CFLAGS)" \
-GNinja \
. \
&& make -j $(CPUS);
&& ninja
cp $(BUN_DEPS_DIR)/mimalloc/$(_MIMALLOC_DEBUG_FILE) $(BUN_DEPS_OUT_DIR)/$(MIMALLOC_FILE)
@@ -1353,8 +1344,9 @@ mimalloc:
-DMI_OVERRIDE=OFF \
-DMI_OSX_ZONE=OFF \
-DCMAKE_C_FLAGS="$(CFLAGS)" \
.\
&& make -j $(CPUS);
-GNinja \
. \
&& ninja;
cp $(BUN_DEPS_DIR)/mimalloc/$(MIMALLOC_INPUT_PATH) $(BUN_DEPS_OUT_DIR)/$(MIMALLOC_FILE)
@@ -1835,12 +1827,31 @@ copy-to-bun-release-dir-bin:
PACKAGE_MAP = --pkg-begin async_io $(BUN_DIR)/src/io/io_darwin.zig --pkg-begin bun $(BUN_DIR)/src/bun_redirect.zig --pkg-end --pkg-end --pkg-begin javascript_core $(BUN_DIR)/src/jsc.zig --pkg-begin bun $(BUN_DIR)/src/bun_redirect.zig --pkg-end --pkg-end --pkg-begin bun $(BUN_DIR)/src/bun_redirect.zig --pkg-end
.PHONY: vendor-without-npm
vendor-without-npm: node-fallbacks runtime_js fallback_decoder bun_error mimalloc picohttp zlib boringssl libarchive lolhtml sqlite usockets uws tinycc c-ares
.PHONY: vendor-without-check
vendor-without-check: npm-install node-fallbacks runtime_js fallback_decoder bun_error mimalloc picohttp zlib boringssl libarchive lolhtml sqlite usockets uws tinycc c-ares
vendor-without-check: npm-install vendor-without-npm
.PHONY: vendor
vendor: require init-submodules vendor-without-check
.PHONY: vendor-dev
vendor-dev: require init-submodules npm-install-dev vendor-without-npm
.PHONY: bun
bun: vendor identifier-cache build-obj bun-link-lld-release bun-codesign-release-local
.PHONY: regenerate-bindings
regenerate-bindings:
@make clean-bindings builtins
@make bindings -j$(CPU_COUNT)
.PHONY: setup
setup: vendor-dev builtins identifier-cache clean-bindings
make jsc-check
make bindings -j$(CPU_COUNT)
@echo ""
@echo "Development environment setup complete"
@echo "Run \`make dev\` to build \`bun-debug\`"
@echo ""

View File

@@ -40,7 +40,7 @@ bun run index.tsx # TS and JSX supported out of the box
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
bunx cowsay 'Hello, world!' # execute a package
```
## Install
@@ -130,7 +130,7 @@ bun upgrade --canary
## Contributing
Refer to the [Project > Contributing](https://bun.sh/docs/project/developing) guide to start contributing to Bun.
Refer to the [Project > Development](https://bun.sh/docs/project/development) guide to start contributing to Bun.
## License

View File

@@ -0,0 +1,4 @@
/** @type {import('eslint').Linter.Config} */
module.exports = {
extends: ["@remix-run/eslint-config", "@remix-run/eslint-config/node"],
};

10
bench/install/.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
node_modules
/.cache
/build
/public/build
.env
package-lock.json
yarn.lock
pnpm-lock.yaml
bun.lockb

18
bench/install/README.md Normal file
View File

@@ -0,0 +1,18 @@
# `install` benchmark
Requires [`hyperfine`](https://github.com/sharkdp/hyperfine)
```
$ hyperfine --prepare 'rm -rf node_modules' --warmup 1 --runs 3 'bun install' 'pnpm install' 'yarn' 'npm install'
```
To check that the app is working as expected:
```
$ bun run dev
$ npm run dev
$ yarn dev
$ pnpm dev
```
Then visit [http://localhost:3000](http://localhost:3000).

View File

@@ -0,0 +1,18 @@
/**
* By default, Remix will handle hydrating your app on the client for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/docs/en/main/file-conventions/entry.client
*/
import { RemixBrowser } from "@remix-run/react";
import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";
startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RemixBrowser />
</StrictMode>,
);
});

View File

@@ -0,0 +1,101 @@
/**
* By default, Remix will handle generating the HTTP Response for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/docs/en/main/file-conventions/entry.server
*/
import { PassThrough } from "node:stream";
import type { EntryContext } from "@remix-run/node";
import { Response } from "@remix-run/node";
import { RemixServer } from "@remix-run/react";
import isbot from "isbot";
import { renderToPipeableStream } from "react-dom/server";
const ABORT_DELAY = 5_000;
export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
) {
return isbot(request.headers.get("user-agent"))
? handleBotRequest(request, responseStatusCode, responseHeaders, remixContext)
: handleBrowserRequest(request, responseStatusCode, responseHeaders, remixContext);
}
function handleBotRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
) {
return new Promise((resolve, reject) => {
const { pipe, abort } = renderToPipeableStream(
<RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />,
{
onAllReady() {
const body = new PassThrough();
responseHeaders.set("Content-Type", "text/html");
resolve(
new Response(body, {
headers: responseHeaders,
status: responseStatusCode,
}),
);
pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
responseStatusCode = 500;
console.error(error);
},
},
);
setTimeout(abort, ABORT_DELAY);
});
}
function handleBrowserRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
) {
return new Promise((resolve, reject) => {
const { pipe, abort } = renderToPipeableStream(
<RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />,
{
onShellReady() {
const body = new PassThrough();
responseHeaders.set("Content-Type", "text/html");
resolve(
new Response(body, {
headers: responseHeaders,
status: responseStatusCode,
}),
);
pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
console.error(error);
responseStatusCode = 500;
},
},
);
setTimeout(abort, ABORT_DELAY);
});
}

View File

@@ -0,0 +1,20 @@
import { Links, LiveReload, Meta, Outlet, Scripts, ScrollRestoration } from "@remix-run/react";
export default function App() {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<Meta />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}

View File

@@ -0,0 +1,30 @@
import type { V2_MetaFunction } from "@remix-run/node";
export const meta: V2_MetaFunction = () => {
return [{ title: "New Remix App" }];
};
export default function Index() {
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1>Welcome to Remix</h1>
<ul>
<li>
<a target="_blank" href="https://remix.run/tutorials/blog" rel="noreferrer">
15m Quickstart Blog Tutorial
</a>
</li>
<li>
<a target="_blank" href="https://remix.run/tutorials/jokes" rel="noreferrer">
Deep Dive Jokes App Tutorial
</a>
</li>
<li>
<a target="_blank" href="https://remix.run/docs" rel="noreferrer">
Remix Docs
</a>
</li>
</ul>
</div>
);
}

View File

@@ -0,0 +1,31 @@
{
"private": true,
"sideEffects": false,
"scripts": {
"build": "remix build",
"dev": "remix dev",
"start": "remix-serve build",
"typecheck": "tsc",
"clean": "rm -rf node_modules",
"bench": "hyperfine --prepare 'rm -rf node_modules' --warmup 1 --runs 3 'bun install' 'pnpm install' 'yarn' 'npm install'"
},
"dependencies": {
"@remix-run/node": "^1.15.0",
"@remix-run/react": "^1.15.0",
"@remix-run/serve": "^1.15.0",
"isbot": "^3.6.5",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@remix-run/dev": "^1.15.0",
"@remix-run/eslint-config": "^1.15.0",
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.8",
"eslint": "^8.27.0",
"typescript": "^4.8.4"
},
"engines": {
"node": ">=14"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,14 @@
/** @type {import('@remix-run/dev').AppConfig} */
module.exports = {
ignoredRouteFiles: ["**/.*"],
// appDirectory: "app",
// assetsBuildDirectory: "public/build",
// serverBuildPath: "build/index.js",
// publicPath: "/build/",
future: {
v2_errorBoundary: true,
v2_meta: true,
v2_normalizeFormMethod: true,
v2_routeConvention: true,
},
};

2
bench/install/remix.env.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
/// <reference types="@remix-run/dev" />
/// <reference types="@remix-run/node" />

View File

@@ -0,0 +1,22 @@
{
"include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2019"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"moduleResolution": "node",
"resolveJsonModule": true,
"target": "ES2019",
"strict": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"paths": {
"~/*": ["./app/*"]
},
// Remix takes care of building everything in `remix build`.
"noEmit": true
}
}

View File

@@ -0,0 +1,42 @@
import { Buffer } from "node:buffer";
import { writeFile } from "node:fs/promises";
import { bench, run } from "mitata";
var hugeFile = Buffer.alloc(1024 * 1024 * 64);
var medFile = Buffer.alloc(1024 * 1024 * 16);
var humongousFile = Buffer.alloc(1024 * 1024 * 256);
bench(
`fs.writeFile ${new Intl.NumberFormat("en-US", {
style: "unit",
unit: "megabyte",
unitDisplay: "narrow",
}).format(humongousFile.byteLength / 1024 / 1024)}`,
async () => {
await writeFile("/tmp/bun.bench-out.humongousFile.txt" + ((Math.random() * 65432) | 0).toString(16), humongousFile);
},
);
bench(
`fs.writeFile ${new Intl.NumberFormat("en-US", {
style: "unit",
unit: "megabyte",
unitDisplay: "narrow",
}).format(hugeFile.byteLength / 1024 / 1024)}`,
async () => {
await writeFile("/tmp/bun.bench-out.huge.txt" + ((Math.random() * 65432) | 0).toString(16), hugeFile);
},
);
bench(
`fs.writeFile ${new Intl.NumberFormat("en-US", {
style: "unit",
unit: "megabyte",
unitDisplay: "narrow",
}).format(medFile.byteLength / 1024 / 1024)}`,
async () => {
await writeFile("/tmp/bun.bench-out.medium.txt" + ((Math.random() * 65432) | 0).toString(16), medFile);
},
);
await run();

View File

@@ -44,10 +44,6 @@ const color_map = std.ComptimeStringMap([]const u8, .{
});
fn addInternalPackages(b: *Build, step: *CompileStep, _: std.mem.Allocator, _: []const u8, target: anytype) !void {
var bun = b.createModule(.{
.source_file = FileSource.relative("src/bun_redirect.zig"),
});
var io: *Module = brk: {
if (target.isDarwin()) {
break :brk b.createModule(.{
@@ -65,7 +61,6 @@ fn addInternalPackages(b: *Build, step: *CompileStep, _: std.mem.Allocator, _: [
};
step.addModule("async_io", io);
step.addModule("bun", bun);
}
const BunBuildOptions = struct {
@@ -218,6 +213,7 @@ pub fn build(b: *Build) !void {
.target = target,
.optimize = optimize,
});
var default_build_options: BunBuildOptions = brk: {
const is_baseline = arch.isX86() and (target.cpu_model == .baseline or
!std.Target.x86.featureSetHas(target.getCpuFeatures(), .avx2));
@@ -285,11 +281,12 @@ pub fn build(b: *Build) !void {
std.io.getStdErr().writer().print("Output: {s}/{s}\n\n", .{ output_dir, bun_executable_name }) catch unreachable;
defer obj_step.dependOn(&obj.step);
obj.emit_bin = .{
.emit_to = b.fmt("{s}/{s}.o", .{ output_dir, bun_executable_name }),
};
var actual_build_options = default_build_options;
if (b.option(bool, "generate-sizes", "Generate sizes of things") orelse false) {
actual_build_options.sizegen = true;
obj.setOutputDir(b.pathFromRoot("misctools/sizegen"));
}
obj.addOptions("build_options", actual_build_options.step(b));
@@ -299,7 +296,6 @@ pub fn build(b: *Build) !void {
obj.strip = false;
obj.bundle_compiler_rt = false;
obj.omit_frame_pointer = optimize != .Debug;
// Disable stack probing on x86 so we don't need to include compiler_rt
if (target.getCpuArch().isX86()) obj.disable_stack_probing = true;
@@ -449,10 +445,12 @@ pub fn build(b: *Build) !void {
.root_source_file = FileSource.relative(test_file orelse "src/main.zig"),
.target = target,
});
headers_obj.setFilter(test_filter);
headers_obj.filter = test_filter;
if (test_bin_) |test_bin| {
headers_obj.name = std.fs.path.basename(test_bin);
if (std.fs.path.dirname(test_bin)) |dir| headers_obj.setOutputDir(dir);
if (std.fs.path.dirname(test_bin)) |dir| headers_obj.emit_bin = .{
.emit_to = b.fmt("{s}/{s}", .{ dir, headers_obj.name }),
};
}
try configureObjectStep(b, headers_obj, @TypeOf(target), target, obj.main_pkg_path.?);
@@ -489,8 +487,6 @@ pub fn build(b: *Build) !void {
// headers_step.dependOn(&after.step);
// }
}
if (obj.emit_bin != .no_emit)
obj.setOutputDir(output_dir);
b.default_step.dependOn(obj_step);
}
@@ -568,9 +564,12 @@ pub fn configureObjectStep(b: *std.build.Builder, obj: *CompileStep, comptime Ta
obj.strip = false;
obj.setOutputDir(output_dir);
// obj.setBuildMode(optimize);
obj.bundle_compiler_rt = false;
if (obj.emit_bin == .default)
obj.emit_bin = .{
.emit_to = b.fmt("{s}/{s}.o", .{ output_dir, obj.name }),
};
if (target.getOsTag() != .freestanding) obj.linkLibC();
if (target.getOsTag() != .freestanding) obj.bundle_compiler_rt = false;

BIN
bun.lockb

Binary file not shown.

View File

@@ -119,7 +119,7 @@ _bun_completions() {
--jsx-runtime)
COMPREPLY=( $(compgen -W "automatic classic" -- "${cur_word}") );
return;;
--platform)
--target)
COMPREPLY=( $(compgen -W "browser node bun" -- "${cur_word}") );
return;;
-l|--loader)

View File

@@ -1,5 +1,7 @@
Use the built-in `bun:ffi` module to efficiently call native libraries from JavaScript. It works with languages that support the C ABI (Zig, Rust, C/C++, C#, Nim, Kotlin, etc).
## Usage (`bun:ffi`)
To print the version number of `sqlite3`:
```ts
@@ -227,11 +229,7 @@ const lib = linkSymbols({
},
});
const [major, minor, patch] = [
lib.symbols.getMajor(),
lib.symbols.getMinor(),
lib.symbols.getPatch(),
];
const [major, minor, patch] = [lib.symbols.getMajor(), lib.symbols.getMinor(), lib.symbols.getPatch()];
```
## Callbacks
@@ -251,13 +249,10 @@ const {
},
});
const searchIterator = new JSCallback(
(ptr, length) => /hello/.test(new CString(ptr, length)),
{
returns: "bool",
args: ["ptr", "usize"],
},
);
const searchIterator = new JSCallback((ptr, length) => /hello/.test(new CString(ptr, length)), {
returns: "bool",
args: ["ptr", "usize"],
});
const str = Buffer.from("wwutwutwutwutwutwutwutwutwutwutut\0", "utf8");
if (search(ptr(str), searchIterator)) {
@@ -278,7 +273,7 @@ When you're done with a JSCallback, you should call `close()` to free the memory
**⚡️ Performance tip** — For a slight performance boost, directly pass `JSCallback.prototype.ptr` instead of the `JSCallback` object:
```ts
const onResolve = new JSCallback((arg) => arg === 42, {
const onResolve = new JSCallback(arg => arg === 42, {
returns: "bool",
args: ["i32"],
});

View File

@@ -1,10 +1,14 @@
{% callout %}
**Note** — The `Bun.file` and `Bun.write` APIs documented on this page are heavily optimized and represent the recommended way to perform file-system tasks using Bun. Existing Node.js projects may use Bun's [nearly complete](/docs/ecosystem/nodejs#node_fs) implementation of the [`node:fs`](https://nodejs.org/api/fs.html) module.
<!-- **Note** — The `Bun.file` and `Bun.write` APIs documented on this page are heavily optimized and represent the recommended way to perform file-system tasks using Bun. Existing Node.js projects may use Bun's [nearly complete](/docs/runtime/nodejs-apis#node_fs) implementation of the [`node:fs`](https://nodejs.org/api/fs.html) module. -->
**Note** — The `Bun.file` and `Bun.write` APIs documented on this page are heavily optimized and represent the recommended way to perform file-system tasks using Bun. For operations that are not yet available with `Bun.file`, such as `mkdir`, you can use Bun's [nearly complete](/docs/runtime/nodejs-apis#node_fs) implementation of the [`node:fs`](https://nodejs.org/api/fs.html) module.
{% /callout %}
Bun provides a set of optimized APIs for reading and writing files.
## Reading files
## Reading files (`Bun.file()`)
`Bun.file(path): BunFile`
@@ -56,7 +60,7 @@ Bun.stdout;
Bun.stderr;
```
## Writing files
## Writing files (`Bun.write()`)
`Bun.write(destination, data): Promise<number>`
@@ -233,7 +237,7 @@ interface Bun {
file(path: string | number | URL, options?: { type?: string }): BunFile;
write(
destination: string | number | FileBlob | URL,
destination: string | number | BunFile | URL,
input: string | Blob | ArrayBuffer | SharedArrayBuffer | TypedArray | Response,
): Promise<number>;
}

View File

@@ -34,7 +34,7 @@ Bun implements the following globals.
- [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer)
- Node.js
- See [Node.js > `Buffer`](/docs/ecosystem/nodejs#node_buffer)
- See [Node.js > `Buffer`](/docs/runtime/nodejs-apis#node_buffer)
---
@@ -172,7 +172,7 @@ Bun implements the following globals.
- [`global`](https://nodejs.org/api/globals.html#global)
- Node.js
- See [Node.js > `global`](/docs/ecosystem/nodejs#node_global).
- See [Node.js > `global`](/docs/runtime/nodejs-apis#node_global).
---
@@ -214,7 +214,7 @@ Bun implements the following globals.
- [`process`](https://nodejs.org/api/process.html)
- Node.js
- See [Node.js > `process`](/docs/ecosystem/nodejs#node_process)
- See [Node.js > `process`](/docs/runtime/nodejs-apis#node_process)
---

View File

@@ -1,8 +1,8 @@
{% callout %}
**Note** — This page documents the `Bun.serve` API. This API is heavily optimized and represents the recommended way to build HTTP servers in Bun. Existing Node.js projects may use Bun's [nearly complete](/docs/ecosystem/nodejs#node_http) implementation of the Node.js [`http`](https://nodejs.org/api/http.html) and [`https`](https://nodejs.org/api/https.html) modules.
**Note** — This page documents the `Bun.serve` API. This API is heavily optimized and represents the recommended way to build HTTP servers in Bun. Existing Node.js projects may use Bun's [nearly complete](/docs/runtime/nodejs-apis#node_http) implementation of the Node.js [`http`](https://nodejs.org/api/http.html) and [`https`](https://nodejs.org/api/https.html) modules.
{% /callout %}
## Send a request
## Send a request (`fetch()`)
Bun implements the Web `fetch` API for making HTTP requests. The `fetch` function is available in the global scope.
@@ -13,7 +13,7 @@ console.log(result.icons[0].src);
// => "/logo-square.jpg"
```
## Start a server
## Start a server (`Bun.serve()`)
Start an HTTP server in Bun with `Bun.serve`.

View File

@@ -1,6 +1,6 @@
Spawn child processes with `Bun.spawn` or `Bun.spawnSync`.
## Spawn a process
## Spawn a process (`Bun.spawn()`)
Provide a command as an array of strings. The result of `Bun.spawn()` is a `Bun.Subprocess` object.
@@ -28,9 +28,7 @@ By default, the input stream of the subprocess is undefined; it can be configure
```ts
const proc = Bun.spawn(["cat"], {
stdin: await fetch(
"https://raw.githubusercontent.com/oven-sh/bun/main/examples/hashing.js",
),
stdin: await fetch("https://raw.githubusercontent.com/oven-sh/bun/main/examples/hashing.js"),
});
const text = await new Response(proc.stdout).text();
@@ -89,17 +87,17 @@ const proc = Bun.spawn(["cat"], {
});
// enqueue string data
proc.stdin!.write("hello");
proc.stdin.write("hello");
// enqueue binary data
const enc = new TextEncoder();
proc.stdin!.write(enc.encode(" world!"));
proc.stdin.write(enc.encode(" world!"));
// send buffered data
proc.stdin!.flush();
proc.stdin.flush();
// close the input stream
proc.stdin!.end();
proc.stdin.end();
```
## Output streams
@@ -183,7 +181,7 @@ const proc = Bun.spawn(["echo", "hello"]);
proc.unref();
```
## Blocking API
## Blocking API (`Bun.spawnSync()`)
Bun provides a synchronous equivalent of `Bun.spawn` called `Bun.spawnSync`. This is a blocking API that supports the same inputs and parameters as `Bun.spawn`. It returns a `SyncSubprocess` object, which differs from `Subprocess` in a few ways.
@@ -194,7 +192,7 @@ Bun provides a synchronous equivalent of `Bun.spawn` called `Bun.spawnSync`. Thi
```ts
const proc = Bun.spawnSync(["echo", "hello"]);
console.log(proc.stdout!.toString());
console.log(proc.stdout.toString());
// => "hello\n"
```
@@ -227,55 +225,58 @@ spawnSync echo hi 1.47 ms/iter (1.14 ms … 2.64 ms) 1.57 ms 2.37 ms
## Reference
A simple reference of the Spawn API and types are shown below. The real types have complex generics to strongly type the `Subprocess` streams with the options passed to `Bun.spawn` and `Bun.spawnSync`. For full details, find these types as defined [bun.d.ts](https://github.com/oven-sh/bun/blob/main/packages/bun-types/bun.d.ts).
```ts
interface Bun {
spawn(command: string[], options?: SpawnOptions): Subprocess;
spawnSync(command: string[], options?: SpawnOptions): SyncSubprocess;
spawn(command: string[], options?: SpawnOptions.OptionsObject): Subprocess;
spawnSync(command: string[], options?: SpawnOptions.OptionsObject): SyncSubprocess;
spawn(options: { cmd: string[] } & SpawnOptions.OptionsObject): Subprocess;
spawnSync(options: { cmd: string[] } & SpawnOptions.OptionsObject): SyncSubprocess;
}
interface SpawnOptions {
cwd?: string;
env?: Record<string, string>;
stdin?:
namespace SpawnOptions {
interface OptionsObject {
cwd?: string;
env?: Record<string, string>;
stdin?: SpawnOptions.Readable;
stdout?: SpawnOptions.Writable;
stderr?: SpawnOptions.Writable;
onExit?: (proc: Subprocess, exitCode: number | null, signalCode: string | null, error: Error | null) => void;
}
type Readable =
| "pipe"
| "inherit"
| "ignore"
| ReadableStream
| null // equivalent to "ignore"
| undefined // to use default
| BunFile
| ArrayBufferView
| number;
type Writable =
| "pipe"
| "inherit"
| "ignore"
| null // equivalent to "ignore"
| undefined // to use default
| BunFile
| ArrayBufferView
| number
| ReadableStream
| Blob
| Response
| Request
| number
| null;
stdout?:
| "pipe"
| "inherit"
| "ignore"
| BunFile
| TypedArray
| DataView
| null;
stderr?:
| "pipe"
| "inherit"
| "ignore"
| BunFile
| TypedArray
| DataView
| null;
onExit?: (
proc: Subprocess,
exitCode: number | null,
signalCode: string | null,
error: Error | null,
) => void;
| Request;
}
interface Subprocess {
interface Subprocess<Stdin, Stdout, Stderr> {
readonly pid: number;
readonly stdin?: number | ReadableStream | FileSink;
readonly stdout?: number | ReadableStream;
readonly stderr?: number | ReadableStream;
// the exact stream types here are derived from the generic parameters
readonly stdin: number | ReadableStream | FileSink | undefined;
readonly stdout: number | ReadableStream | undefined;
readonly stderr: number | ReadableStream | undefined;
readonly exited: Promise<number>;
@@ -288,13 +289,22 @@ interface Subprocess {
kill(code?: number): void;
}
interface SyncSubprocess {
interface SyncSubprocess<Stdout, Stderr> {
readonly pid: number;
readonly success: boolean;
readonly stdout: Buffer;
readonly stderr: Buffer;
// the exact buffer types here are derived from the generic parameters
readonly stdout: Buffer | undefined;
readonly stderr: Buffer | undefined;
}
type ReadableSubprocess = Subprocess<any, "pipe", "pipe">;
type WritableSubprocess = Subprocess<"pipe", any, any>;
type PipedSubprocess = Subprocess<"pipe", "pipe", "pipe">;
type NullSubprocess = Subprocess<null, null, null>;
type ReadableSyncSubprocess = SyncSubprocess<"pipe", "pipe">;
type NullSyncSubprocess = SyncSubprocess<null, null>;
type Signal =
| "SIGABRT"
| "SIGALRM"

View File

@@ -1,6 +1,6 @@
Use Bun's native TCP API implement performance sensitive systems like database clients, game servers, or anything that needs to communicate over TCP (instead of HTTP). This is a low-level API intended for library authors and for advanced use cases.
Use Bun's native TCP API to implement performance sensitive systems like database clients, game servers, or anything that needs to communicate over TCP (instead of HTTP). This is a low-level API intended for library authors and for advanced use cases.
## Start a server
## Start a server (`Bun.listen()`)
To start a TCP server with `Bun.listen`:
@@ -90,7 +90,7 @@ server.stop(true);
server.unref();
```
## Create a connection
## Create a connection (`Bun.connect()`)
Use `Bun.connect` to connect to a TCP server. Specify the server to connect to with `hostname` and `port`. TCP clients can define the same set of handlers as `Bun.listen`, plus a couple client-specific handlers.
@@ -136,7 +136,7 @@ const server = Bun.listen({ /* config */ })
// reloads handlers for all active server-side sockets
server.reload({
socket:
socket: {
data(){
// new 'data' handler
}

View File

@@ -195,7 +195,7 @@ interface TranspilerOptions {
// Default platform to target
// This affects how import and/or require is used
platform?: "browser" | "bun" | "macro" | "node",
target?: "browser" | "bun" | "node",
// Specify a tsconfig.json file as stringified JSON or an object
// Use this to set a custom JSX factory, fragment, or import source

View File

@@ -94,9 +94,7 @@ test("peek", () => {
// If we peek a rejected promise, it:
// - returns the error
// - does not mark the promise as handled
const rejected = Promise.reject(
new Error("Successfully tested promise rejection"),
);
const rejected = Promise.reject(new Error("Successfully tested promise rejection"));
expect(peek(rejected).message).toBe("Successfully tested promise rejection");
});
```
@@ -128,7 +126,7 @@ const currentFile = import.meta.url;
Bun.openInEditor(currentFile);
```
You can override this via the `debug.editor` setting in your [`bunfig.toml`](/docs/project/configuration)
You can override this via the `debug.editor` setting in your [`bunfig.toml`](/docs/runtime/configuration)
```toml-diff#bunfig.toml
+ [debug]
@@ -142,5 +140,5 @@ Bun.openInEditor(import.meta.url, {
editor: "vscode", // or "subl"
line: 10,
column: 5,
})
});
```

View File

@@ -12,7 +12,7 @@
Internally Bun's WebSocket implementation is built on [uWebSockets](https://github.com/uNetworking/uWebSockets).
{% /callout %}
## Create a client
## Connect to a WebSocket server
To connect to an external socket server, create an instance of `WebSocket` with the constructor.
@@ -46,7 +46,7 @@ socket.addEventListener("close", event => {});
socket.addEventListener("error", event => {});
```
## Create a server
## Create a WebSocket server
Below is a simple WebSocket server built with `Bun.serve`, in which all incoming requests are [upgraded](https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism) to WebSocket connections in the `fetch` handler. The socket handlers are declared in the `websocket` parameter.

75
docs/bundler/intro.md Normal file
View File

@@ -0,0 +1,75 @@
<!-- This document is a work in progress. It's not currently included in the actual docs. -->
The goal of this document is to break down why bundling is necessary, how it works, and how the bundler became such a key part of modern JavaScript development. The content is not specific to Bun's bundler, but is rather aimed at anyone looking for a greater understanding of how bundlers work and, by extension, how most modern frameworks are implemented.
## What is bundling
With the adoption of ECMAScript modules (ESM), browsers can now resolve `import`/`export` statements in JavaScript files loaded via `<script>` tags.
{% codetabs %}
```html#index.html
<html>
<head>
<script type="module" src="/index.js" ></script>
</head>
</html>
```
```js#index.js
import {sayHello} from "./hello.js";
sayHello();
```
```js#hello.js
export function sayHello() {
console.log("Hello, world!");
}
```
{% /codetabs %}
When a user visits this website, the files are loaded in the following order:
{% image src="/images/module_loading_unbundled.png" /%}
{% callout %}
**Relative imports** — Relative imports are resolved relative to the URL of the importing file. Because we're importing `./hello.js` from `/index.js`, the browser resolves it to `/hello.js`. If instead we'd imported `./hello.js` from `/src/index.js`, the browser would have resolved it to `/src/hello.js`.
{% /callout %}
This approach works, it requires three round-trip HTTP requests before the browser is ready to render the page. On slow internet connections, this may add up to a non-trivial delay.
This example is extremely simplistic. A modern app may be loading dozens of modules from `node_modules`, each consisting of hundrends of files. Loading each of these files with a separate HTTP request becomes untenable very quickly. While most of these requests will be running in parallel, the number of round-trip requests can still be very high; plus, there are limits on how many simultaneous requests a browser can make.
{% callout %}
Some recent advances like modulepreload and HTTP/3 are intended to solve some of these problems, but at the moment bundling is still the most performant approach.
{% /callout %}
The answer: bundling.
## Entrypoints
A bundler accepts an "entrypoint" to your source code (in this case, `/index.js`) and outputs a single file containing all of the code needed to run your app. If does so by parsing your source code, reading the `import`/`export` statements, and building a "module graph" of your app's dependencies.
{% image src="/images/bundling.png" /%}
We can now load `/bundle.js` from our `index.html` file and eliminate a round trip request, decreasing load times for our app.
{% image src="/images/module_loading_bundled.png" /%}
## Loaders
Bundlers typically have some set of built-in "loaders".
## Transpilation
The JavaScript files above are just that: plain JavaScript. They can be directly executed by any modern browser.
But modern tooling goes far beyond HTML, JavaScript, and CSS. JSX, TypeScript, and PostCSS/CSS-in-JS are all popular technologies that involve non-standard syntax that must be converted into vanilla JavaScript and CSS before if can be consumed by a browser.
## Chunking
## Module resolution
## Plugins

234
docs/bundler/loaders.md Normal file
View File

@@ -0,0 +1,234 @@
The Bun bundler implements a set of default loaders out of the box. As a rule of thumb, the bundler and the runtime both support the same set of file types out of the box.
`.js` `.cjs` `.mjs` `.mts` `.cts` `.ts` `.tsx` `.jsx` `.toml` `.json` `.txt` `.wasm` `.node`
Bun uses the file extension to determine which built-in _loader_ should be used to parse the file. Every loader has a name, such as `js`, `tsx`, or `json`. These names are used when building [plugins](/docs/bundler/plugins) that extend Bun with custom loaders.
## Built-in loaders
### `js`
**JavaScript**. Default for `.cjs` and `.mjs`.
Parses the code and applies a set if default transforms, like dead-code elimination, tree shaking, and environment variable inlining. Note that Bun does not attempt to down-convert syntax at the moment.
### `jsx`
**JavaScript + JSX.**. Default for `.js` and `.jsx`.
Same as the `js` loader, but JSX syntax is supported. By default, JSX is downconverted to plain JavaScript; the details of how this is done depends on the `jsx*` compiler options in your `tsconfig.json`. Refer to the TypeScript documentation [on JSX](https://www.typescriptlang.org/docs/handbook/jsx.html) for more information.
### `ts`
**TypeScript loader**. Default for `.ts`, `.mts`, and `.cts`.
Strips out all TypeScript syntax, then behaves identically to the `js` loader. Bun does not perform typechecking.
### `tsx`
**TypeScript + JSX loader**. Default for `.tsx`. Transpiles both TypeScript and JSX to vanilla JavaScript.
### `json`
**JSON loader**. Default for `.json`.
JSON files can be directly imported.
```ts
import pkg from "./package.json";
pkg.name; // => "my-package"
```
During bundling, the parsed JSON is inlined into the bundle as a JavaScript object.
```ts
var pkg = {
name: "my-package",
// ... other fields
};
pkg.name;
```
If a `.json` file is passed as an entrypoint to the bundler, it will be converted to a `.js` module that `export default`s the parsed object.
{% codetabs %}
```json#Input
{
"name": "John Doe",
"age": 35,
"email": "johndoe@example.com"
}
```
```js#Output
export default {
name: "John Doe",
age: 35,
email: "johndoe@example.com"
}
```
{% /codetabs %}
### `toml`
**TOML loader**. Default for `.toml`.
TOML files can be directly imported. Bun will parse them with its fast native TOML parser.
```ts
import config from "./bunfig.toml";
config.logLevel; // => "debug"
```
During bundling, the parsed TOML is inlined into the bundle as a JavaScript object.
```ts
var config = {
logLevel: "debug",
// ...other fields
};
config.logLevel;
```
If a `.toml` file is passed as an entrypoint, it will be converted to a `.js` module that `export default`s the parsed object.
{% codetabs %}
```toml#Input
name = "John Doe"
age = 35
email = "johndoe@example.com"
```
```js#Output
export default {
name: "John Doe",
age: 35,
email: "johndoe@example.com"
}
```
{% /codetabs %}
### `text`
**Text loader**. Default for `.txt`.
The contents of the text file are read and inlined into the bundle as a string.
Text files can be directly imported. The file is read and returned as a string.
```ts
import contents from "./file.txt";
console.log(contents); // => "Hello, world!"
```
When referenced during a build, the contents are into the bundle as a string.
```ts
var contents = `Hello, world!`;
console.log(contents);
```
If a `.txt` file is passed as an entrypoint, it will be converted to a `.js` module that `export default`s the file contents.
{% codetabs %}
```txt#Input
Hello, world!
```
```js#Output
export default "Hello, world!";
```
{% /codetabs %}
### `wasm`
**WebAssembly loader**. Default for `.wasm`.
In the runtime, WebAssembly files can be directly imported. The file is read and returned as a `WebAssembly.Module`.
```ts
import wasm from "./module.wasm";
console.log(wasm); // => WebAssembly.Module
```
In the bundler, `.wasm` files are handled using the [`file`](#file) loader.
### `napi`
**Native addon loader**. Default for `.node`.
In the runtime, native addons can be directly imported.
```ts
import addon from "./addon.node";
console.log(addon);
```
In the bundler, `.node` files are handled using the [`file`](#file) loader.
### `file`
**File loader**. Default for all unrecognized file types.
The file loader resolves the import as a _path/URL_ to the imported file. It's commonly used for referencing media or font assets.
```ts#logo.ts
import logo from "./logo.svg";
console.log(logo);
```
_In the runtime_, Bun checks that the `logo.svg` file exists and converts it to an absolute path to the location of `logo.svg` on disk.
```bash
$ bun run logo.ts
/path/to/project/logo.svg
```
_In the bundler_, things are slightly different. The file is copied into `outdir` as-is, and the import is resolved as a relative path pointing to the copied file.
```ts#Output
var logo = "./logo.svg";
console.log(logo);
```
If a value is specified for `publicPath`, the import will use value as a prefix to construct an absolute path/URL.
{% table %}
- Public path
- Resolved import
---
- `""` (default)
- `/logo.svg`
---
- `"/assets"`
- `/assets/logo.svg`
---
- `"https://cdn.example.com/"`
- `https://cdn.example.com/`
{% /table %}
{% callout %}
The location and file name of the copied file is determined by the value of [`naming.asset`](/docs/cli/build#naming).
{% callout %}
This loader is copied into the `outdir` as-is. The name of the copied file is determined using the value of `naming.asset`.
{% details summary="Fixing TypeScript import errors" %}
If you're using TypeScript, you may get an error like this:
```ts
// TypeScript error
// Cannot find module './logo.svg' or its corresponding type declarations.
```

View File

@@ -2,30 +2,55 @@
**Note** — Introduced in Bun v0.1.11.
{% /callout %}
Bun's runtime can be extended to support additional file types using _plugins_. Plugins can intercept imports and perform custom loading logic: reading files, transpiling code, etc. They can be used to extend Bun's runtime with _loaders_ for additional file types.
Bun provides a universal plugin API that can be used to extend both the _runtime_ and _bundler_.
Plugins intercept imports and perform custom loading logic: reading files, transpiling code, etc. They can be used to add support for additional file types, like `.scss` or `.yaml`. In the context of Bun's bundler, plugins can be used to implement framework-level features like CSS extraction, macros, and client-server code co-location.
## Usage
A plugin is defined as simple JavaScript object containing a `name` property and a `setup` function. Register a plugin with Bun using the `plugin` function.
```tsx#yamlPlugin.ts
import { plugin } from "bun";
import type { BunPlugin } from "bun";
plugin({
const myPlugin: BunPlugin = {
name: "YAML loader",
setup(build) {
// implementation
},
};
```
This plugin can be passed into the `plugins` array when calling `Bun.build`.
```ts
Bun.build({
entrypoints: ["./app.ts"],
outdir: "./out",
plugins: [myPlugin],
});
```
To consume this plugin, add this file to the `preload` option in your [`bunfig.toml`](/docs/project/configuration). Bun automatically loads the files/modules specified in `preload` before running a file.
It can also be "registered" with the Bun runtime using the `Bun.plugin()` function. Once registered, the currently executing `bun` process will incorporate the plugin into its module resolution algorithm.
```ts
Bun.plugin(myPlugin);
```
To consume this plugin, add this file to the `preload` option in your [`bunfig.toml`](/docs/runtime/configuration). Bun automatically loads the files/modules specified in `preload` before running a file.
```toml
preload = ["./yamlPlugin.ts"]
```
{% details summary="Usage without preload" %}
To preload files during `bun test`:
```toml
[test]
preload = ["./loader.ts"]
```
{% details summary="Usage without preload" %}
Alternatively, you can import this file manually at the top of your project's entrypoint, before any application code is imported.
@@ -243,15 +268,24 @@ namespace Bun {
}
type PluginBuilder = {
onResolve: (
args: { filter: RegExp; namespace?: string },
callback: (args: { path: string; importer: string }) => {
path: string;
namespace?: string;
} | void,
) => void;
onLoad: (
args: { filter: RegExp; namespace?: string },
callback: (args: { path: string }) => {
loader?: "js" | "jsx" | "ts" | "tsx" | "json" | "toml" | "object";
loader?: Loader;
contents?: string;
exports?: Record<string, any>;
},
) => void;
};
type Loader = "js" | "jsx" | "ts" | "tsx" | "json" | "toml" | "object";
```
The `onLoad` method optionally accepts a `namespace` in addition to the `filter` regex. This namespace will be be used to prefix the import in transpiled code; for instance, a loader with a `filter: /\.yaml$/` and `namespace: "yaml:"` will transform an import from `./myfile.yaml` into `yaml:./myfile.yaml`.

1002
docs/cli/build.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,8 @@
Use `bunx` to auto-install and run packages from `npm`. The `bunx` CLI will be auto-installed when you install `bun`.
{% callout %}
**Note**`bunx` is an alias for `bun x`. The `bunx` CLI will be auto-installed when you install `bun`.
{% /callout %}
Use `bunx` to auto-install and run packages from `npm`. It's Bun's equivalent of `npx` or `yarn dlx`.
```bash
$ bunx cowsay "Hello world!"
@@ -46,23 +50,20 @@ $ bunx my-cli --foo bar
## Shebangs
By default, Bun respects shebangs. If an executable is marked with `#!/usr/bin/env node`, Bun will spin up a `node` process to execute the file. However, in some cases it may be desirable to run executables using [Bun's runtime](/docs/runtime), even if the executable indicates otherwise. To do so, include the `--bun` flag.
By default, Bun respects shebangs. If an executable is marked with `#!/usr/bin/env node`, Bun will spin up a `node` process to execute the file. However, in some cases it may be desirable to run executables using Bun's runtime, even if the executable indicates otherwise. To do so, include the `--bun` flag.
```bash
$ bunx --bun my-cli
```
{% callout %}
**Note** — The `--bun` flag must occur _before_ the executable name. Flags that appear _after_ the name are passed through to the executable.
The `--bun` flag must occur _before_ the executable name. Flags that appear _after_ the name are passed through to the executable.
```bash
$ bunx --bun my-cli # good
$ bunx my-cli --bun # bad
```
{% /callout %}
## Environment variables
<!-- ## Environment variables
Bun automatically loads environment variables from `.env` files before running a file, script, or executable. The following files are checked, in order:
@@ -70,4 +71,4 @@ Bun automatically loads environment variables from `.env` files before running a
2. `NODE_ENV` === `"production"` ? `.env.production` : `.env.development`
3. `.env`
To debug environment variables, run `bun run env` to view a list of resolved environment variables.
To debug environment variables, run `bun run env` to view a list of resolved environment variables. -->

View File

@@ -1,3 +1,29 @@
## `bun init`
Scaffold an empty project with `bun init`. It's an interactive tool.
```bash
$ bun init
bun init helps you get started with a minimal project and tries to
guess sensible defaults. Press ^C anytime to quit.
package name (quickstart):
entry point (index.ts):
Done! A package.json file was saved in the current directory.
+ index.ts
+ .gitignore
+ tsconfig.json (for editor auto-complete)
+ README.md
To get started, run:
bun run index.ts
```
Press `enter` to accept the default answer for each prompt, or pass the `-y` flag to auto-accept the defaults.
## `bun create`
Template a new Bun project with `bun create`.
```bash

View File

@@ -1,8 +1,8 @@
The `bun` CLI contains an `npm`-compatible package manager designed to be a faster replacement for existing package management tools like `npm`, `yarn`, and `pnpm`. It's designed for Node.js compatibility; use it in any Bun or Node.js project.
The `bun` CLI contains a Node.js-compatible package manager designed to be a dramatically faster replacement for `npm`, `yarn`, and `pnpm`. It's a standalone tool that will work in pre-existing Node.js projects; if your project has a `package.json`, `bun install` can help you speed up your workflow.
{% callout %}
**⚡️ 80x faster** — Switch from `npm install` to `bun install` in any Node.js project to make your installations up to 80x faster.
**⚡️ 25x faster** — Switch from `npm install` to `bun install` in any Node.js project to make your installations up to 25x faster.
{% image src="https://user-images.githubusercontent.com/709451/147004342-571b6123-17a9-49a2-8bfd-dcfc5204047e.png" height="200" /%}
@@ -23,7 +23,9 @@ sudo apt install --install-recommends linux-generic-hwe-20.04
{% /details %}
## Install dependencies
## Manage dependencies
### `bun install`
To install all dependencies of a project:
@@ -84,13 +86,12 @@ dryRun = false
{% /details %}
## Add and remove packages
### `bun add`
To add or remove a particular package:
To add a particular package:
```bash
$ bun add preact
$ bun remove preact
```
To specify a version, version range, or tag:
@@ -147,222 +148,15 @@ To view a complete list of options for a given command:
$ bun add --help
```
## Git dependencies
### `bun remove`
To add a dependency from a git repository:
To remove a dependency:
```bash
$ bun install git@github.com:moment/moment.git
$ bun remove preact
```
Bun supports a variety of protocols, including [`github`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#github-urls), [`git`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#git-urls-as-dependencies), `git+ssh`, `git+https`, and many more.
```json
{
"dependencies": {
"dayjs": "git+https://github.com/iamkun/dayjs.git",
"lodash": "git+ssh://github.com/lodash/lodash.git#4.17.21",
"moment": "git@github.com:moment/moment.git",
"zod": "github:colinhacks/zod"
}
}
```
## Global cache
All packages downloaded from the registry are stored in a global cache at `~/.bun/install/cache`. They are stored in subdirectories named like `${name}@${version}`, so multiple versions of a package can be cached.
{% details summary="Configuring cache behavior" %}
```toml
[install.cache]
# the directory to use for the cache
dir = "~/.bun/install/cache"
# when true, don't load from the global cache.
# Bun may still write to node_modules/.cache
disable = false
# when true, always resolve the latest versions from the registry
disableManifest = false
```
{% /details %}
### Minimizing re-downloads
Bun strives to avoid re-downloading packages mutiple times. When installing a package, if the cache already contains a version in the range specified by `package.json`, Bun will use the cached package instead of downloading it again.
{% details summary="Installation details" %}
If the semver version has pre-release suffix (`1.0.0-beta.0`) or a build suffix (`1.0.0+20220101`), it is replaced with a hash of that value instead, to reduce the chances of errors associated with long file paths.
When the `node_modules` folder exists, before installing, Bun checks that `node_modules` contains all expected packages with appropriate versions. If so `bun install` completes. Bun uses a custom JSON parser which stops parsing as soon as it finds `"name"` and `"version"`.
If a package is missing or has a version incompatible with the `package.json`, Bun checks for a compatible module in the cache. If found, it is installed into `node_modules`. Otherwise, the package will be downloaded from the registry then installed.
{% /details %}
### Fast copying
Once a package is downloaded into the cache, Bun still needs to copy those files into `node_modules`. Bun uses the fastest syscalls available to perform this task. On Linux, it uses hardlinks; on macOS, it uses `clonefile`.
### Saving disk space
Since Bun uses hardlinks to "copy" a module into a project's `node_modules` directory on Linux, the contents of the package only exist in a single location on disk, greatly reducing the amount of disk space dedicated to `node_modules`.
This benefit does not extend to macOS, which uses `clonefile` for performance reasons.
{% details summary="Installation strategies" %}
This behavior is configurable with the `--backend` flag, which is respected by all of Bun's package management commands.
- **`hardlink`**: Default on Linux.
- **`clonefile`** Default on macOS.
- **`clonefile_each_dir`**: Similar to `clonefile`, except it clones each file individually per directory. It is only available on macOS and tends to perform slower than `clonefile`.
- **`copyfile`**: The fallback used when any of the above fail. It is the slowest option. On macOS, it uses `fcopyfile()`; on Linux it uses `copy_file_range()`.
**`symlink`**: Currently used only `file:` (and eventually `link:`) dependencies. To prevent infinite loops, it skips symlinking the `node_modules` folder.
If you install with `--backend=symlink`, Node.js won't resolve node_modules of dependencies unless each dependency has its own `node_modules` folder or you pass `--preserve-symlinks` to `node`. See [Node.js documentation on `--preserve-symlinks`](https://nodejs.org/api/cli.html#--preserve-symlinks).
```bash
$ bun install --backend symlink
$ node --preserve-symlinks ./foo.js
```
Bun's runtime does not currently expose an equivalent of `--preserve-symlinks`.
{% /details %}
## Lockfile
Running `bun install` will create a binary lockfile called `bun.lockb`.
#### Why is it binary?
In a word: Performance. Buns lockfile saves & loads incredibly quickly, and saves a lot more data than what is typically inside lockfiles.
#### How do I inspect it?
Run `bun install -y` to generate a Yarn-compatible `yarn.lock` (v1) that can be inspected more easily.
#### Platform-specific dependencies?
Bun stores normalized `cpu` and `os` values from npm in the lockfile, along with the resolved packages. It skips downloading, extracting, and installing packages disabled for the current target at runtime. This means the lockfile wont change between platforms/architectures even if the packages ultimately installed do change.
#### What does the lockfile store?
Packages, metadata for those packages, the hoisted install order, dependencies for each package, what packages those dependencies resolved to, an integrity hash (if available), what each package was resolved to, and which version (or equivalent).
#### Why is it fast?
It uses linear arrays for all data. [Packages](https://github.com/oven-sh/bun/blob/be03fc273a487ac402f19ad897778d74b6d72963/src/install/install.zig#L1825) are referenced by an auto-incrementing integer ID or a hash of the package name. Strings longer than 8 characters are de-duplicated. Prior to saving on disk, the lockfile is garbage-collected & made deterministic by walking the package tree and cloning the packages in dependency order.
#### Can I opt out?
To install without creating a lockfile:
```bash
$ bun install --no-save
```
To install a Yarn lockfile _in addition_ to `bun.lockb`.
{% codetabs %}
```bash#CLI flag
$ bun install --yarn
```
```toml#bunfig.toml
[install.lockfile]
# whether to save a non-Bun lockfile alongside bun.lockb
# only "yarn" is supported
print = "yarn"
```
{% /codetabs %}
{% details summary="Configuring lockfile" %}
```toml
[install.lockfile]
# path to read bun.lockb from
path = "bun.lockb"
# path to save bun.lockb to
savePath = "bun.lockb"
# whether to save the lockfile to disk
save = true
# whether to save a non-Bun lockfile alongside bun.lockb
# only "yarn" is supported
print = "yarn"
```
{% /details %}
## Workspaces
Bun supports [`workspaces`](https://docs.npmjs.com/cli/v9/using-npm/workspaces?v=true#description) in `package.json`. Workspaces make it easy to develop complex software as a _monorepo_ consisting of several independent packages.
To try it, specify a list of sub-packages in the `workspaces` field of your `package.json`; it's conventional to place these sub-packages in a directory called `packages`.
```json
{
"name": "my-project",
"version": "1.0.0",
"workspaces": ["packages/*"]
}
```
{% callout %}
**Glob support** — Bun v0.5.8 added support for simple globs for workspace names, with a "*/" at the end. Nothing too fancy.
{% /callout %}
This has a couple major benefits.
- **Code can be split into logical parts.** If one package relies on another, you can simply add it as a dependency with `bun add`. If package `b` depends on `a`, `bun install` will symlink your local `packages/a` directory into the `node_modules` folder of `b`, instead of trying to download it from the npm registry.
- **Dependencies can be de-duplicated.** If `a` and `b` share a common dependency, it will be _hoisted_ to the root `node_modules` directory. This reduces redundant disk usage and minimizes "dependency hell" issues associated with having multiple versions of a package installed simultaneously.
{% callout %}
⚡️ **Speed** — Installs are fast, even for big monorepos. Bun installs the [Remix](https://github.com/remix-run/remix) monorepo in about `500ms` on Linux.
- 28x faster than `npm install`
- 12x faster than `yarn install` (v1)
- 8x faster than `pnpm install`
{% image src="https://user-images.githubusercontent.com/709451/212829600-77df9544-7c9f-4d8d-a984-b2cd0fd2aa52.png" /%}
{% /callout %}
## Registries
The default registry is `registry.npmjs.org`. This can be globally configured in `bunfig.toml`:
```toml
[install]
# set default registry as a string
registry = "https://registry.npmjs.org"
# set a token
registry = { url = "https://registry.npmjs.org", token = "123456" }
# set a username/password
registry = "https://username:password@registry.npmjs.org"
```
To configure a private registry scoped to a particular organization:
```toml
[install.scopes]
# registry as string
"@myorg1" = "https://username:password@registry.myorg.com/"
# registry with username/password
# you can reference environment variables
"@myorg2" = { username = "myusername", password = "$NPM_PASS", url = "https://registry.myorg.com/" }
# registry with token
"@myorg3" = { token = "$npm_token", url = "https://registry.myorg.com/" }
```
## Linking and unlinking
## Local packages (`bun link`)
Use `bun link` in a local directory to register the current package as a "linkable" package.
@@ -403,44 +197,56 @@ This will add `cool-pkg` to the `dependencies` field of your app's package.json
}
```
## Utilities
## Git dependencies
The `bun pm` command group provides a set of utilities for working with Bun's package manager.
To print the path to the `bin` directory for the local project:
To add a dependency from a git repository:
```bash
$ bun pm bin
/path/to/current/project/node_modules/.bin
$ bun install git@github.com:moment/moment.git
```
To get the path to the global `bin` directory:
Bun supports a variety of protocols, including [`github`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#github-urls), [`git`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#git-urls-as-dependencies), `git+ssh`, `git+https`, and many more.
```bash
$ bun pm bin
<$HOME>/.bun/bin
```json
{
"dependencies": {
"dayjs": "git+https://github.com/iamkun/dayjs.git",
"lodash": "git+ssh://github.com/lodash/lodash.git#4.17.21",
"moment": "git@github.com:moment/moment.git",
"zod": "github:colinhacks/zod"
}
}
```
To print a list of packages installed in the current project and their resolved versions, excluding their dependencies. Use the `--all` flag to print the entire tree, including all nth-order dependencies.
## Tarball dependencies
```bash
$ bun pm ls
/path/to/project node_modules (5)
├── eslint@8.33.0
├── react@18.2.0
├── react-dom@18.2.0
├── typescript@4.8.4
└── zod@3.20.1
A package name can correspond to a publically hosted `.tgz` file. During `bun install`, Bun will download and install the package from the specified tarball URL, rather than from the package registry.
```json#package.json
{
"dependencies": {
"zod": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz"
}
}
```
To print the path to Bun's global module cache:
## CI/CD
```bash
$ bun pm cache
```
To clear Bun's global module cache:
```bash
$ bun pm cache rm
Looking to speed up your CI? Use the official `oven-sh/setup-bun` action to install `bun` in a GitHub Actions pipeline.
```yaml#.github/workflows/release.yml
name: bun-types
jobs:
build:
name: build-app
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Install bun
uses: oven-sh/setup-bun@v1
- name: Install dependencies
run: bun install
- name: Build app
run: bun run build
```

View File

@@ -1,31 +1,38 @@
The `bun` CLI can be used to execute JavaScript/TypeScript files, `package.json` scripts, and [executable packages](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#bin).
## Running a file
<!-- ## Speed -->
<!--
Performance sensitive APIs like `Buffer`, `fetch`, and `Response` are heavily profiled and optimized. Under the hood Bun uses the [JavaScriptCore engine](https://developer.apple.com/documentation/javascriptcore), which is developed by Apple for Safari. It starts and runs faster than V8, the engine used by Node.js and Chromium-based browsers. -->
## Run a file
{% callout %}
Compare to `node <file>`
{% /callout %}
Bun can execute `.js`, `.jsx`, `.ts`, and `.tsx` files. Every file is transpiled to vanilla JavaScript by Bun's fast native transpiler before being executed. For details on Bun's runtime, refer to the [Bun runtime](/docs/runtime) documentation.
```ts#foo.ts
import { z } from "zod";
const schema = z.string()
const result = schema.parse("Billie Eilish");
console.log(result);
```
To run a file in Bun:
Use `bun run` to execute a source file.
```bash
$ bun foo.ts
Billie Eilish
$ bun run index.js
```
If no `node_modules` directory is found in the working directory or above, Bun will abandon Node.js-style module resolution in favor of the `Bun module resolution algorithm`. Under Bun-style module resolution, all packages are _auto-installed_ on the fly into a [global module cache](/docs/cli/install#global-cache). For full details on this algorithm, refer to [Runtime > Modules](/docs/runtime/modules).
Bun supports TypeScript and JSX out of the box. Every file is transpiled on the fly by Bun's fast native transpiler before being executed.
## Running a package script
```bash
$ bun run index.js
$ bun run index.jsx
$ bun run index.ts
$ bun run index.tsx
```
The "naked" `bun` command is equivalent to `bun run`.
```bash
$ bun index.tsx
```
## Run a `package.json` script
{% note %}
Compare to `npm run <script>` or `yarn <script>`
@@ -80,3 +87,23 @@ quickstart scripts:
```
Bun respects lifecycle hooks. For instance, `bun run clean` will execute `preclean` and `postclean`, if defined. If the `pre<script>` fails, Bun will not execute the script itself.
## Environment variables
Bun automatically loads environment variables from `.env` files before running a file, script, or executable. The following files are checked, in order:
1. `.env.local` (first)
2. `NODE_ENV` === `"production"` ? `.env.production` : `.env.development`
3. `.env`
To debug environment variables, run `bun run env` to view a list of resolved environment variables.
## Performance
Bun is designed to start fast and run fast.
Under the hood Bun uses the [JavaScriptCore engine](https://developer.apple.com/documentation/javascriptcore), which is developed by Apple for Safari. In most cases, the startup and running performance is faster than V8, the engine used by Node.js and Chromium-based browsers. It's transpiler and runtime are written in Zig, a modern, high-performance language. On Linux, this translates into startup times [4x faster](https://twitter.com/jarredsumner/status/1499225725492076544) than Node.js.
{% image src="/images/bun-run-speed.jpeg" caption="Bun vs Node.js vs Deno running Hello World" /%}
<!-- If no `node_modules` directory is found in the working directory or above, Bun will abandon Node.js-style module resolution in favor of the `Bun module resolution algorithm`. Under Bun-style module resolution, all packages are _auto-installed_ on the fly into a [global module cache](/docs/cli/install#global-cache). For full details on this algorithm, refer to [Runtime > Modules](/docs/runtime/modules). -->

View File

@@ -1,10 +1,12 @@
Bun ships with a built-in test runner.
## Run tests
```bash
$ bun test
```
Tests are written in JavaScript or TypeScript with a Jest-like API.
Tests are written in JavaScript or TypeScript with a Jest-like API. Refer to [Writing tests](/docs/test/writing) for full documentation.
```ts#math.test.ts
import { expect, test } from "bun:test";
@@ -14,10 +16,6 @@ test("2 + 2", () => {
});
```
It's fast.
{% image src="/images/buntest.jpeg" caption="Bun runs 266 React SSR tests faster than Jest can print its version number." /%}
The runner recursively searches the working directory for files that match the following patterns:
- `*.test.{js|jsx|ts|tsx}`
@@ -31,6 +29,40 @@ You can filter the set of tests to run by passing additional positional argument
$ bun test <filter> <filter> ...
```
## Snapshot testing
Snapshots are supported by `bun test`. First, write a test using the `.toMatchSnapshot()` matcher:
```ts
import { test, expect } from "bun:test";
test("snap", () => {
expect("foo").toMatchSnapshot();
});
```
Then generate snapshots with the following command:
```bash
bun test --update-snapshots
```
Snapshots will be stored in a `__snapshots__` directory next to the test file.
## Watch mode
Similar to `bun run`, you can pass the `--watch` flag to `bun test` to watch for changes and re-run tests.
```bash
$ bun test --watch
```
## Performance
Bun's test runner is fast.
{% image src="/images/buntest.jpeg" caption="Running 266 React SSR tests faster than Jest can print its version number." /%}
<!--
Consider the following directory structure:
@@ -57,182 +89,3 @@ $ bun test foo
```
Any test file in the directory with an _absolute path_ that contains one of the targets will run. Glob patterns are not yet supported. -->
## Writing tests
Define tests with a Jest-like API imported from the built-in `bun:test` module.
```ts#math.test.ts
import { expect, test } from "bun:test";
test("2 + 2", () => {
expect(2 + 2).toBe(4);
});
```
Group tests into suites with `describe`.
```ts#math.test.ts
import { expect, test, describe } from "bun:test";
describe("arithmetic", () => {
test("2 + 2", () => {
expect(2 + 2).toBe(4);
});
test("2 * 2", () => {
expect(2 * 2).toBe(4);
});
});
```
Tests can be `async`.
```ts
import { expect, test } from "bun:test";
test("2 * 2", async () => {
const result = await Promise.resolve(2 * 2);
expect(result).toEqual(4);
});
```
Alternatively, use the `done` callback to signal completion. If you include the `done` callback as a parameter in your test definition, you _must_ call it or the test will hang.
```ts
import { expect, test } from "bun:test";
test("2 * 2", done => {
Promise.resolve(2 * 2).then(result => {
expect(result).toEqual(4);
done();
});
});
```
Perform per-test setup and teardown logic with `beforeEach` and `afterEach`.
```ts
import { expect, test } from "bun:test";
beforeEach(() => {
console.log("running test.");
});
afterEach(() => {
console.log("done with test.");
});
// tests...
```
Perform per-scope setup and teardown logic with `beforeAll` and `afterAll`. At the top-level, the _scope_ is the current file; in a `describe` block, the scope is the block itself.
```ts
import { expect, test, beforeAll, afterAll } from "bun:test";
let db: Database;
beforeAll(() => {
// connect to database
});
afterAll(() => {
// close connection
});
// tests...
```
Skip individual tests with `test.skip`.
```ts
import { expect, test } from "bun:test";
test.skip("wat", () => {
// TODO: fix this
expect(0.1 + 0.2).toEqual(0.3);
});
```
## Expect matchers
Bun implements the following matchers. Full Jest compatibility is on the roadmap; track progress [here](https://github.com/oven-sh/bun/issues/1825).
- [x] [`.not`](https://jestjs.io/docs/expect#not)
- [x] [`.toBe()`](https://jestjs.io/docs/expect#tobevalue)
- [x] [`.toEqual()`](https://jestjs.io/docs/expect#toequalvalue)
- [x] [`.toBeNull()`](https://jestjs.io/docs/expect#tobenull)
- [x] [`.toBeUndefined()`](https://jestjs.io/docs/expect#tobeundefined)
- [x] [`.toBeNaN()`](https://jestjs.io/docs/expect#tobenan)
- [x] [`.toBeDefined()`](https://jestjs.io/docs/expect#tobedefined)
- [x] [`.toBeFalsy()`](https://jestjs.io/docs/expect#tobefalsy)
- [x] [`.toBeTruthy()`](https://jestjs.io/docs/expect#tobetruthy)
- [x] [`.toContain()`](https://jestjs.io/docs/expect#tocontainitem)
- [x] [`.toStrictEqual()`](https://jestjs.io/docs/expect#tostrictequalvalue)
- [x] [`.toThrow()`](https://jestjs.io/docs/expect#tothrowerror)
- [x] [`.toHaveLength()`](https://jestjs.io/docs/expect#tohavelengthnumber)
- [x] [`.toHaveProperty()`](https://jestjs.io/docs/expect#tohavepropertykeypath-value)
- [ ] [`.extend`](https://jestjs.io/docs/expect#expectextendmatchers)
- [ ] [`.anything()`](https://jestjs.io/docs/expect#expectanything)
- [ ] [`.any()`](https://jestjs.io/docs/expect#expectanyconstructor)
- [ ] [`.arrayContaining()`](https://jestjs.io/docs/expect#expectarraycontainingarray)
- [ ] [`.assertions()`](https://jestjs.io/docs/expect#expectassertionsnumber)
- [ ] [`.closeTo()`](https://jestjs.io/docs/expect#expectclosetonumber-numdigits)
- [ ] [`.hasAssertions()`](https://jestjs.io/docs/expect#expecthasassertions)
- [ ] [`.objectContaining()`](https://jestjs.io/docs/expect#expectobjectcontainingobject)
- [ ] [`.stringContaining()`](https://jestjs.io/docs/expect#expectstringcontainingstring)
- [ ] [`.stringMatching()`](https://jestjs.io/docs/expect#expectstringmatchingstring--regexp)
- [ ] [`.addSnapshotSerializer()`](https://jestjs.io/docs/expect#expectaddsnapshotserializerserializer)
- [ ] [`.resolves()`](https://jestjs.io/docs/expect#resolves)
- [ ] [`.rejects()`](https://jestjs.io/docs/expect#rejects)
- [ ] [`.toHaveBeenCalled()`](https://jestjs.io/docs/expect#tohavebeencalled)
- [ ] [`.toHaveBeenCalledTimes()`](https://jestjs.io/docs/expect#tohavebeencalledtimesnumber)
- [ ] [`.toHaveBeenCalledWith()`](https://jestjs.io/docs/expect#tohavebeencalledwitharg1-arg2-)
- [ ] [`.toHaveBeenLastCalledWith()`](https://jestjs.io/docs/expect#tohavebeenlastcalledwitharg1-arg2-)
- [ ] [`.toHaveBeenNthCalledWith()`](https://jestjs.io/docs/expect#tohavebeennthcalledwithnthcall-arg1-arg2-)
- [ ] [`.toHaveReturned()`](https://jestjs.io/docs/expect#tohavereturned)
- [ ] [`.toHaveReturnedTimes()`](https://jestjs.io/docs/expect#tohavereturnedtimesnumber)
- [ ] [`.toHaveReturnedWith()`](https://jestjs.io/docs/expect#tohavereturnedwithvalue)
- [ ] [`.toHaveLastReturnedWith()`](https://jestjs.io/docs/expect#tohavelastreturnedwithvalue)
- [ ] [`.toHaveNthReturnedWith()`](https://jestjs.io/docs/expect#tohaventhreturnedwithnthcall-value)
- [ ] [`.toBeCloseTo()`](https://jestjs.io/docs/expect#tobeclosetonumber-numdigits)
- [x] [`.toBeGreaterThan()`](https://jestjs.io/docs/expect#tobegreaterthannumber--bigint)
- [x] [`.toBeGreaterThanOrEqual()`](https://jestjs.io/docs/expect#tobegreaterthanorequalnumber--bigint)
- [x] [`.toBeLessThan()`](https://jestjs.io/docs/expect#tobelessthannumber--bigint)
- [x] [`.toBeLessThanOrEqual()`](https://jestjs.io/docs/expect#tobelessthanorequalnumber--bigint)
- [x] [`.toBeInstanceOf()`](https://jestjs.io/docs/expect#tobeinstanceofclass) (Bun v0.5.8+)
- [ ] [`.toContainEqual()`](https://jestjs.io/docs/expect#tocontainequalitem)
- [ ] [`.toMatch()`](https://jestjs.io/docs/expect#tomatchregexp--string)
- [ ] [`.toMatchObject()`](https://jestjs.io/docs/expect#tomatchobjectobject)
- [x] [`.toMatchSnapshot()`](https://jestjs.io/docs/expect#tomatchsnapshotpropertymatchers-hint) (Bun v0.5.8+)
- [ ] [`.toMatchInlineSnapshot()`](https://jestjs.io/docs/expect#tomatchinlinesnapshotpropertymatchers-inlinesnapshot)
- [ ] [`.toThrowErrorMatchingSnapshot()`](https://jestjs.io/docs/expect#tothrowerrormatchingsnapshothint)
- [ ] [`.toThrowErrorMatchingInlineSnapshot()`](https://jestjs.io/docs/expect#tothrowerrormatchinginlinesnapshotinlinesnapshot)
<!-- ```ts
test('matchers', ()=>{
expect(5).toBe(5);
expect("do re mi").toContain("mi");
expect("do re mi").toEqual("do re mi");
expect({}).toStrictEqual({}); // uses Bun.deepEquals()
expect([1,2,3]).toHaveLength(3);
expect({ name: "foo" }).toHaveProperty("name");
expect({ name: "foo" }).toHaveProperty("name", "foo");
expect(5).toBeTruthy();
expect(0).toBeFalsy();
expect("").toBeDefined();
expect(undefined).toBeUndefined();
expect(parseInt('tuna')).toBeNaN();
expect(null).toBeNull();
expect(5).toBeGreaterThan(4);
expect(5).toBeGreaterThanOrEqual(5);
expect(5).toBeLessThan(6);
expect(5).toBeLessThanOrEqual(5);
expect(()=>throw new Error()).toThrow();
// negation
expect(5).not.toBe(4)
})
``` -->

View File

@@ -1,7 +1,7 @@
Projects that use Express and other major Node.js HTTP libraries should work out of the box.
Projects that use Express and other major Node.js HTTP libraries should work out of the box.
{% callout %}
If you run into bugs, [please file an issue](https://bun.sh/issues) *in Bun's repo*, not the library. It is Bun's responsibility to address Node.js compatibility issues.
If you run into bugs, [please file an issue](https://bun.sh/issues) _in Bun's repo_, not the library. It is Bun's responsibility to address Node.js compatibility issues.
{% /callout %}
```ts
@@ -22,7 +22,7 @@ app.listen(port, () => {
Bun implements the [`node:http`](https://nodejs.org/api/http.html) and [`node:https`](https://nodejs.org/api/https.html) modules that these libraries rely on. These modules can also be used directly, though [`Bun.serve`](/docs/api/http) is recommended for most use cases.
{% callout %}
**Note** — Refer to the [Runtime > Node.js APIs](/docs/ecosystem/nodejs#node_http) page for more detailed compatibility information.
**Note** — Refer to the [Runtime > Node.js APIs](/docs/runtime/nodejs-apis#node_http) page for more detailed compatibility information.
{% /callout %}
```ts

View File

@@ -19,23 +19,23 @@ $ bun run react.tsx
<Component message="Hello world!" />
```
### Prop punning
### Prop punning
The Bun runtime also supports "prop punning for JSX. This is a shorthand syntax useful for assigning a variable to a prop with the same name.
The Bun runtime also supports "prop punning" for JSX. This is a shorthand syntax useful for assigning a variable to a prop with the same name.
```tsx
function Div(props: {className: string;}) {
const {className} = props;
// without punning
return <div className={className} />;
// with punning
return <div {className} />;
}
```
### Server-side rendering
To server-side render (SSR) React in an [HTTP server](/docs/api/http):
```tsx#ssr.tsx

View File

@@ -1,92 +0,0 @@
Bun can directly execute `.ts` and `.tsx` files just like vanilla JavaScript, with no extra configuration. If you import a `.ts` or `.tsx` file (or an `npm` module that exports these files), Bun internally transpiles it into JavaScript then executes the file.
{% callout %}
**Note** — Similar to other build tools, Bun does not typecheck the files. Use [`tsc --noEmit`](https://www.typescriptlang.org/docs/handbook/compiler-options.html) (the official TypeScript CLI) if you're looking to catch static type errors.
{% /callout %}
## Type definitions
To install TypeScript definitions for Bun's built-in APIs, first install `bun-types`.
```sh
$ bun add -d bun-types # dev dependency
```
Then include `"bun-types"` in the `compilerOptions.types` in your `tsconfig.json`:
```json-diff
{
"compilerOptions": {
+ "types": ["bun-types"]
}
}
```
## Compiler options
Bun's runtime implements [modern ECMAScript features](https://github.com/sudheerj/ECMAScript-features), like bigint literals, nullish coalescing, dynamic imports, `import.meta`, `globalThis`, ES modules, top-level await, and more. To use these features without seeing TypeScript errors in your IDE, your `tsconfig.json` needs to be properly configured.
These are the recommended `compilerOptions` for a Bun project.
> The config below sets `moduleResolution` to `bundler` which requires TypeScript option is set to `"bundler"` to support [path mapping](#path-mapping).
```jsonc
{
"compilerOptions": {
// enable latest features
"lib": ["esnext"],
"module": "esnext",
"target": "esnext",
// requires typescript 5.x+
// use "nodenext" for earlier versions
"moduleResolution": "bundler",
// support JSX, CommonJS
"jsx": "react-jsx", // support JSX (value doesn't matter)
"allowJs": true, // allow importing `.js` from `.ts`
"esModuleInterop": true, // allow default imports for CommonJS modules
// best practices
"strict": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
// add Bun type definitions
"types": ["bun-types"]
}
}
```
If you use `bun init`, an appropriate `tsconfig.json` is automatically generated for you.
## Path mapping
When resolving modules, Bun's runtime respects path mappings defined in [`compilerOptions.paths`](https://www.typescriptlang.org/tsconfig#paths) in your `tsconfig.json`. No other runtime does this.
Given the following `tsconfig.json`...
```json
{
"compilerOptions": {
"paths": {
"data": ["./data.ts"]
}
}
}
```
...the import from `"data"` will work as expected.
{% codetabs %}
```ts#index.ts
import { foo } from "data";
console.log(foo); // => "Hello world!"
```
```ts#data.ts
export const foo = "Hello world!"
```
{% /codetabs %}

View File

@@ -19,7 +19,7 @@ $ bunx cowsay "Hello, world!" # execute a package
**Bun is still under development.** Use it to speed up your development workflows or run simpler production code in resource-constrained environments like serverless functions. We're working on more complete Node.js compatibility and integration with existing frameworks. Join the [Discord](https://bun.sh/discord) and watch the [GitHub repository](https://github.com/oven-sh/bun) to keep tabs on future releases.
{% /callout %}
### Get started
Get started with one of the quick links below, or read on to learn more about Bun.
{% block className="gap-2 grid grid-flow-row grid-cols-1 md:grid-cols-2" %}
{% arrowbutton href="/docs/installation" text="Install Bun" /%}
@@ -38,7 +38,7 @@ JavaScript (or, more formally, ECMAScript) is just a _specification_ for a progr
### Browsers
But most JavaScript programs don't run in a vacuum. They need a way to access to the outside world to perform useful tasks. This is where _runtimes_ come in. They implement additional APIs that are then made available to the JavaScript programs they execute. Notably, browsers ship with JavaScript runtimes that implement a set of Web-specific APIs that are exposed via the global `window` object. Any JavaScript code executed by the browser can use these APIs to implement interactive or dynamic behavior in the context of the current webpage.
But most JavaScript programs don't run in a vacuum. They need a way to access the outside world to perform useful tasks. This is where _runtimes_ come in. They implement additional APIs that are then made available to the JavaScript programs they execute. Notably, browsers ship with JavaScript runtimes that implement a set of Web-specific APIs that are exposed via the global `window` object. Any JavaScript code executed by the browser can use these APIs to implement interactive or dynamic behavior in the context of the current webpage.
<!-- JavaScript runtime that exposes JavaScript engines are designed to run "vanilla" JavaScript programs, but it's often JavaScript _runtimes_ use an engine internally to execute the code and implement additional APIs that are then made available to executed programs.
JavaScript was [initially designed](https://en.wikipedia.org/wiki/JavaScript) as a language to run in web browsers to implement interactivity and dynamic behavior in web pages. Browsers are the first JavaScript runtimes. JavaScript programs that are executed in browsers have access to a set of Web-specific global APIs on the `window` object. -->

59
docs/install/cache.md Normal file
View File

@@ -0,0 +1,59 @@
All packages downloaded from the registry are stored in a global cache at `~/.bun/install/cache`. They are stored in subdirectories named like `${name}@${version}`, so multiple versions of a package can be cached.
{% details summary="Configuring cache behavior" %}
```toml
[install.cache]
# the directory to use for the cache
dir = "~/.bun/install/cache"
# when true, don't load from the global cache.
# Bun may still write to node_modules/.cache
disable = false
# when true, always resolve the latest versions from the registry
disableManifest = false
```
{% /details %}
## Minimizing re-downloads
Bun strives to avoid re-downloading packages mutiple times. When installing a package, if the cache already contains a version in the range specified by `package.json`, Bun will use the cached package instead of downloading it again.
{% details summary="Installation details" %}
If the semver version has pre-release suffix (`1.0.0-beta.0`) or a build suffix (`1.0.0+20220101`), it is replaced with a hash of that value instead, to reduce the chances of errors associated with long file paths.
When the `node_modules` folder exists, before installing, Bun checks that `node_modules` contains all expected packages with appropriate versions. If so `bun install` completes. Bun uses a custom JSON parser which stops parsing as soon as it finds `"name"` and `"version"`.
If a package is missing or has a version incompatible with the `package.json`, Bun checks for a compatible module in the cache. If found, it is installed into `node_modules`. Otherwise, the package will be downloaded from the registry then installed.
{% /details %}
## Fast copying
Once a package is downloaded into the cache, Bun still needs to copy those files into `node_modules`. Bun uses the fastest syscalls available to perform this task. On Linux, it uses hardlinks; on macOS, it uses `clonefile`.
## Saving disk space
Since Bun uses hardlinks to "copy" a module into a project's `node_modules` directory on Linux, the contents of the package only exist in a single location on disk, greatly reducing the amount of disk space dedicated to `node_modules`.
This benefit does not extend to macOS, which uses `clonefile` for performance reasons.
{% details summary="Installation strategies" %}
This behavior is configurable with the `--backend` flag, which is respected by all of Bun's package management commands.
- **`hardlink`**: Default on Linux.
- **`clonefile`** Default on macOS.
- **`clonefile_each_dir`**: Similar to `clonefile`, except it clones each file individually per directory. It is only available on macOS and tends to perform slower than `clonefile`.
- **`copyfile`**: The fallback used when any of the above fail. It is the slowest option. On macOS, it uses `fcopyfile()`; on Linux it uses `copy_file_range()`.
**`symlink`**: Currently used only `file:` (and eventually `link:`) dependencies. To prevent infinite loops, it skips symlinking the `node_modules` folder.
If you install with `--backend=symlink`, Node.js won't resolve node_modules of dependencies unless each dependency has its own `node_modules` folder or you pass `--preserve-symlinks` to `node`. See [Node.js documentation on `--preserve-symlinks`](https://nodejs.org/api/cli.html#--preserve-symlinks).
```bash
$ bun install --backend symlink
$ node --preserve-symlinks ./foo.js
```
Bun's runtime does not currently expose an equivalent of `--preserve-symlinks`.
{% /details %}

190
docs/install/index.md Normal file
View File

@@ -0,0 +1,190 @@
The `bun` CLI contains an `npm`-compatible package manager designed to be a faster replacement for existing package management tools like `npm`, `yarn`, and `pnpm`. It's designed for Node.js compatibility; use it in any Bun or Node.js project.
{% callout %}
**⚡️ 80x faster** — Switch from `npm install` to `bun install` in any Node.js project to make your installations up to 80x faster.
{% image src="https://user-images.githubusercontent.com/709451/147004342-571b6123-17a9-49a2-8bfd-dcfc5204047e.png" height="200" /%}
{% /callout %}
{% details summary="For Linux users" %}
The minimum Linux Kernel version is 5.1. If you're on Linux kernel 5.1 - 5.5, `bun install` should still work, but HTTP requests will be slow due to a lack of support for io_uring's `connect()` operation.
If you're using Ubuntu 20.04, here's how to install a [newer kernel](https://wiki.ubuntu.com/Kernel/LTSEnablementStack):
```bash
# If this returns a version >= 5.6, you don't need to do anything
uname -r
# Install the official Ubuntu hardware enablement kernel
sudo apt install --install-recommends linux-generic-hwe-20.04
```
{% /details %}
## Manage dependencies
### `bun install`
To install all dependencies of a project:
```bash
$ bun install
```
On Linux, `bun install` tends to install packages 20-100x faster than `npm install`. On macOS, it's more like 4-80x.
![package install benchmark](https://user-images.githubusercontent.com/709451/147004342-571b6123-17a9-49a2-8bfd-dcfc5204047e.png)
Running `bun install` will:
- **Install** all `dependencies`, `devDependencies`, and `optionalDependencies`. Bun does not install `peerDependencies` by default.
- **Run** your project's `{pre|post}install` scripts at the appropriate time. For security reasons Bun _does not execute_ lifecycle scripts of installed dependencies.
- **Write** a `bun.lockb` lockfile to the project root.
To install in production mode (i.e. without `devDependencies`):
```bash
$ bun install --production
```
To perform a dry run (i.e. don't actually install anything):
```bash
$ bun install --dry-run
```
To modify logging verbosity:
```bash
$ bun install --verbose # debug logging
$ bun install --silent # no logging
```
{% details summary="Configuring behavior" %}
The default behavior of `bun install` can be configured in `bun.toml`:
```toml
[install]
# whether to install optionalDependencies
optional = true
# whether to install devDependencies
dev = true
# whether to install peerDependencies
peer = false
# equivalent to `--production` flag
production = false
# equivalent to `--dry-run` flag
dryRun = false
```
{% /details %}
### `bun add`
To add a particular package:
```bash
$ bun add preact
```
To specify a version, version range, or tag:
```bash
$ bun add zod@3.20.0
$ bun add zod@^3.0.0
$ bun add zod@latest
```
To add a package as a dev dependency (`"devDependencies"`):
```bash
$ bun add --development @types/react
$ bun add -d @types/react
```
To add a package as an optional dependency (`"optionalDependencies"`):
```bash
$ bun add --optional lodash
```
To install a package globally:
```bash
$ bun add --global cowsay # or `bun add -g cowsay`
$ cowsay "Bun!"
______
< Bun! >
------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
```
{% details summary="Configuring global installation behavior" %}
```toml
[install]
# where `bun install --global` installs packages
globalDir = "~/.bun/install/global"
# where globally-installed package bins are linked
globalBinDir = "~/.bun/bin"
```
{% /details %}
To view a complete list of options for a given command:
```bash
$ bun add --help
```
### `bun remove`
To remove a dependency:
```bash
$ bun remove preact
```
## Git dependencies
To add a dependency from a git repository:
```bash
$ bun install git@github.com:moment/moment.git
```
Bun supports a variety of protocols, including [`github`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#github-urls), [`git`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#git-urls-as-dependencies), `git+ssh`, `git+https`, and many more.
```json
{
"dependencies": {
"dayjs": "git+https://github.com/iamkun/dayjs.git",
"lodash": "git+ssh://github.com/lodash/lodash.git#4.17.21",
"moment": "git@github.com:moment/moment.git",
"zod": "github:colinhacks/zod"
}
}
```
## Tarball dependencies
A package name can correspond to a publically hosted `.tgz` file. During `bun install`, Bun will download and install the package from the specified tarball URL, rather than from the package registry.
```json#package.json
{
"dependencies": {
"zod": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz"
}
}
```

67
docs/install/lockfile.md Normal file
View File

@@ -0,0 +1,67 @@
Running `bun install` will create a binary lockfile called `bun.lockb`.
#### Why is it binary?
In a word: Performance. Buns lockfile saves & loads incredibly quickly, and saves a lot more data than what is typically inside lockfiles.
#### How do I inspect it?
Run `bun install -y` to generate a Yarn-compatible `yarn.lock` (v1) that can be inspected more easily.
#### Platform-specific dependencies?
Bun stores normalized `cpu` and `os` values from npm in the lockfile, along with the resolved packages. It skips downloading, extracting, and installing packages disabled for the current target at runtime. This means the lockfile wont change between platforms/architectures even if the packages ultimately installed do change.
#### What does the lockfile store?
Packages, metadata for those packages, the hoisted install order, dependencies for each package, what packages those dependencies resolved to, an integrity hash (if available), what each package was resolved to, and which version (or equivalent).
#### Why is it fast?
It uses linear arrays for all data. [Packages](https://github.com/oven-sh/bun/blob/be03fc273a487ac402f19ad897778d74b6d72963/src/install/install.zig#L1825) are referenced by an auto-incrementing integer ID or a hash of the package name. Strings longer than 8 characters are de-duplicated. Prior to saving on disk, the lockfile is garbage-collected & made deterministic by walking the package tree and cloning the packages in dependency order.
#### Can I opt out?
To install without creating a lockfile:
```bash
$ bun install --no-save
```
To install a Yarn lockfile _in addition_ to `bun.lockb`.
{% codetabs %}
```bash#CLI flag
$ bun install --yarn
```
```toml#bunfig.toml
[install.lockfile]
# whether to save a non-Bun lockfile alongside bun.lockb
# only "yarn" is supported
print = "yarn"
```
{% /codetabs %}
{% details summary="Configuring lockfile" %}
```toml
[install.lockfile]
# path to read bun.lockb from
path = "bun.lockb"
# path to save bun.lockb to
savePath = "bun.lockb"
# whether to save the lockfile to disk
save = true
# whether to save a non-Bun lockfile alongside bun.lockb
# only "yarn" is supported
print = "yarn"
```
{% /details %}

View File

@@ -0,0 +1,26 @@
The default registry is `registry.npmjs.org`. This can be globally configured in `bunfig.toml`:
```toml
[install]
# set default registry as a string
registry = "https://registry.npmjs.org"
# set a token
registry = { url = "https://registry.npmjs.org", token = "123456" }
# set a username/password
registry = "https://username:password@registry.npmjs.org"
```
To configure a private registry scoped to a particular organization:
```toml
[install.scopes]
# registry as string
"@myorg1" = "https://username:password@registry.myorg.com/"
# registry with username/password
# you can reference environment variables
"@myorg2" = { username = "myusername", password = "$NPM_PASS", url = "https://registry.myorg.com/" }
# registry with token
"@myorg3" = { token = "$npm_token", url = "https://registry.myorg.com/" }
```

58
docs/install/utilities.md Normal file
View File

@@ -0,0 +1,58 @@
The `bun pm` command group provides a set of utilities for working with Bun's package manager.
To print the path to the `bin` directory for the local project:
```bash
$ bun pm bin
/path/to/current/project/node_modules/.bin
```
To print the path to the global `bin` directory:
```bash
$ bun pm bin -g
<$HOME>/.bun/bin
```
To print a list of installed dependencies in the current project and their resolved versions, excluding their dependencies.
```bash
$ bun pm ls
/path/to/project node_modules (135)
├── eslint@8.38.0
├── react@18.2.0
├── react-dom@18.2.0
├── typescript@5.0.4
└── zod@3.21.4
```
To print all installed dependencies, including nth-order dependencies.
```bash
$ bun pm ls --all
/path/to/project node_modules (135)
├── @eslint-community/eslint-utils@4.4.0
├── @eslint-community/regexpp@4.5.0
├── @eslint/eslintrc@2.0.2
├── @eslint/js@8.38.0
├── @nodelib/fs.scandir@2.1.5
├── @nodelib/fs.stat@2.0.5
├── @nodelib/fs.walk@1.2.8
├── acorn@8.8.2
├── acorn-jsx@5.3.2
├── ajv@6.12.6
├── ansi-regex@5.0.1
├── ...
```
To print the path to Bun's global module cache:
```bash
$ bun pm cache
```
To clear Bun's global module cache:
```bash
$ bun pm cache rm
```

View File

@@ -0,0 +1,30 @@
Bun supports [`workspaces`](https://docs.npmjs.com/cli/v9/using-npm/workspaces?v=true#description) in `package.json`. Workspaces make it easy to develop complex software as a _monorepo_ consisting of several independent packages.
To try it, specify a list of sub-packages in the `workspaces` field of your `package.json`; it's conventional to place these sub-packages in a directory called `packages`.
```json
{
"name": "my-project",
"version": "1.0.0",
"workspaces": ["packages/*"]
}
```
{% callout %}
**Glob support** — Bun v0.5.8 added support for simple `<directory>/*` globs in `"workspaces"`. Full glob syntax (e.g. `**` and `?`) is not yet supported (soon!).
{% /callout %}
This has a couple major benefits.
- **Code can be split into logical parts.** If one package relies on another, you can simply add it as a dependency with `bun add`. If package `b` depends on `a`, `bun install` will symlink your local `packages/a` directory into the `node_modules` folder of `b`, instead of trying to download it from the npm registry.
- **Dependencies can be de-duplicated.** If `a` and `b` share a common dependency, it will be _hoisted_ to the root `node_modules` directory. This reduces redundant disk usage and minimizes "dependency hell" issues associated with having multiple versions of a package installed simultaneously.
{% callout %}
⚡️ **Speed** — Installs are fast, even for big monorepos. Bun installs the [Remix](https://github.com/remix-run/remix) monorepo in about `500ms` on Linux.
- 28x faster than `npm install`
- 12x faster than `yarn install` (v1)
- 8x faster than `pnpm install`
{% image src="https://user-images.githubusercontent.com/709451/212829600-77df9544-7c9f-4d8d-a984-b2cd0fd2aa52.png" /%}
{% /callout %}

View File

@@ -99,6 +99,14 @@ $ docker run --rm --init --ulimit memlock=-1:-1 oven/bun:edge
this is some output
``` -->
## Uninstalling
Bun's binary and install cache is located in `~/.bun` by default. To uninstall bun, delete this directory and edit your shell config (`.bashrc`, `.zshrc`, or similar) to remove `~/.bun/bin` from the `$PATH` variable.
```sh
$ rm -rf ~/.bun # make sure to remove ~/.bun/bin from $PATH
```
## TypeScript
To install TypeScript definitions for Bun's built-in APIs in your project, install `bun-types`.
@@ -117,7 +125,7 @@ Then include `"bun-types"` in the `compilerOptions.types` in your `tsconfig.json
}
```
Refer to [Ecosystem > TypeScript](/docs/ecosystem/typescript) for a complete guide to TypeScript support in Bun.
Refer to [Ecosystem > TypeScript](/docs/runtime/typescript) for a complete guide to TypeScript support in Bun.
## Completions

View File

@@ -33,32 +33,35 @@ export default {
description: "Install Bun with npm, Homebrew, Docker, or the official install script.",
}),
page("quickstart", "Quickstart", {
description: "Get started with Bun by building and running a simple HTTP server in 5 lines of TypeScript.",
description: "Get started with Bun by building and running a simple HTTP server in 6 lines of TypeScript.",
}),
page("templates", "Templates", {
description: "Hit the ground running with one of Bun's official templates, or download a template from GitHub.",
}),
// page("typescript", "TypeScript"),
divider("CLI"),
page("cli/run", "`bun run`", {
description:
"Use `bun run` to execute JavaScript/TypeScript files, package.json scripts, and executable packages.",
}),
page("cli/install", "`bun install`", {
description: "A 100x faster npm client with workspaces, git dependencies, and private registry support.",
}),
page("cli/test", "`bun test`", {
description: "Bun's test runner uses Jest-compatible syntax but runs 100x faster.",
}),
page("cli/create", "`bun create`", {
description: "Scaffold a new Bun project from an official template or GitHub repo.",
}),
page("cli/bunx", "`bunx`", {
description:
"Use `bunx` to auto-install and run executable packages from npm, or use locally installed command-line tools.",
}),
page("cli/deploy", "`bun deploy`", {
disabled: true,
description: "Deploy your Bun app to the cloud (eventually)",
}),
// divider("CLI"),
// page("cli/run", "`bun run`", {
// description:
// "Use `bun run` to execute JavaScript/TypeScript files, package.json scripts, and executable packages.",
// }),
// page("cli/install", "`bun install`", {
// description: "A 100x faster npm client with workspaces, git dependencies, and private registry support.",
// }),
// page("cli/test", "`bun test`", {
// description: "Bun's test runner uses Jest-compatible syntax but runs 100x faster.",
// }),
// page("cli/create", "`bun create`", {
// description: "Scaffold a new Bun project from an official template or GitHub repo.",
// }),
// page("cli/bunx", "`bunx`", {
// description:
// "Use `bunx` to auto-install and run executable packages from npm, or use locally installed command-line tools.",
// }),
// page("cli/deploy", "`bun deploy`", {
// disabled: true,
// description: "Deploy your Bun app to the cloud (eventually)",
// }),
// page("bundler", "Bundler"),
// page("cli/bun-install", "`bun install`"),
@@ -70,37 +73,122 @@ export default {
// page("bundev", "Dev server"),
// page("benchmarks", "Benchmarks"),
// divider("Runtime"),
divider("Runtime"),
page("runtime/index", "Runtime", {
description: `Bun is a new JavaScript runtime designed to be a faster, leaner, more modern replacement for Node.js.`,
page("cli/run", "`bun run`", {
description: "Use `bun run` to execute JavaScript/TypeScript files and package.json scripts.",
}),
// page("runtime/index", "Overview", {
// description: `Bun is a new JavaScript runtime designed to be a faster, leaner, more modern replacement for Node.js.`,
// }),
// page("runtime/performance", "Performance", {
// description: `Bun is a new JavaScript runtime designed to be a faster, leaner, more modern replacement for Node.js.`,
// }),
page("runtime/loaders", "File types", {
description: `Bun's runtime supports JavaScript/TypeScript files, JSX syntax, Wasm, JSON/TOML imports, and more.`,
}),
page("runtime/typescript", "TypeScript", {
description: `Bun can directly execute TypeScript files without additional configuration.`,
}),
// page("runtime/jsx", "JSX", {
// description: `Bun can directly execute TypeScript files without additional configuration.`,
// }),
// page("runtime/apis", "APIs", {
// description: `Bun is a new JavaScript runtime designed to be a faster, leaner, more modern replacement for Node.js.`,
// }),
page("runtime/bun-apis", "Bun APIs", {
description: `Bun provides a set of highly optimized native APIs for performing common tasks.`,
}),
page("runtime/web-apis", "Web APIs", {
description: `Bun implements an array of Web-standard APIs like fetch, URL, and WebSocket.`,
}),
page("runtime/nodejs-apis", "Node.js compatibility", {
description: `Bun aims for full Node.js compatibility. This page tracks the current compatibility status.`,
}),
// page("runtime/nodejs", "Node.js compatibility", {
// description: `Track the status of Bun's API compatibility with Node.js.`,
// }),
// page("runtime/web-apis", "Web APIs"),
page("runtime/modules", "Module resolution", {
description: `Bun uses ESM and implements an extended version of the Node.js module resolution algorithm.`,
}),
// page("runtime/loaders", "Loaders"),
page("runtime/hot", "Watch mode", {
description: `Reload your application & tests automatically.`,
}),
// page("runtime/loaders", "Loaders"),
page("runtime/plugins", "Plugins", {
description: `Implement custom loaders and module resolution logic with Bun's plugin system.`,
page("runtime/modules", "Module resolution", {
description: `Bun uses ESM and implements an extended version of the Node.js module resolution algorithm.`,
}),
page("runtime/autoimport", "Auto-install", {
description: `Never use node_modules again. Bun can optionally auto-install your dependencies on the fly.`,
}),
page("runtime/configuration", "Configuration", {
description: `Bun's runtime is configurable with environment variables and the bunfig.toml config file.`,
}),
page("runtime/framework", "Framework API", {
disabled: true,
description:
"Coming soon. Use the Framework API to build a fast, cloud-ready framework on top of Bun's bundler and runtime.",
}),
divider("Package manager"),
page("cli/install", "`bun install`", {
description:
"Install all dependencies with `bun install`, or manage dependencies with `bun add` and `bun remove`.",
}),
page("install/workspaces", "Workspaces", {
description: "Bun's package manager supports workspaces and mono-repo development workflows.",
}),
page("install/cache", "Global cache", {
description:
"Bun's package manager installs all packages into a shared global cache to avoid redundant re-downloads.",
}),
page("install/lockfile", "Lockfile", {
description:
"Bun's binary lockfile `bun.lockb` tracks your resolved dependency ytrr, making future installs fast and repeatable.",
}),
page("install/registries", "Scopes and registries", {
description: "How to configure private scopes and custom package registries.",
}),
page("install/utilities", "Utilities", {
description: "Use `bun pm` to introspect your global module cache or project dependency tree.",
}),
divider("Bundler"),
page("cli/build", "`Bun.build`", {
description: "Bundle code for comsumption in the browser with Bun's native bundler.",
}),
// page("bundler/intro", "How bundlers work", {
// description: "A visual introduction to bundling",
// }),
page("bundler/loaders", "Loaders", {
description: "Bun's built-in loaders for the bundler and runtime",
}),
page("bundler/plugins", "Plugins", {
description: `Implement custom loaders and module resolution logic with Bun's plugin system.`,
}),
divider("Test runner"),
page("cli/test", "`bun test`", {
description: "Bun's test runner uses Jest-compatible syntax but runs 100x faster.",
}),
page("test/writing", "Writing tests", {
description:
"Write your tests using Jest-like expect matchers, plus setup/teardown hooks, snapshot testing, and more",
}),
divider("Package runner"),
page("cli/bunx", "`bunx`", {
description: "Use `bunx` to auto-install and run executable packages from npm.",
}),
// page("runtime/nodejs", "Node.js APIs"),
divider("Ecosystem"),
page("ecosystem/nodejs", "Node.js", {
description: `Track the status of Bun's API compatibility with Node.js.`,
}),
page("ecosystem/typescript", "TypeScript", {
description: `Bun can directly execute TypeScript files without additional configuration.`,
}),
page("ecosystem/react", "React", {
description: `The Bun runtime supports JSX syntax out of the box and optimizes server-side rendering.`,
// page("ecosystem/react", "React", {
// description: `The Bun runtime supports JSX syntax out of the box and optimizes server-side rendering.`,
// }),
page("ecosystem/express", "Express", {
description: `Servers built with Express and other major Node.js HTTP libraries work out of the box.`,
}),
page("ecosystem/elysia", "Elysia", {
description: `Get started with Elysia, a Bun-native framework designed for the edge.`,
@@ -111,9 +199,7 @@ export default {
page("ecosystem/buchta", "Buchta", {
description: `Buchta is a Bun-native fullstack framework for Svelte and Preact apps.`,
}),
page("ecosystem/express", "Express", {
description: `Servers built with Express and other major Node.js HTTP libraries work out of the box.`,
}),
page("ecosystem/awesome", "Awesome", {
href: "https://github.com/apvarun/awesome-bun",
description: ``,
@@ -162,9 +248,9 @@ export default {
page("api/utils", "Utils", {
description: `Bun implements a set of utilities that are commonly required by developers.`,
}), // "`Bun.peek`"),
page("api/dns", "DNS", {
description: `Resolve domain names to IP addresses.`,
}), // "`bun:dns`"),
// page("api/dns", "DNS", {
// description: `Resolve domain names to IP addresses.`,
// }), // "`bun:dns`"),
page("api/node-api", "Node-API", {
description: `Bun implements the Node-API spec for building native addons.`,
}), // "`Node-API`"),
@@ -180,13 +266,11 @@ export default {
page("project/roadmap", "Roadmap", {
description: `Track Bun's near-term and long-term goals.`,
}),
page("project/configuration", "Configuration", {
description: `Bun's runtime is configurable with environment variables and the bunfig.toml config file.`,
}),
page("project/benchmarking", "Benchmarking", {
description: `Bun is designed for performance. Learn how to benchmark Bun yourself.`,
}),
page("project/developing", "Development", {
page("project/development", "Development", {
description: "Learn how to contribute to Bun and get your local development environment up and running.",
}),
page("project/licensing", "License", {

View File

@@ -12,17 +12,18 @@ To precisely measure time, Bun offers two runtime APIs functions:
When writing your own benchmarks, it's important to choose the right tool.
- For microbenchmarks, a great general-purpose tool is [`mitata`](https://github.com/evanwashere/mitata).
- For load testing, you *must use* an HTTP benchmarking tool that is at least as fast as `Bun.serve()`, or your results will be skewed. Some popular Node.js-based benchmarking tools like [`autocannon`](https://github.com/mcollina/autocannon) are not fast enough. We recommend one of the following:
- For load testing, you _must use_ an HTTP benchmarking tool that is at least as fast as `Bun.serve()`, or your results will be skewed. Some popular Node.js-based benchmarking tools like [`autocannon`](https://github.com/mcollina/autocannon) are not fast enough. We recommend one of the following:
- [`bombardier`](https://github.com/codesenberg/bombardier)
- [`oha`](https://github.com/hatoo/oha)
- [`http_load_test`](https://github.com/uNetworking/uSockets/blob/master/examples/http_load_test.c)
- For benchmarking scripts or CLI commands, we recommend [`hyperfine`](https://github.com/sharkdp/hyperfine). It's an easy way to compare
- For benchmarking scripts or CLI commands, we recommend [`hyperfine`](https://github.com/sharkdp/hyperfine).
## Measuring memory usage
Bun has two heaps. One heap is for the JavaScript runtime and the other heap is for everything else.
{% anchor id="bunjsc" /%}
### JavaScript heap stats
The `bun:jsc` module exposes a few functions for measuring memory usage:
@@ -31,7 +32,9 @@ The `bun:jsc` module exposes a few functions for measuring memory usage:
import { heapStats } from "bun:jsc";
console.log(heapStats());
```
{% details summary="View example statistics" %}
```ts
{
heapSize: 1657575,
@@ -134,14 +137,15 @@ console.log(heapStats());
}
}
```
{% /details %}
JavaScript is a garbage-collected language, not reference counted. It's normal and correct for objects to not be freed immediately in all cases, though it's not normal for objects to never be freed.
Tp force garbage collection to run manually:
To force garbage collection to run manually:
```js
Bun.gc(true); // synchronous
Bun.gc(true); // synchronous
Bun.gc(false); // asynchronous
```
@@ -161,15 +165,12 @@ To view the snapshot, open the `heap.json` file in Safari's Developer Tools (or
3. Click "JavaScript Allocations" in the menu on the left. It might not be visible until you click the pencil icon to show all the timelines
4. Click "Import" and select your heap snapshot JSON
{% image alt="Import heap json" src="https://user-images.githubusercontent.com/709451/204428943-ba999e8f-8984-4f23-97cb-b4e3e280363e.png" caption="Importing a heap snapshot" /%}
Once imported, you should see something like this:
{% image alt="Viewing heap snapshot in Safari" src="https://user-images.githubusercontent.com/709451/204429337-b0d8935f-3509-4071-b991-217794d1fb27.png" caption="Viewing heap snapshot in Safari Dev Tools" /%}
### Native heap stats
Bun uses mimalloc for the other heap. To report a summary of non-JavaScript memory usage, set the `MIMALLOC_SHOW_STATS=1` environment variable. and stats will print on exit.

View File

@@ -1,209 +0,0 @@
Configuring a development environment for Bun usually takes 30-90 minutes depending on your operating system.
## Linux/Windows
The best way to build Bun on Linux and Windows is with the official [Dev Container](https://containers.dev). It ships with Zig, JavaScriptCore, Zig Language Server, and more pre-installed on an instance of Ubuntu.
{% image src="https://user-images.githubusercontent.com/709451/147319227-6446589c-a4d9-480d-bd5b-43037a9e56fd.png" /%}
To develop on Linux/Windows, [Docker](https://www.docker.com) is required. If using WSL on Windows, it is recommended to use [Docker Desktop](https://docs.microsoft.com/en-us/windows/wsl/tutorials/wsl-containers) for its WSL2 integration.
### VSCode
If you're using VSCode, you'll need to have the [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension installed.
To get started, open VS Code in the `bun` repository. The first time you try to open the dev container, the extension will automatically build it for you, based on [`Dockerfile.devcontainer`](https://github.com/oven-sh/bun/blob/main/Dockerfile.devcontainer).
To open the dev container, open the command palette (`Ctrl` + `Shift` + `P`) and run: `Dev Containers: Reopen in Container`. To later rebuild it (only needed when the devcontainer itself changes, not the Bun code), run: `Dev Containers: Rebuild and Reopen in Container`.
### Other editors and CLI
If you're using another editor or want to manually control the dev container from the command line or a script, you'll need to install the [Dev Container CLI](https://www.npmjs.com/package/@devcontainers/cli): `npm install -g @devcontainers/cli`.
To create and start the dev container, in the `bun` repository, locally run:
```bash
# `make devcontainer-<command>` should be equivalent
# to `devcontainer <command>`, it just sets the architecture
# so if you're on ARM64, it'll do the right thing
$ make devcontainer-up
```
To just build the dev container image, run:
```bash
$ make devcontainer-build
```
To start a shell inside the container, run:
```bash
$ make devcontainer-sh
# if it attaches to the container non-interactively,
# instead use the regular docker exec command:
$ docker exec -it <container-name/id> zsh
```
### Cloning
You will then need to clone the GitHub repository inside that container.
```bash
# First time setup
$ gh auth login # if it fails to open a browser, use Personal Access Token instead
$ gh repo clone oven-sh/bun . -- --depth=1 --progress -j8
```
### Building
```bash
# Compile Bun dependencies (zig is already compiled)
$ make devcontainer
# It initializes and updates all submodules except WebKit, because WebKit
# takes a while and it's already compiled for you. To do it manually, use:
$ git -c submodule."src/bun.js/WebKit".update=none submodule update --init --recursive --depth=1 --progress
# Build Bun for development
$ make dev
# Run Bun
$ bun-debug
```
## MacOS
Install LLVM 15 and `homebrew` dependencies:
```bash
$ brew install llvm@15 coreutils libtool cmake libiconv automake ninja gnu-sed pkg-config esbuild go rust
```
Bun (& the version of Zig) need LLVM 15 and Clang 15 (`clang` is part of LLVM). Make sure LLVM 15 is in your `$PATH`:
```bash
$ which clang-15
```
If not, run this to manually link it:
```bash#bash
# use fish_add_path if you're using fish
$ export PATH="$PATH:$(brew --prefix llvm@15)/bin"
$ export LDFLAGS="$LDFLAGS -L$(brew --prefix llvm@15)/lib"
$ export CPPFLAGS="$CPPFLAGS -I$(brew --prefix llvm@15)/include"
```
### Install Zig
{% callout %}
**⚠️ Warning** — You must use the same version of Zig used by Bun in [oven-sh/zig](https://github.com/oven-sh/zig). Installing with `brew` or via Zig's download page will not work!
{% /callout %}
Use [`zigup`](https://github.com/marler8997/zigup) to install the version of Zig (`ZIG_VERSION`) specified in the official [`Dockerfile`](https://github.com/oven-sh/bun/blob/main/Dockerfile). For example:
```bash
$ zigup 0.11.0-dev.1783+436e99d13
```
### Building
To install and build dependencies:
```bash
# without --depth=1 this will take 20+ minutes on 1gbps internet
# mostly due to WebKit
$ git submodule update --init --recursive --progress --depth=1 --checkout
$ bun install
$ make vendor identifier-cache
```
To compile the C++ bindings:
```bash
# without -j this will take 30+ minutes
$ make bindings -j12
```
<!-- If you're building on a macOS device, you'll need to have a valid Developer Certificate, or else the code signing step will fail. To check if you have one, open the `Keychain Access` app, go to the `login` profile and search for `Apple Development`. You should have at least one certificate with a name like `Apple Development: user@example.com (WDYABC123)`. If you don't have one, follow [this guide](https://ioscodesigning.com/generating-code-signing-files/#generate-a-code-signing-certificate-using-xcode) to get one. -->
<!-- You can still work with the generated binary locally at `packages/debug-bun-*/bun-debug` even if the code signing fails. -->
### Testing
To verify the build worked, lets print the version number on the development build of Bun.
```bash
$ packages/debug-bun-darwin-*/bun-debug --version
bun 0.x.y__dev
```
You will want to add `packages/debug-bun-darwin-arm64/` or `packages/debug-bun-darwin-x64/` (depending on your architecture) to `$PATH` so you can run `bun-debug` from anywhere.
### Troubleshooting
If you see an error when compiling `libarchive`, run this:
```bash
$ brew install pkg-config
```
If you see an error about missing files on `zig build obj`, make sure you built the headers.
```bash
$ make headers
```
## JavaScript builtins
When you change anything in `src/bun.js/builtins/js/*`, run this:
```bash
$ make clean-bindings generate-builtins && make bindings -j12
```
That inlines the JavaScript code into C++ headers using the same builtins generator script that Safari uses.
## Code generation scripts
Bun leverages a lot of code generation scripts.
The [./src/bun.js/bindings/headers.h](https://github.com/oven-sh/bun/blob/main/src/bun.js/bindings/headers.h) file has bindings to & from Zig <> C++ code. This file is generated by running the following:
```bash
$ make headers
```
This ensures that the types for Zig and the types for C++ match up correctly, by using comptime reflection over functions exported/imported.
TypeScript files that end with `*.classes.ts` are another code generation script. They generate C++ boilerplate for classes implemented in Zig. The generated code lives in:
- [src/bun.js/bindings/ZigGeneratedClasses.cpp](https://github.com/oven-sh/bun/tree/main/src/bun.js/bindings/ZigGeneratedClasses.cpp)
- [src/bun.js/bindings/ZigGeneratedClasses.h](https://github.com/oven-sh/bun/tree/main/src/bun.js/bindings/ZigGeneratedClasses.h)
- [src/bun.js/bindings/generated_classes.zig](https://github.com/oven-sh/bun/tree/main/src/bun.js/bindings/generated_classes.zig)
To generate the code, run:
```bash
$ make codegen
```
Lastly, we also have a [code generation script](src/bun.js/scripts/generate-jssink.js) for our native stream implementations.
To run that, run:
```bash
$ make generate-sink
```
You probably won't need to run that one much.
## Modifying ESM core modules
Certain modules like `node:fs`, `node:path`, `node:stream`, and `bun:sqlite` are implemented in JavaScript. These live in `src/bun.js/*.exports.js` files.
While Bun is in beta, you can modify them at runtime in release builds via the environment variable `BUN_OVERRIDE_MODULE_PATH`. When set, Bun will look in the override directory for `<name>.exports.js` before checking the files from `src/bun.js` (which are now baked in to the binary). This lets you test changes to the ESM modules without needing to re-compile Bun.
## Troubleshooting
If you encounter `error: the build command failed with exit code 9` during the build process, this means you ran out of memory or swap. Bun currently needs about 22 GB of RAM to compile.

225
docs/project/development.md Normal file
View File

@@ -0,0 +1,225 @@
Configuring a development environment for Bun can take 10-30 minutes depending on your internet connection and computer speed. You will need ~10GB of free disk space for the repository and build artifacts.
If you are using Windows, you must use a WSL environment as Bun does not yet compile on Windows natively.
## Install LLVM
Bun requires LLVM 15 and Clang 15 (`clang` is part of LLVM). This version requirement is to match WebKit (precompiled), as mismatching versions will cause memory allocation failures at runtime. In most cases, you can install LLVM through your system package manager:
{% codetabs %}
```bash#macOS (Homebrew)
$ brew install llvm@15
```
```bash#Ubuntu/Debian
# On Ubuntu 22.04 and newer, LLVM 15 is available in the default repositories
$ sudo apt install llvm-15 lld-15
# On older versions,
$ wget https://apt.llvm.org/llvm.sh -O - | sudo bash -s -- 15 all
```
```bash#Arch
$ sudo pacman -S llvm clang lld
```
{% /codetabs %}
If none of the above solutions apply, you will have to install it [manually](https://github.com/llvm/llvm-project/releases/tag/llvmorg-15.0.7).
Make sure LLVM 15 is in your path:
```bash
$ which clang-15
```
If not, run this to manually link it:
{% codetabs %}
```bash#macOS (Homebrew)
# use fish_add_path if you're using fish
$ export PATH="$PATH:$(brew --prefix llvm@15)/bin"
$ export LDFLAGS="$LDFLAGS -L$(brew --prefix llvm@15)/lib"
$ export CPPFLAGS="$CPPFLAGS -I$(brew --prefix llvm@15)/include"
```
{% /codetabs %}
## Install Dependencies
Using your system's package manager, install the rest of Bun's dependencies:
{% codetabs %}
```bash#macOS (Homebrew)
$ brew install automake ccache cmake coreutils esbuild gnu-sed go libiconv libtool ninja pkg-config rust
```
```bash#Ubuntu/Debian
$ sudo apt install cargo ccache cmake esbuild git golang libtool ninja-build pkg-config rustc
```
```bash#Arch
$ pacman -S base-devel ccache cmake esbuild git go libiconv libtool make ninja pkg-config python rust sed unzip
```
{% /codetabs %}
In addition to this, you will need either `bun` or `npm` installed to install the package.json dependencies.
## Install Zig
Zig can be installed either with our npm package [`@oven/zig`](https://www.npmjs.com/package/@oven/zig), or by using [zigup](https://github.com/marler8997/zigup).
```bash
$ bun install -g @oven/zig
$ zigup master
```
## Building
After cloning the repository, prepare bun to be built:
```bash
$ make setup
```
Then to build Bun:
```bash
$ make dev
```
The binary will be located at `packages/debug-bun-{platform}-{arch}/bun-debug`. It is recommended to add this to your `$PATH`. To verify the build worked, lets print the version number on the development build of Bun.
```bash
$ packages/debug-bun-*/bun-debug --version
bun 0.x.y__dev
```
## VSCode
VSCode is the recommended IDE for working on Bun, as it has been configured. Once opening, you can run `Extensions: Show Recommended Extensions` to install the recommended extensions for Zig and C++. ZLS is automatically configured.
## JavaScript builtins
When you change anything in `src/bun.js/builtins/js/*` or switch branches, run this:
```bash
$ make regenerate-bindings
```
That inlines the JavaScript code into C++ headers using the same builtins generator script that Safari uses.
{% callout %}
Make sure you have `ccache` installed, otherwise regeneration will take much longer than it should.
{% /callout %}
## Code generation scripts
Bun leverages a lot of code generation scripts.
The [./src/bun.js/bindings/headers.h](https://github.com/oven-sh/bun/blob/main/src/bun.js/bindings/headers.h) file has bindings to & from Zig <> C++ code. This file is generated by running the following:
```bash
$ make headers
```
This ensures that the types for Zig and the types for C++ match up correctly, by using comptime reflection over functions exported/imported.
TypeScript files that end with `*.classes.ts` are another code generation script. They generate C++ boilerplate for classes implemented in Zig. The generated code lives in:
- [src/bun.js/bindings/ZigGeneratedClasses.cpp](https://github.com/oven-sh/bun/tree/main/src/bun.js/bindings/ZigGeneratedClasses.cpp)
- [src/bun.js/bindings/ZigGeneratedClasses.h](https://github.com/oven-sh/bun/tree/main/src/bun.js/bindings/ZigGeneratedClasses.h)
- [src/bun.js/bindings/generated_classes.zig](https://github.com/oven-sh/bun/tree/main/src/bun.js/bindings/generated_classes.zig)
To generate the code, run:
```bash
$ make codegen
```
Lastly, we also have a [code generation script](src/bun.js/scripts/generate-jssink.js) for our native stream implementations.
To run that, run:
```bash
$ make generate-sink
```
You probably won't need to run that one much.
## Modifying ESM core modules
Certain modules like `node:fs`, `node:path`, `node:stream`, and `bun:sqlite` are implemented in JavaScript. These live in `src/bun.js/*.exports.js` files.
While Bun is in beta, you can modify them at runtime in release builds via the environment variable `BUN_OVERRIDE_MODULE_PATH`. When set, Bun will look in the override directory for `<name>.exports.js` before checking the files from `src/bun.js` (which are now baked in to the binary). This lets you test changes to the ESM modules without needing to re-compile Bun.
## Release build
To build a release build of Bun, run:
```bash
$ make release-bindings -j12
$ make release
```
The binary will be located at `packages/bun-{platform}-{arch}/bun`.
## Valgrind
On Linux, valgrind can help find memory issues.
Keep in mind:
- JavaScriptCore doesn't support valgrind. It will report spurious errors.
- Valgrind is slow
- Mimalloc will sometimes cause spurious errors when debug build is enabled
You'll need a very recent version of Valgrind due to DWARF 5 debug symbols. You may need to manually compile Valgrind instead of using it from your Linux package manager.
`--fair-sched=try` is necessary if running multithreaded code in Bun (such as the bundler). Otherwise it will hang.
```bash
$ valgrind --fair-sched=try --track-origins=yes bun-debug <args>
```
## Troubleshooting
### libarchive
If you see an error when compiling `libarchive`, run this:
```bash
$ brew install pkg-config
```
### missing files on `zig build obj`
If you see an error about missing files on `zig build obj`, make sure you built the headers.
```bash
$ make headers
```
### cmakeconfig.h not found
If you see an error about `cmakeconfig.h` not being found, this is because the precompiled WebKit did not install properly.
```bash
$ bun install
```
Check to see the command installed webkit, and you can manully look for `node_modules/bun-webkit-{platform}-{arch}`:
```bash
# this should reveal two directories. if not, something went wrong
$ echo node_modules/bun-webkit*
```
### macOS `library not found for -lSystem`
If you see this error when compiling, run:
```bash
$ xcode-select --install
```

View File

@@ -0,0 +1,98 @@
{% callout %}
**Note** — Added in Bun v0.3.0
{% /callout %}
If no `node_modules` directory is found in the working directory or higher, Bun will abandon Node.js-style module resolution in favor of the **Bun module resolution algorithm**.
Under Bun-style module resolution, all imported packages are auto-installed on the fly into a [global module cache](/docs/cli/install#global-cache) during execution (the same cache used by [`bun install`](/docs/cli/install)).
```ts
import { foo } from "foo"; // install `latest` version
foo();
```
The first time you run this script, Bun will auto-install `"foo"` and cache it. The next time you run the script, it will use the cached version.
## Version resolution
To determine which version to install, Bun follows the following algorithm:
1. Check for a `bun.lockb` file in the project root. If it exists, use the version specified in the lockfile.
2. Otherwise, scan up the tree for a `package.json` that includes `"foo"` as a dependency. If found, use the specified semver version or version range.
3. Otherwise, use `latest`.
## Cache behavior
Once a version or version range has been determined, Bun will:
1. Check the module cache for a compatible version. If one exists, use it.
2. When resolving `latest`, Bun will check if `package@latest` has been downloaded and cached in the last _24 hours_. If so, use it.
3. Otherwise, download and install the appropriate version from the `npm` registry.
## Installation
Packages are installed and cached into `<cache>/<pkg>@<version>`, so multiple versions of the same package can be cached at once. Additionally, a symlink is created under `<cache>/<pkg>/<version>` to make it faster to look up all versions of a package that exist in the cache.
## Version specifiers
This entire resolution algorithm can be short-circuited by specifying a version or version range directly in your import statement.
```ts
import { z } from "zod@3.0.0"; // specific version
import { z } from "zod@next"; // npm tag
import { z } from "zod@^3.20.0"; // semver range
```
## Benefits
This auto-installation approach is useful for a few reasons:
- **Space efficiency** — Each version of a dependency only exists in one place on disk. This is a huge space and time savings compared to redundant per-project installations.
- **Portability** — To share simple scripts and gists, your source file is _self-contained_. No need to `zip` together a directory containing your code and config files. With version specifiers in `import` statements, even a `package.json` isn't necessary.
- **Convenience** — There's no need to run `npm install` or `bun install` before running a file or script. Just `bun run` it.
- **Backwards compatibility** — Because Bun still respects the versions specified in `package.json` if one exists, you can switch to Bun-style resolution with a single command: `rm -rf node_modules`.
## Limitations
- No Intellisense. TypeScript auto-completion in IDEs relies on the existence of type declaration files inside `node_modules`. We are investigating various solutions to this.
- No [patch-package](https://github.com/ds300/patch-package) support
<!-- - The implementation details of Bun's install cache will change between versions. Don't think of it as an API. To reliably resolve packages, use Bun's builtin APIs (such as `Bun.resolveSync` or `import.meta.resolve`) instead of relying on the filesystem directly. Bun will likely move to a binary archive format where packages may not correspond to files/folders on disk at all - so if you depend on the filesystem structure instead of the JavaScript API, your code will eventually break. -->
<!-- ## Customizing behavior
To prefer locally-installed versions of packages. Instead of checking npm for latest versions, you can pass the `--prefer-offline` flag to prefer locally-installed versions of packages.
```bash
$ bun run --prefer-offline my-script.ts
```
This will check the install cache for installed versions of packages before checking the npm registry. If no matching version of a package is installed, only then will it check npm for the latest version.
#### Prefer latest
To always use the latest version of a package, you can pass the `--prefer-latest` flag.
```bash
$ bun run --prefer-latest my-script.ts
``` -->
## FAQ
{% details summary="How is this different from what pnpm does?" %}
With pnpm, you have to run `pnpm install`, which creates a `node_modules` folder of symlinks for the runtime to resolve. By contrast, Bun resolves dependencies on the fly when you run a file; there's no need to run any `install` command ahead of time. Bun also doesn't create a `node_modules` folder.
{% /details %}
{% details summary="How is this different from Yarn Plug'N'Play does?" %}
With Yarn, you must run `yarn install` before you run a script. By contrast, Bun resolves dependencies on the fly when you run a file; there's no need to run any `install` command ahead of time.
Yarn Plug'N'Play also uses zip files to store dependencies. This makes dependency loading [slower at runtime](https://twitter.com/jarredsumner/status/1458207919636287490), as random access reads on zip files tend to be slower than the equivalent disk lookup.
{% /details %}
{% details summary="How is this different from what Deno does?" %}
Deno requires an `npm:` specifier before each npm `import`, lacks support for import maps via `compilerOptions.paths` in `tsconfig.json`, and has incomplete support for `package.json` settings. Unlike Deno, Bun does not currently support URL imports.
{% /details %}

75
docs/runtime/bun-apis.md Normal file
View File

@@ -0,0 +1,75 @@
Bun implements a set of native APIs on the `Bun` global object and through a number of built-in modules. These APIs represent the canonical "Bun-native" way to perform some common development tasks. They are all heavily optimized for performance. Click the link in the left column to view the associated documentation.
{% table %}
- Topic
- APIs
---
- [HTTP](/docs/api/http)
- `Bun.serve`
---
- [File I/O](/docs/api/file-io)
- `Bun.file` `Bun.write`
---
- [Processes](/docs/api/spawn)
- `Bun.spawn` `Bun.spawnSync`
---
- [TCP](/docs/api/tcp)
- `Bun.listen` `Bun.connect`
---
- [Transpiler](/docs/api/transpiler)
- `Bun.Transpiler`
---
- [Routing](/docs/api/file-system-router)
- `Bun.FileSystemRouter`
---
- [HTMLRewriter](/docs/api/html-rewriter)
- `HTMLRewriter`
---
<!-- - [DNS](/docs/api/dns)
- `Bun.dns`
--- -->
- [Utils](/docs/api/utils)
- `Bun.peek` `Bun.which`
---
- [SQLite](/docs/api/sqlite)
- `bun:sqlite`
---
- [FFI](/docs/api/ffi)
- `bun:ffi`
---
- [Testing](/docs/api/test)
- `bun:test`
---
- [Node-API](/docs/api/node-api)
- `Node-API`
---
{% /table %}

View File

@@ -1,23 +1,27 @@
## Environment variables
There are two primary mechanisms for configuring the behavior of Bun.
- `GOMAXPROCS`: For `bun bun`, this sets the maximum number of threads to use. If youre experiencing an issue with `bun bun`, try setting `GOMAXPROCS=1` to force Bun to run single-threaded
- `DISABLE_BUN_ANALYTICS=1` this disables Bun's analytics. Bun records bundle timings (so we can answer with data, "is Bun getting faster?") and feature usage (e.g., "are people actually using macros?"). The request body size is about 60 bytes, so its not a lot of data
- `TMPDIR`: Before `bun bun` completes, it stores the new `.bun` in `$TMPDIR`. If unset, `TMPDIR` defaults to the platform-specific temporary directory (on Linux, `/tmp` and on macOS `/private/tmp`)
- environment variables
- `bunfig.toml`: Bun's configuration file
## `bunfig.toml`
Configuring with `bunfig.toml` is optional. Bun aims to be zero-configuration out of the box, but is also highly configurable for advanced use cases. Your `bunfig.toml` should live in your project root alongside `package.json`.
Bun's configuration file is called `bunfig.toml`. Configuring with `bunfig.toml` is optional. Bun aims to be zero-configuration out of the box, but is also highly configurable for advanced use cases..
Your `bunfig.toml` should live in your project root alongside `package.json`. You can also create a global configuration file at the following paths:
You can also create a global configuration file at the following paths:
- `$HOME/.bunfig.toml`
- `$XDG_CONFIG_HOME/.bunfig.toml`
If both a global and local `bunfig` are detected, the results are shallow-merged, with local overridding global. CLI flags will override `bunfig` setting where applicable.
## Environment variables
<!-- - `GOMAXPROCS`: For `bun bun`, this sets the maximum number of threads to use. If youre experiencing an issue with `bun bun`, try setting `GOMAXPROCS=1` to force Bun to run single-threaded -->
- `DISABLE_BUN_ANALYTICS=1` this disables Bun's analytics. Bun records bundle timings (so we can answer with data, "is Bun getting faster?") and feature usage (e.g., "are people actually using macros?"). The request body size is about 60 bytes, so its not a lot of data
- `TMPDIR`: Bun occasionally requires a directory to store intermediate assets during bundling or other operations. If unset, `TMPDIR` defaults to the platform-specific temporary directory (on Linux, `/tmp` and on macOS `/private/tmp`).
## Configure `bun install`
Package management is a complex issue; to support a range of use cases, the behavior of `bun install` can be configured in [`bunfig.toml`](/docs/project/configuration).
Package management is a complex issue; to support a range of use cases, the behavior of `bun install` can be configured in [`bunfig.toml`](/docs/runtime/configuration).
### Default flags
@@ -42,7 +46,7 @@ production = false
dryRun = false
```
### Registries
### Private scopes and registries
The default registry is `https://registry.npmjs.org/`. This can be globally configured in `bunfig.toml`:
@@ -99,7 +103,7 @@ disableManifest = false
To configure lockfile behavior:
```toml {% disabled %}
```toml
[install.lockfile]
# path to read bun.lockb from

View File

@@ -7,16 +7,17 @@ Bun supports two kinds of automatic reloading via CLI flags:
Watch mode can be used with `bun test` or when running TypeScript, JSX, and JavaScript files.
To run a file in `--watch` mode:
```bash
$ bun index.tsx --watch
$ bun --watch index.tsx
```
To run your tests in `--watch` mode:
```bash
$ bun test --watch
$ bun --watch test
```
In `--watch` mode, Bun keeps track of all imported files and watches them for changes. When a change is detected, Bun restarts the process, preserving the same set of CLI arguments and environment variables used in the initial run. If Bun crashes, `--watch` will attempt to automatically restart the process.
@@ -34,7 +35,7 @@ The following examples show Bun live-reloading a file as it is edited, with VSCo
{% codetabs %}
```bash
$ bun run watchy.tsx --watch
$ bun run --watch watchy.tsx
```
```tsx#watchy.tsx
@@ -57,7 +58,7 @@ serve({
Running `bun test` in watch mode and `save-on-keypress` enabled:
```bash
$ bun test --watch
$ bun --watch test
```
![bun test gif](https://user-images.githubusercontent.com/709451/228396976-38a23864-4a1d-4c96-87cc-04e5181bf459.gif)

View File

@@ -1,17 +1,28 @@
Bun is a new JavaScript runtime designed to be a faster, leaner, more modern replacement for Node.js.
Bun is a new JavaScript & TypeScript runtime designed to be a faster, leaner, and more modern drop-in replacement for Node.js.
## Speed
Bun is designed to start fast and run fast. It's transpiler and runtime are written in Zig, a modern, high-performance language. On Linux, this translates into startup times [4x faster](https://twitter.com/jarredsumner/status/1499225725492076544) than Node.js. Performance sensitive APIs like `Buffer`, `fetch`, and `Response` are heavily profiled and optimized. Under the hood Bun uses the [JavaScriptCore engine](https://developer.apple.com/documentation/javascriptcore), which is developed by Apple for Safari. It starts and runs faster than V8, the engine used by Node.js and Chromium-based browsers.
Bun is designed to start fast and run fast. It's transpiler and runtime are written in Zig, a modern, high-performance language. On Linux, this translates into startup times [4x faster](https://twitter.com/jarredsumner/status/1499225725492076544) than Node.js.
## File types
{% image src="/images/bun-run-speed.jpeg" caption="Bun vs Node.js vs Deno running Hello World" /%}
Bun natively supports TypeScript and JSX out of the box.
<!-- If no `node_modules` directory is found in the working directory or above, Bun will abandon Node.js-style module resolution in favor of the `Bun module resolution algorithm`. Under Bun-style module resolution, all packages are _auto-installed_ on the fly into a [global module cache](/docs/cli/install#global-cache). For full details on this algorithm, refer to [Runtime > Modules](/docs/runtime/modules). -->
Performance sensitive APIs like `Buffer`, `fetch`, and `Response` are heavily profiled and optimized. Under the hood Bun uses the [JavaScriptCore engine](https://developer.apple.com/documentation/javascriptcore), which is developed by Apple for Safari. It starts and runs faster than V8, the engine used by Node.js and Chromium-based browsers.
## TypeScript
Bun natively supports TypeScript out of the box. All files are transpiled on the fly by Bun's fast native transpiler before being executed. Similar to other build tools, Bun does not perform typechecking; it simply removes type annotations from the file.
```bash
$ bun server.tsx
$ bun index.js
$ bun index.jsx
$ bun index.ts
$ bun index.tsx
```
Some aspects of Bun's runtime behavior are affected by the contents of your `tsconfig.json` file. Refer to [Runtime > TypeScript](/docs/runtime/typescript) page for details.
<!-- Before execution, Bun internally transforms all source files to vanilla JavaScript using its fast native transpiler. The transpiler looks at the files extension to determine how to handle it. -->
<!--
@@ -79,6 +90,10 @@ every file before execution. It's transpiler can directly run TypeScript and JS
{% /table %} -->
## JSX
## JSON and TOML
Source files can import a `*.json` or `*.toml` file to load its contents as a plain old JavaScript object.
```ts
@@ -86,7 +101,9 @@ import pkg from "./package.json";
import bunfig from "./bunfig.toml";
```
As of v0.5.2, experimental support has been for the [WebAssembly System Interface](https://github.com/WebAssembly/WASI) (WASI), you can run `.wasm` binaries.
## WASM
As of v0.5.2, experimental support exists for WASI, the [WebAssembly System Interface](https://github.com/WebAssembly/WASI). To run a `.wasm` binary with Bun:
```bash
$ bun ./my-wasm-app.wasm
@@ -95,14 +112,13 @@ $ bun run ./my-wasm-app.whatever
```
{% callout %}
**Note** — WASI support is based on [wasi-js](https://github.com/sagemathinc/cowasm/tree/main/packages/wasi-js). Currently, it only supports WASI binaries that use the `wasi_snapshot_preview1` or `wasi_unstable` APIs. Bun's implementation is not optimized for performance, but if this feature gets popular, we'll definitely invest time in making it faster.
{% /callout %}
Support for additional file types can be implemented with [Plugins](/docs/runtime/plugins).
**Note** — WASI support is based on [wasi-js](https://github.com/sagemathinc/cowasm/tree/main/packages/wasi-js). Currently, it only supports WASI binaries that use the `wasi_snapshot_preview1` or `wasi_unstable` APIs. Bun's implementation is not fully optimized for performance; this will become more of a priority as WASM grows in popularity.
{% /callout %}
## Node.js compatibility
Long-term, Bun aims for complete Node.js compatibility. Most Node.js packages already work with Bun out of the box, but certain low-level APIs like `dgram` are still unimplemented. Track the current compatibility status at [Ecosystem > Node.js](/docs/ecosystem/nodejs).
Long-term, Bun aims for complete Node.js compatibility. Most Node.js packages already work with Bun out of the box, but certain low-level APIs like `dgram` are still unimplemented. Track the current compatibility status at [Ecosystem > Node.js](/docs/runtime/nodejs-apis).
Bun implements the Node.js module resolution algorithm, so dependencies can still be managed with `package.json`, `node_modules`, and CommonJS-style imports.
@@ -110,7 +126,7 @@ Bun implements the Node.js module resolution algorithm, so dependencies can stil
**Note** — We recommend using Bun's [built-in package manager](/docs/cli/install) for a performance boost over other npm clients.
{% /callout %}
## Web-standard
## Web APIs
<!-- When prudent, Bun attempts to implement Web-standard APIs instead of introducing new APIs. Refer to [Runtime > Web APIs](/docs/web-apis) for a list of Web APIs that are available in Bun. -->
@@ -207,7 +223,7 @@ The following Web APIs are partially or completely supported.
{% /table %}
## Bun-native APIs
## Bun APIs
Bun exposes a set of Bun-specific APIs on the `Bun` global object and through a number of built-in modules. These APIs represent the canonical "Bun-native" way to perform some common development tasks. They are all heavily optimized for performance. Click the link in the left column to view the associated documentation.
@@ -284,3 +300,7 @@ Bun exposes a set of Bun-specific APIs on the `Bun` global object and through a
---
{% /table %}
## Plugins
Support for additional file types can be implemented with plugins. Refer to [Runtime > Plugins](/docs/runtime/plugins) for full documentation.

35
docs/runtime/jsx.md Normal file
View File

@@ -0,0 +1,35 @@
Bun supports `.jsx` and `.tsx` files out of the box. Bun's internal transpiler converts JSX syntax into vanilla JavaScript before execution.
```tsx#react.tsx
function Component(props: {message: string}) {
return (
<body>
<h1 style={{color: 'red'}}>{props.message}</h1>
</body>
);
}
console.log(<Component message="Hello world!" />);
```
Bun implements special logging for JSX to make debugging easier.
```bash
$ bun run react.tsx
<Component message="Hello world!" />
```
<!-- ### Prop punning
The Bun runtime also supports "prop punning" for JSX. This is a shorthand syntax useful for assigning a variable to a prop with the same name.
```tsx
function Div(props: {className: string;}) {
const {className} = props;
// without punning
return <div className={className} />;
// with punning
return <div {className} />;
}
``` -->

View File

@@ -1,3 +1,91 @@
## TypeScript
Bun natively supports TypeScript out of the box. All files are transpiled on the fly by Bun's fast native transpiler before being executed. Similar to other build tools, Bun does not perform typechecking; it simply removes type annotations from the file.
```bash
$ bun index.js
$ bun index.jsx
$ bun index.ts
$ bun index.tsx
```
Some aspects of Bun's runtime behavior are affected by the contents of your `tsconfig.json` file. Refer to [Runtime > TypeScript](/docs/runtime/typescript) page for details.
## JSX
Bun supports `.jsx` and `.tsx` files out of the box. Bun's internal transpiler converts JSX syntax into vanilla JavaScript before execution.
```tsx#react.tsx
function Component(props: {message: string}) {
return (
<body>
<h1 style={{color: 'red'}}>{props.message}</h1>
</body>
);
}
console.log(<Component message="Hello world!" />);
```
Bun implements special logging for JSX to make debugging easier.
```bash
$ bun run react.tsx
<Component message="Hello world!" />
```
## Text files
{% callout %}
Supported in Bun v0.6.0 canary.
{% /callout %}
Text files can be imported as strings.
{% codetabs %}
```ts#index.ts
import text from "./text.txt";
console.log(text);
// => "Hello world!"
```
```txt#text.txt
Hello world!
```
{% /codetabs %}
## JSON and TOML
JSON and TOML files can be directly imported from a source file. The contents will be loaded and returned as a JavaScript object.
```ts
import pkg from "./package.json";
import data from "./data.toml";
```
## WASM
As of v0.5.2, experimental support exists for WASI, the [WebAssembly System Interface](https://github.com/WebAssembly/WASI). To run a `.wasm` binary with Bun:
```bash
$ bun ./my-wasm-app.wasm
# if the filename doesn't end with ".wasm"
$ bun run ./my-wasm-app.whatever
```
{% callout %}
**Note** — WASI support is based on [wasi-js](https://github.com/sagemathinc/cowasm/tree/main/packages/wasi-js). Currently, it only supports WASI binaries that use the `wasi_snapshot_preview1` or `wasi_unstable` APIs. Bun's implementation is not fully optimized for performance; this will become more of a priority as WASM grows in popularity.
{% /callout %}
## Custom loaders
Support for additional file types can be implemented with plugins. Refer to [Runtime > Plugins](/docs/runtime/plugins) for full documentation.
<!--
A loader determines how to map imports &amp; file extensions to transforms and output.
Currently, Bun implements the following loaders:
@@ -25,4 +113,4 @@ You can configure which loaders map to which extensions by passing `--loaders` t
$ bun --loader=.js:js
```
This will disable JSX transforms for `.js` files.
This will disable JSX transforms for `.js` files. -->

View File

@@ -156,104 +156,3 @@ In the spirit of treating TypeScript as a first-class citizen, the Bun runtime w
```
If you aren't a TypeScript user, you can create a [`jsconfig.json`](https://code.visualstudio.com/docs/languages/jsconfig) in your project root to achieve the same behavior.
## Bun-style resolution
{% callout %}
**Note** — Added in Bun v0.3.0
{% /callout %}
If no `node_modules` directory is found in the working directory or higher, Bun will abandon Node.js-style module resolution in favor of the **Bun module resolution algorithm**.
Under Bun-style module resolution, all imported packages are auto-installed on the fly into a [global module cache](/docs/cli/install#global-cache) during execution (the same cache used by [`bun install`](/docs/cli/install)).
```ts
import { foo } from "foo"; // install `latest` version
foo();
```
The first time you run this script, Bun will auto-install `"foo"` and cache it. The next time you run the script, it will use the cached version.
### Version resolution
To determine which version to install, Bun follows the following algorithm:
1. Check for a `bun.lockb` file in the project root. If it exists, use the version specified in the lockfile.
2. Otherwise, scan up the tree for a `package.json` that includes `"foo"` as a dependency. If found, use the specified semver version or version range.
3. Otherwise, use `latest`.
### Cache behavior
Once a version or version range has been determined, Bun will:
1. Check the module cache for a compatible version. If one exists, use it.
2. When resolving `latest`, Bun will check if `package@latest` has been downloaded and cached in the last _24 hours_. If so, use it.
3. Otherwise, download and install the appropriate version from the `npm` registry.
### Installation
Packages are installed and cached into `<cache>/<pkg>@<version>`, so multiple versions of the same package can be cached at once. Additionally, a symlink is created under `<cache>/<pkg>/<version>` to make it faster to look up all versions of a package that exist in the cache.
### Version specifiers
This entire resolution algorithm can be short-circuited by specifying a version or version range directly in your import statement.
```ts
import { z } from "zod@3.0.0"; // specific version
import { z } from "zod@next"; // npm tag
import { z } from "zod@^3.20.0"; // semver range
```
### Benefits
This auto-installation approach is useful for a few reasons:
- **Space efficiency** — Each version of a dependency only exists in one place on disk. This is a huge space and time savings compared to redundant per-project installations.
- **Portability** — To share simple scripts and gists, your source file is _self-contained_. No need to `zip` together a directory containing your code and config files. With version specifiers in `import` statements, even a `package.json` isn't necessary.
- **Convenience** — There's no need to run `npm install` or `bun install` before running a file or script. Just `bun run` it.
- **Backwards compatibility** — Because Bun still respects the versions specified in `package.json` if one exists, you can switch to Bun-style resolution with a single command: `rm -rf node_modules`.
### Limitations
- No Intellisense. TypeScript auto-completion in IDEs relies on the existence of type declaration files inside `node_modules`. We are investigating various solutions to this.
- No [patch-package](https://github.com/ds300/patch-package) support
<!-- - The implementation details of Bun's install cache will change between versions. Don't think of it as an API. To reliably resolve packages, use Bun's builtin APIs (such as `Bun.resolveSync` or `import.meta.resolve`) instead of relying on the filesystem directly. Bun will likely move to a binary archive format where packages may not correspond to files/folders on disk at all - so if you depend on the filesystem structure instead of the JavaScript API, your code will eventually break. -->
<!-- ### Customizing behavior
To prefer locally-installed versions of packages. Instead of checking npm for latest versions, you can pass the `--prefer-offline` flag to prefer locally-installed versions of packages.
```bash
$ bun run --prefer-offline my-script.ts
```
This will check the install cache for installed versions of packages before checking the npm registry. If no matching version of a package is installed, only then will it check npm for the latest version.
#### Prefer latest
To always use the latest version of a package, you can pass the `--prefer-latest` flag.
```bash
$ bun run --prefer-latest my-script.ts
``` -->
### FAQ
{% details summary="How is this different from what pnpm does?" %}
With pnpm, you have to run `pnpm install`, which creates a `node_modules` folder of symlinks for the runtime to resolve. By contrast, Bun resolves dependencies on the fly when you run a file; there's no need to run any `install` command ahead of time. Bun also doesn't create a `node_modules` folder.
{% /details %}
{% details summary="How is this different from Yarn Plug'N'Play does?" %}
With Yarn, you must run `yarn install` before you run a script. By contrast, Bun resolves dependencies on the fly when you run a file; there's no need to run any `install` command ahead of time.
Yarn Plug'N'Play also uses zip files to store dependencies. This makes dependency loading [slower at runtime](https://twitter.com/jarredsumner/status/1458207919636287490), as random access reads on zip files tend to be slower than the equivalent disk lookup.
{% /details %}
{% details summary="How is this different from what Deno does?" %}
Deno requires an `npm:` specifier before each npm `import`, lacks support for import maps via `compilerOptions.paths` in `tsconfig.json`, and has incomplete support for `package.json` settings. Unlike Deno, Bun does not currently support URL imports.
{% /details %}

View File

@@ -87,7 +87,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
- {% anchor id="node_fs" %} [`node:fs`](https://nodejs.org/api/fs.html) {% /anchor %}
- 🟡
- Missing `fs.constants` `fs.fdatasync{Sync}` `fs.opendir{Sync}` `fs.readv{Sync}` `fs.{watch|watchFile|unwatchFile}` `fs.writev{Sync}`.
- Missing `fs.fdatasync{Sync}` `fs.opendir{Sync}` `fs.readv{Sync}` `fs.{watch|watchFile|unwatchFile}` `fs.writev{Sync}`.
---
@@ -183,6 +183,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
- {% anchor id="node_string_decoder" %} [`node:string_decoder`](https://nodejs.org/api/string_decoder.html) {% /anchor %}
- 🟢
- Fully implemented.
---
@@ -230,7 +231,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
- {% anchor id="node_v8" %} [`node:v8`](https://nodejs.org/api/v8.html) {% /anchor %}
- 🔴
- Not implemented or planned. For profiling, use `bun:jsc` instead.
- Not implemented or planned. For profiling, use [`bun:jsc`](/docs/project/benchmarking#bunjsc) instead.
---

125
docs/runtime/typescript.md Normal file
View File

@@ -0,0 +1,125 @@
Bun treats TypeScript as a first-class citizen.
## Running `.ts` files
Bun can directly execute `.ts` and `.tsx` files just like vanilla JavaScript, with no extra configuration. If you import a `.ts` or `.tsx` file (or an `npm` module that exports these files), Bun internally transpiles it into JavaScript then executes the file.
**Note** — Similar to other build tools, Bun does not typecheck the files. Use [`tsc`](https://www.typescriptlang.org/docs/handbook/compiler-options.html) (the official TypeScript CLI) if you're looking to catch static type errors.
{% callout %}
**Is transpiling still necessary?** — Because Bun can directly execute TypeScript, you may not need to transpile your TypeScript to run in production. Bun internally transpiles every file it executes (both `.js` and `.ts`), so the additional overhead of directly executing your `.ts/.tsx` source files is negligible.
That said, if you are using Bun as a development tool but still targeting Node.js or browsers in production, you'll still need to transpile.
{% /callout %}
## Configuring `tsconfig.json`
Bun supports a number of features that TypeScript doesn't support by default, such as extensioned imports, top-level await, and `exports` conditions. It also implements global APIs like the `Bun`. To enable these features, your `tsconfig.json` must be configured properly.
{% callout %}
If you initialized your project with `bun init`, everything is already configured properly.
{% /callout %}
To get started, install the `bun-types` package.
```sh
$ bun add -d bun-types # dev dependency
```
If you're using a canary build of Bun, use the `canary` tag. The canary package is updated on every commit to the `main` branch.
```sh
$ bun add -d bun-types@canary
```
<!-- ### Quick setup
{% callout %}
**Note**  This approach requires TypeScript 5.0 or later!
{% /callout %}
Add the following to your `tsconfig.json`.
```json-diff
{
+ "extends": ["bun-types"]
// other options...
}
```
{% callout %}
**Note** — The `"extends"` field in your `tsconfig.json` can accept an array of values. If you're already using `"extends"`, just add `"bun-types"` to the array.
{% /callout %}
That's it! You should be able to use Bun's full feature set without seeing any TypeScript compiler errors.
### Manual setup -->
### Recommended `compilerOptions`
These are the recommended `compilerOptions` for a Bun project.
```jsonc
{
"compilerOptions": {
// add Bun type definitions
"types": ["bun-types"],
// enable latest features
"lib": ["esnext"],
"module": "esnext",
"target": "esnext",
// if TS 5.x+
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"moduleDetection": "force",
// if TS 4.x or earlier
"moduleResolution": "nodenext",
"jsx": "react-jsx", // support JSX
"allowJs": true, // allow importing `.js` from `.ts`
"esModuleInterop": true, // allow default imports for CommonJS modules
// best practices
"strict": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true
}
}
```
## Path mapping
When resolving modules, Bun's runtime respects path mappings defined in [`compilerOptions.paths`](https://www.typescriptlang.org/tsconfig#paths) in your `tsconfig.json`. No other runtime does this.
Given the following `tsconfig.json`...
```json
{
"compilerOptions": {
"paths": {
"data": ["./data.ts"]
}
}
}
```
...the import from `"data"` will work as expected.
{% codetabs %}
```ts#index.ts
import { foo } from "data";
console.log(foo); // => "Hello world!"
```
```ts#data.ts
export const foo = "Hello world!"
```
{% /codetabs %}

View File

@@ -1,22 +1,33 @@
Many web APIs aren't relevant in the context of a server-first runtime like Bun, such as the [DOM API](https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API#html_dom_api_interfaces), [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage), and [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History_API). Many others, though, are broadly useful outside of the browser context; when possible, Bun implements these Web-standard APIs instead of introducing new APIs.
Some Web APIs aren't relevant in the context of a server-first runtime like Bun, such as the [DOM API](https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API#html_dom_api_interfaces) or [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API). Many others, though, are broadly useful outside of the browser context; when possible, Bun implements these Web-standard APIs instead of introducing new APIs.
The following Web APIs are partially or completely supported.
## Globals
{% table %}
---
- Crypto
- [`crypto`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto) [`SubtleCrypto`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto)
[`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey)
- HTTP
- [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)
---
- Debugging
- URLs
- [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console)[`performance`](https://developer.mozilla.org/en-US/docs/Web/API/Performance)
---
- Streams
- [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream) [`TransformStream`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream) [`ByteLengthQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/ByteLengthQueuingStrategy) [`CountQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/CountQueuingStrategy) and associated classes
---
- Blob
- [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob)
---
- WebSockets
- [`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
---
@@ -35,8 +46,15 @@ The following Web APIs are partially or completely supported.
---
- HTTP
- [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)
- Crypto
- [`crypto`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto) [`SubtleCrypto`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto)
[`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey)
---
- Debugging
- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console) [`performance`](https://developer.mozilla.org/en-US/docs/Web/API/Performance)
---
@@ -52,15 +70,12 @@ The following Web APIs are partially or completely supported.
---
- User interaction
- [`alert`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert) [`confirm`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm) [`prompt`](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt)
- [`alert`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert) [`confirm`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm) [`prompt`](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt) (intended for interactive CLIs)
<!-- - Blocking. Prints the alert message to terminal and awaits `[ENTER]` before proceeding. -->
<!-- - Blocking. Prints confirmation message and awaits `[y/N]` input from user. Returns `true` if user entered `y` or `Y`, `false` otherwise.
- Blocking. Prints prompt message and awaits user input. Returns the user input as a string. -->
- Blob
- [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob)
---
- Realms
@@ -74,227 +89,4 @@ The following Web APIs are partially or completely supported.
---
- WebSockets
- [`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
---
- URLs
- [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
---
- Streams
- [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream) [`TransformStream`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream) [`ByteLengthQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/ByteLengthQueuingStrategy) [`CountQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/CountQueuingStrategy) plus associated `*Reader`, `*Writer`, and `*Controller` classes.
<!-- ## Globals
{% table %}
---
---
- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console)
---
- [`crypto`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto)
---
- [`performance`](https://developer.mozilla.org/en-US/docs/Web/API/Performance)
{% /table %}
## Functions
{% table %}
- [`atob`](https://developer.mozilla.org/en-US/docs/Web/API/atob)
---
- [`btoa`](https://developer.mozilla.org/en-US/docs/Web/API/btoa)
---
- [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval)
---
- [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout)
---
- [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch)
---
- [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask)
---
- [`reportError`](https://developer.mozilla.org/en-US/docs/Web/API/reportError)
---
- [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval)
---
- [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout)
---
- [`alert`](https://developer.mozilla.org/en-US/docs/Web/API/alert)
- Blocking. Prints the alert message to terminal and awaits `[ENTER]` before proceeding.
---
- [`confirm`](https://developer.mozilla.org/en-US/docs/Web/API/confirm)
- Blocking. Prints confirmation message and awaits `[y/N]` input from user. Returns `true` if user entered `y` or `Y`, `false` otherwise.
---
- [`prompt`](https://developer.mozilla.org/en-US/docs/Web/API/prompt)
- Blocking. Prints prompt message and awaits user input. Returns the user input as a string.
---
- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console)
{% /table %}
## Classes
{% table %}
---
- [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob)
---
- [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
---
- [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)
---
- [`TextEncoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) and [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder)
---
---
- [`ShadowRealm`](https://github.com/tc39/proposal-shadowrealm)
- A ["better `eval`](https://2ality.com/2022/04/shadow-realms.html). Currently a Stage 3 TC39 proposal
---
- [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers)
---
- [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget)
---
- [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event)
---
- [`ErrorEvent`](https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent)
---
- [`CloseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent)
---
- [`MessageEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent)
---
- [`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
---
- [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
---
- [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL)
---
- [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)
---
- [`Loader`](https://developer.mozilla.org/en-US/docs/Web/API/Loader)
---
- [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)
---
- [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)
---
- [`ByteLengthQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/ByteLengthQueuingStrategy)
---
- [`ReadableStreamDefaultController`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultController)
---
- [`ReadableStreamDefaultReader`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader)
---
- [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream)
---
- [`WritableStreamDefaultController`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultController)
---
- [`WritableStreamDefaultWriter`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultWriter)
---
- [`TransformStream`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream)
---
- [`TransformStreamDefaultController`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStreamDefaultController)
---
- [`CountQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/CountQueuingStrategy)
---
- [`SubtleCrypto`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto)
---
- [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey)
---
- [`ResolveError`](https://developer.mozilla.org/en-US/docs/Web/API/ResolveError)
---
- [`BuildError`](https://developer.mozilla.org/en-US/docs/Web/API/BuildError)
{% /table %} -->

256
docs/templates.md Normal file
View File

@@ -0,0 +1,256 @@
## `bun init`
Scaffold an empty project with the interactive `bun init` command.
```bash
$ bun init
bun init helps you get started with a minimal project and tries to
guess sensible defaults. Press ^C anytime to quit.
package name (quickstart):
entry point (index.ts):
Done! A package.json file was saved in the current directory.
+ index.ts
+ .gitignore
+ tsconfig.json (for editor auto-complete)
+ README.md
To get started, run:
bun run index.ts
```
Press `enter` to accept the default answer for each prompt, or pass the `-y` flag to auto-accept the defaults.
## `bun create`
Template a new Bun project with `bun create`.
```bash
$ bun create <template> <destination>
```
{% callout %}
**Note** You dont need `bun create` to use Bun. You dont need any configuration at all. This command exists to make getting started a bit quicker and easier.
{% /callout %}
A template can take a number of forms:
```bash
$ bun create <template> # an official template (remote)
$ bun create <username>/<repo> # a GitHub repo (remote)
$ bun create <local-template> # a custom template (local)
```
Running `bun create` performs the following steps:
- Download the template (remote templates only)
- Copy all template files into the destination folder. By default Bun will _not overwrite_ any existing files. Use the `--force` flag to overwrite existing files.
- Install dependencies with `bun install`.
- Initialize a fresh Git repo. Opt out with the `--no-git` flag.
- Run the template's configured `start` script, if defined.
### Official templates
The following official templates are available.
```bash
bun create next ./myapp
bun create react ./myapp
bun create svelte-kit ./myapp
bun create elysia ./myapp
bun create hono ./myapp
bun create kingworld ./myapp
```
Each of these corresponds to a directory in the [bun-community/create-templates](https://github.com/bun-community/create-templates) repo. If you think a major framework is missing, please open a PR there. This list will change over time as additional examples are added. To see an up-to-date list, run `bun create` with no arguments.
```bash
$ bun create
Welcome to bun! Create a new project by pasting any of the following:
<list of templates>
```
{% callout %}
⚡️ **Speed** — At the time of writing, `bun create react app` runs ~11x faster on a M1 Macbook Pro than `yarn create react-app app`.
{% /callout %}
### GitHub repos
A template of the form `<username>/<repo>` will be downloaded from GitHub.
```bash
$ bun create ahfarmer/calculator ./myapp
```
Complete GitHub URLs will also work:
```bash
$ bun create github.com/ahfarmer/calculator ./myapp
$ bun create https://github.com/ahfarmer/calculator ./myapp
```
Bun installs the files as they currently exist current default branch (usually `main` or `master`). Unlike `git clone` it doesn't download the commit history or configure a remote.
### Local templates
{% callout %}
**⚠️ Warning** — Unlike remote templates, running `bun create` with a local template will delete the entire destination folder if it already exists! Be careful.
{% /callout %}
Bun's templater can be extended to support custom templates defined on your local file system. These templates should live in one of the following directories:
- `$HOME/.bun-create/<name>`: global templates
- `<project root>/.bun-create/<name>`: project-specific templates
{% callout %}
**Note** — You can customize the global template path by setting the `BUN_CREATE_DIR` environment variable.
{% /callout %}
To create a local template, navigate to `$HOME/.bun-create` and create a new directory with the desired name of your template.
```bash
$ cd $HOME/.bun-create
$ mkdir foo
$ cd foo
```
Then, create a `package.json` file in that directory with the following contents:
```json
{
"name": "foo"
}
```
You can run `bun create foo` elsewhere on your file system to verify that Bun is correctly finding your local template.
{% table %}
---
- `postinstall`
- runs after installing dependencies
---
- `preinstall`
- runs before installing dependencies
<!-- ---
- `start`
- a command to auto-start the application -->
{% /table %}
Each of these can correspond to a string or array of strings. An array of commands will be executed in order. Here is an example:
```json
{
"name": "@bun-examples/simplereact",
"version": "0.0.1",
"main": "index.js",
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"bun-create": {
"preinstall": "echo 'Installing...'", // a single command
"postinstall": ["echo 'Done!'"], // an array of commands
"start": "bun run echo 'Hello world!'"
}
}
```
When cloning a template, `bun create` will automatically remove the `"bun-create"` section from `package.json` before writing it to the destination folder.
### Reference
#### CLI flags
{% table %}
- Flag
- Description
---
- `--force`
- Overwrite existing files
---
- `--no-install`
- Skip installing `node_modules` & tasks
---
- `--no-git`
- Dont initialize a git repository
---
- `--open`
- Start & open in-browser after finish
{% /table %}
#### Environment variables
{% table %}
- Name
- Description
---
- `GITHUB_API_DOMAIN`
- If youre using a GitHub enterprise or a proxy, you can customize the GitHub domain Bun pings for downloads
---
- `GITHUB_API_TOKEN`
- This lets `bun create` work with private repositories or if you get rate-limited
{% /table %}
{% details summary="How `bun create` works" %}
When you run `bun create ${template} ${destination}`, heres what happens:
IF remote template
1. GET `registry.npmjs.org/@bun-examples/${template}/latest` and parse it
2. GET `registry.npmjs.org/@bun-examples/${template}/-/${template}-${latestVersion}.tgz`
3. Decompress & extract `${template}-${latestVersion}.tgz` into `${destination}`
- If there are files that would overwrite, warn and exit unless `--force` is passed
IF GitHub repo
1. Download the tarball from GitHubs API
2. Decompress & extract into `${destination}`
- If there are files that would overwrite, warn and exit unless `--force` is passed
ELSE IF local template
1. Open local template folder
2. Delete destination directory recursively
3. Copy files recursively using the fastest system calls available (on macOS `fcopyfile` and Linux, `copy_file_range`). Do not copy or traverse into `node_modules` folder if exists (this alone makes it faster than `cp`)
4. Parse the `package.json` (again!), update `name` to be `${basename(destination)}`, remove the `bun-create` section from the `package.json` and save the updated `package.json` to disk.
- IF Next.js is detected, add `bun-framework-next` to the list of dependencies
- IF Create React App is detected, add the entry point in /src/index.{js,jsx,ts,tsx} to `public/index.html`
- IF Relay is detected, add `bun-macro-relay` so that Relay works
5. Auto-detect the npm client, preferring `pnpm`, `yarn` (v1), and lastly `npm`
6. Run any tasks defined in `"bun-create": { "preinstall" }` with the npm client
7. Run `${npmClient} install` unless `--no-install` is passed OR no dependencies are in package.json
8. Run any tasks defined in `"bun-create": { "preinstall" }` with the npm client
9. Run `git init; git add -A .; git commit -am "Initial Commit";`
- Rename `gitignore` to `.gitignore`. NPM automatically removes `.gitignore` files from appearing in packages.
- If there are dependencies, this runs in a separate thread concurrently while node_modules are being installed
- Using libgit2 if available was tested and performed 3x slower in microbenchmarks
{% /details %}

357
docs/test/writing.md Normal file
View File

@@ -0,0 +1,357 @@
Define tests with a Jest-like API imported from the built-in `bun:test` module. Long term, Bun aims for complete Jest compatibility; at the moment, a [limited set](#matchers) of `expect` matchers are supported.
## Basic usage
To define a simple test:
```ts#math.test.ts
import { expect, test } from "bun:test";
test("2 + 2", () => {
expect(2 + 2).toBe(4);
});
```
Tests can be grouped into suites with `describe`.
```ts#math.test.ts
import { expect, test, describe } from "bun:test";
describe("arithmetic", () => {
test("2 + 2", () => {
expect(2 + 2).toBe(4);
});
test("2 * 2", () => {
expect(2 * 2).toBe(4);
});
});
```
Tests can be `async`.
```ts
import { expect, test } from "bun:test";
test("2 * 2", async () => {
const result = await Promise.resolve(2 * 2);
expect(result).toEqual(4);
});
```
Alternatively, use the `done` callback to signal completion. If you include the `done` callback as a parameter in your test definition, you _must_ call it or the test will hang.
```ts
import { expect, test } from "bun:test";
test("2 * 2", done => {
Promise.resolve(2 * 2).then(result => {
expect(result).toEqual(4);
done();
});
});
```
Skip individual tests with `test.skip`.
```ts
import { expect, test } from "bun:test";
test.skip("wat", () => {
// TODO: fix this
expect(0.1 + 0.2).toEqual(0.3);
});
```
## Setup and teardown
Perform per-test setup and teardown logic with `beforeEach` and `afterEach`.
```ts
import { expect, test } from "bun:test";
beforeEach(() => {
console.log("running test.");
});
afterEach(() => {
console.log("done with test.");
});
// tests...
```
Perform per-scope setup and teardown logic with `beforeAll` and `afterAll`. At the top-level, the _scope_ is the current file; in a `describe` block, the scope is the block itself.
```ts
import { expect, test, beforeAll, afterAll } from "bun:test";
let db: Database;
beforeAll(() => {
// connect to database
db = initializeDatabase();
});
afterAll(() => {
// close connection
db.close();
});
// tests...
```
## Matchers
Bun implements the following matchers. Full Jest compatibility is on the roadmap; track progress [here](https://github.com/oven-sh/bun/issues/1825).
{% table %}
- 🟢
- [`.not`](https://jestjs.io/docs/expect#not)
---
- 🟢
- [`.toBe()`](https://jestjs.io/docs/expect#tobevalue)
---
- 🟢
- [`.toEqual()`](https://jestjs.io/docs/expect#toequalvalue)
---
- 🟢
- [`.toBeNull()`](https://jestjs.io/docs/expect#tobenull)
---
- 🟢
- [`.toBeUndefined()`](https://jestjs.io/docs/expect#tobeundefined)
---
- 🟢
- [`.toBeNaN()`](https://jestjs.io/docs/expect#tobenan)
---
- 🟢
- [`.toBeDefined()`](https://jestjs.io/docs/expect#tobedefined)
---
- 🟢
- [`.toBeFalsy()`](https://jestjs.io/docs/expect#tobefalsy)
---
- 🟢
- [`.toBeTruthy()`](https://jestjs.io/docs/expect#tobetruthy)
---
- 🟢
- [`.toContain()`](https://jestjs.io/docs/expect#tocontainitem)
---
- 🟢
- [`.toStrictEqual()`](https://jestjs.io/docs/expect#tostrictequalvalue)
---
- 🟢
- [`.toThrow()`](https://jestjs.io/docs/expect#tothrowerror)
---
- 🟢
- [`.toHaveLength()`](https://jestjs.io/docs/expect#tohavelengthnumber)
---
- 🟢
- [`.toHaveProperty()`](https://jestjs.io/docs/expect#tohavepropertykeypath-value)
---
- 🔴
- [`.extend`](https://jestjs.io/docs/expect#expectextendmatchers)
---
- 🔴
- [`.anything()`](https://jestjs.io/docs/expect#expectanything)
---
- 🔴
- [`.any()`](https://jestjs.io/docs/expect#expectanyconstructor)
---
- 🔴
- [`.arrayContaining()`](https://jestjs.io/docs/expect#expectarraycontainingarray)
---
- 🔴
- [`.assertions()`](https://jestjs.io/docs/expect#expectassertionsnumber)
---
- 🔴
- [`.closeTo()`](https://jestjs.io/docs/expect#expectclosetonumber-numdigits)
---
- 🔴
- [`.hasAssertions()`](https://jestjs.io/docs/expect#expecthasassertions)
---
- 🔴
- [`.objectContaining()`](https://jestjs.io/docs/expect#expectobjectcontainingobject)
---
- 🔴
- [`.stringContaining()`](https://jestjs.io/docs/expect#expectstringcontainingstring)
---
- 🔴
- [`.stringMatching()`](https://jestjs.io/docs/expect#expectstringmatchingstring--regexp)
---
- 🔴
- [`.addSnapshotSerializer()`](https://jestjs.io/docs/expect#expectaddsnapshotserializerserializer)
---
- 🔴
- [`.resolves()`](https://jestjs.io/docs/expect#resolves)
---
- 🔴
- [`.rejects()`](https://jestjs.io/docs/expect#rejects)
---
- 🔴
- [`.toHaveBeenCalled()`](https://jestjs.io/docs/expect#tohavebeencalled)
---
- 🔴
- [`.toHaveBeenCalledTimes()`](https://jestjs.io/docs/expect#tohavebeencalledtimesnumber)
---
- 🔴
- [`.toHaveBeenCalledWith()`](https://jestjs.io/docs/expect#tohavebeencalledwitharg1-arg2-)
---
- 🔴
- [`.toHaveBeenLastCalledWith()`](https://jestjs.io/docs/expect#tohavebeenlastcalledwitharg1-arg2-)
---
- 🔴
- [`.toHaveBeenNthCalledWith()`](https://jestjs.io/docs/expect#tohavebeennthcalledwithnthcall-arg1-arg2-)
---
- 🔴
- [`.toHaveReturned()`](https://jestjs.io/docs/expect#tohavereturned)
---
- 🔴
- [`.toHaveReturnedTimes()`](https://jestjs.io/docs/expect#tohavereturnedtimesnumber)
---
- 🔴
- [`.toHaveReturnedWith()`](https://jestjs.io/docs/expect#tohavereturnedwithvalue)
---
- 🔴
- [`.toHaveLastReturnedWith()`](https://jestjs.io/docs/expect#tohavelastreturnedwithvalue)
---
- 🔴
- [`.toHaveNthReturnedWith()`](https://jestjs.io/docs/expect#tohaventhreturnedwithnthcall-value)
---
- 🔴
- [`.toBeCloseTo()`](https://jestjs.io/docs/expect#tobeclosetonumber-numdigits)
---
- 🟢
- [`.toBeGreaterThan()`](https://jestjs.io/docs/expect#tobegreaterthannumber--bigint)
---
- 🟢
- [`.toBeGreaterThanOrEqual()`](https://jestjs.io/docs/expect#tobegreaterthanorequalnumber--bigint)
---
- 🟢
- [`.toBeLessThan()`](https://jestjs.io/docs/expect#tobelessthannumber--bigint)
---
- 🟢
- [`.toBeLessThanOrEqual()`](https://jestjs.io/docs/expect#tobelessthanorequalnumber--bigint)
---
- 🟢
- [`.toBeInstanceOf()`](https://jestjs.io/docs/expect#tobeinstanceofclass) (Bun v0.5.8+)
---
- 🔴
- [`.toContainEqual()`](https://jestjs.io/docs/expect#tocontainequalitem)
---
- 🔴
- [`.toMatch()`](https://jestjs.io/docs/expect#tomatchregexp--string)
---
- 🔴
- [`.toMatchObject()`](https://jestjs.io/docs/expect#tomatchobjectobject)
---
- 🟢
- [`.toMatchSnapshot()`](https://jestjs.io/docs/expect#tomatchsnapshotpropertymatchers-hint) (Bun v0.5.8+)
---
- 🔴
- [`.toMatchInlineSnapshot()`](https://jestjs.io/docs/expect#tomatchinlinesnapshotpropertymatchers-inlinesnapshot)
---
- 🔴
- [`.toThrowErrorMatchingSnapshot()`](https://jestjs.io/docs/expect#tothrowerrormatchingsnapshothint)
---
- 🔴
- [`.toThrowErrorMatchingInlineSnapshot()`](https://jestjs.io/docs/expect#tothrowerrormatchinginlinesnapshotinlinesnapshot)
{% /table %}

View File

@@ -1,7 +1,7 @@
const std = @import("std");
const path_handler = @import("../src/resolver/resolve_path.zig");
const bun = @import("bun");
const bun = @import("root").bun;
const string = bun.string;
const Output = bun.Output;
const Global = bun.Global;

View File

@@ -1,5 +1,5 @@
const std = @import("std");
const bun = @import("bun");
const bun = @import("root").bun;
const string = bun.string;
const Output = bun.Output;
const Global = bun.Global;
@@ -9,18 +9,18 @@ const MutableString = bun.MutableString;
const stringZ = bun.stringZ;
const default_allocator = bun.default_allocator;
const C = bun.C;
pub usingnamespace @import("bun");
pub usingnamespace @import("root").bun;
const clap = bun.clap;
const URL = @import("../src/url.zig").URL;
const Headers = @import("bun").HTTP.Headers;
const Headers = @import("root").bun.HTTP.Headers;
const Method = @import("../src/http/method.zig").Method;
const ColonListType = @import("../src/cli/colon_list_type.zig").ColonListType;
const HeadersTuple = ColonListType(string, noop_resolver);
const path_handler = @import("../src/resolver/resolve_path.zig");
const HTTPThread = @import("bun").HTTP.HTTPThread;
const HTTP = @import("bun").HTTP;
const HTTPThread = @import("root").bun.HTTP.HTTPThread;
const HTTP = @import("root").bun.HTTP;
fn noop_resolver(in: string) !string {
return in;
}

View File

@@ -1,5 +1,5 @@
const std = @import("std");
const bun = @import("bun");
const bun = @import("root").bun;
const string = bun.string;
const Output = bun.Output;
const Global = bun.Global;
@@ -177,7 +177,7 @@ pub const Arguments = struct {
}
};
const HTTP = @import("bun").HTTP;
const HTTP = @import("root").bun.HTTP;
const NetworkThread = HTTP.NetworkThread;
var stdout_: std.fs.File = undefined;

Some files were not shown because too many files have changed in this diff Show More