Bun

Bun v0.6.5


Jarred Sumner · 2023 年 5 月 29 日

我們正在招募 C/C++ 和 Zig 工程師,一同打造 JavaScript 的未來!加入我們的團隊 →

上週,我們在 Bun v0.6.0 中推出了全新的 JavaScript 打包器

今天,我們推出了對 CommonJS 的原生執行階段支援、Bun.build() 中更聰明的 CommonJS -> ES 模組轉換、bun run 中的 $npm_lifecycle_event、Bun.serve() 串流檔案的錯誤修正、createConnection (在 node:net 中) 的錯誤修正以及更多內容

curl
npm
brew
docker
curl
curl -fsSL https://bun.dev.org.tw/install | bash
npm
npm install -g bun
brew
brew tap oven-sh/bun
brew install bun
docker
docker pull oven/bun
docker run --rm --init --ulimit memlock=-1:-1 oven/bun

升級 Bun

bun upgrade

原生 CommonJS 執行階段支援

我們已在 Bun 中重新實作 CommonJS 支援,從僅限轉譯器支援改為在執行階段中原生支援。這修正了許多阻礙 npm 套件在 Bun 中運作的錯誤,並提高了與 Node.js 的相容性。

以下是 3 個因此解除封鎖的套件

Vue

先前,導入 Vue 會回報缺少匯出錯誤。感謝原生的 CommonJS 支援,Vue 現在可以開箱即用。

在 Bun v0.6.5 中

輸出
input.js
輸出
3.3.4
input.js
import {version} from "vue";
console.log(version);

在 Bun v0.6.4 及更早版本中

import {version} from "vue";
console.log(version);

> SyntaxError: Import named 'version' not found in module './node_modules/vue/index.mjs'.

Winston logger

先前,嘗試使用 Winston logger 時,Bun 會拋出錯誤。現在,它可以開箱即用。

在 Bun v0.6.5 中

輸出
input.js
輸出
info: What time is the testing at? {"service":"user-service"}
input.js

import winston from "winston";

const logger = winston.createLogger({
  level: "info",
  format: winston.format.json(),
  defaultMeta: { service: "user-service" },
  transports: [
    //
    // - Write all logs with importance level of `error` or less to `error.log`
    // - Write all logs with importance level of `info` or less to `combined.log`
    //
    new winston.transports.File({ filename: "error.log", level: "error" }),
    new winston.transports.File({ filename: "combined.log" }),
  ],
});

//
// If we're not in production then log to the `console` with the format:
// `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
//
logger.add(
  new winston.transports.Console({
    format: winston.format.simple(),
  })
);

logger.log({
  level: "info",
  message: "What time is the testing at?",
});

在 Bun v0.6.4 及更早版本中

1 | import winston from "winston";
2 |
3 | winston.format.json();
   ^
TypeError: undefined is not an object (evaluating 'winston.format.json')
      input.js:3:0

Viem

先前,導入 "viem" 會拋出 ReferenceError。感謝原生的 CommonJS 支援,viem 現在可以如預期載入。

在 Bun v0.6.5 中

輸出
input.js
輸出
[Function: createClient]
input.js
import { createClient } from "viem";
console.log(createClient);

在 Bun v0.6.4 及更早版本中

11 |   if (param.type.startsWith("tuple"))
12 |     return `(${formatAbiParams(param.components, { includeName })})${param.type.slice(5)}`;
13 |   return param.type + (includeName && param.name ? ` ${param.name}` : "");
14 | };
15 |
16 | var {InvalidDefinitionTypeError} = import.meta.require("viem/dist/esm/errors/abi.js");
   ^
ReferenceError: Cannot access uninitialized variable.
        input.js:16:0

具體來說,變更了什麼?

先前,Bun 會將 CommonJS 模組轉譯成如下形式的 ES 模組

// Bun v0.6.4 and earlier wrapper:
import { cjs2ESM } from "bun:wrap";
export default cjs2ESM((module, exports) => {
  /* ...code */
});

另外,所有對這些模組的 import 都會被重寫,以檢查它是否為 CommonJS 模組,如果是,則呼叫該函數並傳回 CommonJS 匯出,而不是 ES 模組匯出。

該步驟有錯誤。在我們解析原始碼之前,我們並不總是知道模組是否為 CommonJS。package.json 有一些提示,但很多時候並不準確。

在 Node.js 中,靜態已知的 CommonJS 匯出會變成具名的 ES 模組匯出。例如,module.exports = { a: 'b' } 會變成 export const a = 'b'。我們忽略了在 Bun 中執行此操作,而是使用轉譯器來重寫 CommonJS 模組的用法,以直接使用 module.exports。這種方法無法正確處理 export * fromexport * as。有時我們也無法偵測到 CommonJS 模組 (或錯誤地假設 ES 模組是 CommonJS)。

因此,我們從頭開始重新實作了所有這些運作方式。

現在,當 Bun 的 JavaScript 執行階段偵測到 CommonJS 模組時

  1. 將模組包裝在一個以 moduleexports 作為參數的函數中。
(function (module, exports, require) {
  /* ...code */
})(module, exports, require);
  1. 執行產生的函數

  2. exports 的屬性附加為具名的 ES 模組匯出。

這表示 export * from '...'export * as ... 可以如預期運作。此外,Bun 現在也支援依賴「寬鬆模式」功能 (如 with) 和隱含全域變數賦值的套件。與之前一樣,您可以繼續在 ES 模組中使用 importrequire

打包器中更聰明的 CommonJS -> ESM 轉換

與執行階段 CommonJS 變更無關,我們也讓 Bun.build() 在將 CommonJS 模組轉換為 ES 模組方面變得更聰明。

bun run 中的 $npm_lifecycle_event

您現在可以在 bun run 腳本中存取 $npm_lifecycle_event$npm_lifecycle_event 環境變數會設定為執行的腳本名稱。這對於偵測執行了哪個 package.json 腳本非常有用。

輸出
input.js
輸出
bun run hey
hey
input.js
console.log(process.env.npm_lifecycle_event);

感謝 @TiranexDev 的貢獻!

Bun.serve() 串流檔案的錯誤修正

Bun 現在全域忽略 SIGPIPE 信號,這修正了一個錯誤,該錯誤會導致在 Linux 上使用 new Response(Bun.file(path)) 串流檔案時,當客戶端提早斷線時 Bun 可能會崩潰。

node:netcreateConnection 的錯誤修正

這修正了 node:net 中的參數解析問題,該問題導致 createConnection 在某些情況下失敗。感謝 @cirospaciari 的貢獻!

轉譯器與打包器錯誤修正

Bun 先前錯誤地將 Symbol["for"] 和其他幾十個透過靜態已知計算屬性字串文字存取的全域無副作用 getter 轉譯為 undefined。此問題已修正。此錯誤是在 Bun v0.6.0 中引入的,並在 v0.6.4 中開始影響 Bun 的 JavaScript 執行階段。感謝 @zloirock 回報此問題。