【AICon】探索RAG 技术在实际应用中遇到的挑战及应对策略!AICon精华内容已上线73%>>> 了解详情
写点什么

Bun 发布全新 Bundler:比 Webpack 快 220 倍

作者:Jarred Sumner

  • 2023-05-30
    北京
  • 本文字数:5580 字

    阅读完需:约 18 分钟

Bun发布全新Bundler:比Webpack快220倍

Bun 的高速原生 bundler 目前正处于 beta 阶段。大家已经可以通过 bun build CLI 命令或者新的 Bun.build() JavaScript API 抢先体验。



在带 sourcemaps 和 minification 的情况下,从零开始捆绑 10 个 three.js 副本


通过内置的 Bun.build() 函数或者 bun build CLI 命令用这款 bundler 构建前端应用。


Bun.build({  entrypoints: ['./src/index.tsx'],  outdir: './build',  minify: true,  // additional config});
复制代码


降低 JavaScript 复杂性


JavaScript 最初只负责自动填充表单字段,如今却在多年发展之后成了众多关键场景内的开发手段,甚至负责驱动火箭发射项目的地面控制台。


相应的,JavaScript 生态系统的复杂性也呈现出爆发式增长。我们该如何运行 TypeScript 文件?如何构建 / 捆绑生产代码?软件包是否适用于 ESM?如何加载仅限本地的配置?需不需要安装相应的依赖项?如何让 sourcemaps 顺利起效?需要烦恼的问题实在太多。


复杂性是效率的大敌,导致我们得花很长时间把工具组合起来,或者坐等处理完成。npm 包的安装速度很慢,测试消耗的时间也远比预想的长。既然 2003 年的时候只需要几毫秒就能把文件上传到 FTP 服务器,2023 年部署软件反倒还需要好几分钟?


多年以来,我一直对 JavaScript 缓慢的运行速度感到沮丧。如果测试变更甚至是保存文件所消耗的时间都足够我们看几眼 Hacker News,那肯定是哪里出了大问题。


倒不是说复杂性就不该存在。Bundlers 和 minifiers 让网站的加载速度圩快,TypeScript 的编辑器内交互文档则提升了开发人员的工作效率。类型安全有助于在实际报错前就提出警告,而作为版本化包形式的依赖项也要比以往的复制文件更易于维护。


但 Unix 的基本理念就是“集中精力做好一件事”,但这“一件事”被多种孤立工具所割裂时,理念也将随之崩溃。


正因为如此,我们决定打造 Bun,并在今天高兴地向大家介绍刚刚推出的 Bun bundler。


没错,一款全新 bundler


使用这款新的 bundler,Bun 生态系统将捆绑雕琢成了一流元素,具体涵盖 bun build CLI 命令、新的顶级 Bun.build 函数,还有稳定的插件系统。


之所以决定打造 Bun 的专有 bundler,主要是考虑到以下几个原因。


集成度更好


Bundlers 是一种元工具,能够协调并启用所有其他工具,包括 JSX、TypeScript、CSS 模块和服务器组件等——所有这一切都需要 bundler 的集成才能工作。


现如今,bundlers 已经成为 JavaScript 生态系统中巨大复杂性的来源。通过向 JavaScript 运行时内引入新捆绑机制,我们相信能够让前端和全栈代码的交付变得更简单、更快捷。


  • 快速插件。插件将在快速启动的轻量化 Bun 进程内执行。

  • 无冗余转译。使用 target:”bun”,新 bundler 就能生成面向 Bun 运行时进行优化的预转译文件,从而提高运行性能并避免不必要的重新转译。

  • 统一插件 API。Bun 提供统一的插件 API,能够与 bundler 和运行时配合使用。任何扩展 Bun 捆绑功能的插件亦可用于扩展 Bun 的运行时功能。

  • 运行时集成。构建会返回一个 BuildArtifact 对象数组,这些对象将实现 Blob 接口,并可被直接传递至 HTTP API,例如 new Resonpse( )。运行时还为 BiuildArtifact 实现了非常精美的输出效果。

  • 独立的可执行文件。此 bundler 可以通过—compile 标志在 TypeScript 和 JavaScript 脚本中生成独立的可执行文件。这些可执行文件是完全独立的,包括 Bun 运行时副本。


bundler 还将很快与 Bun 的 HTTP 服务器 API(Bun.serve)相集成,从而利用简单的声明性 API 表达当前复杂的构建管线。这一点将在后文中具体介绍。


性能表现


性能当然有所提高。作为运行时,Bun 的代码库已经包含了快速解析和转换源代码的基础成果(在 Zig 中实现)。但问题是其很难与现有原生 bundler 相集成,而且进程间通信所引发的额外开销还会损耗性能。


而新 bundler 没有让我们失望。在基准测试中(esbuild 的 three.js 基准测试),Bun 比 esbuild 快 1.75 倍,比 Parcel 2 快 150 倍,比 Rollup + Terser 快 180 倍,比 Webpack 快 220 倍。


开发者体验


回顾原有 bundlers 的 API,我们发现其中仍有巨大的改进空间。没人喜欢被 bundler 的配置工作消耗宝贵精力,因此 Bun bundler 的 API 设计中着重强调了清晰易用。


API


API 目前遵循设计最小化的理念。我们的初始版本希望能在不牺牲性能的情况下,提供一个速度快、稳定性佳、可适应大多数现代用例的最小功能集。


下面来看目前的 API:


interface Bun {  build(options: BuildOptions): Promise<BuildOutput>;}interface BuildOptions {  entrypoints: string[]; // required  outdir?: string; // default: no write (in-memory only)  target?: "browser" | "bun" | "node"; // "browser"  format?: "esm"; // later: "cjs" | "iife"  splitting?: boolean; // default false  plugins?: BunPlugin[]; // [] // see https://bun.sh/docs/bundler/plugins  loader?: { [k in string]: string }; // see https://bun.sh/docs/bundler/loaders  external?: string[]; // default []  sourcemap?: "none" | "inline" | "external"; // default "none"  root?: string; // default: computed from entrypoints  publicPath?: string; // e.g. http://mydomain.com/  naming?:    | string // equivalent to naming.entry    | { entry?: string; chunk?: string; asset?: string };  minify?:    | boolean // default false    | { identifiers?: boolean; whitespace?: boolean; syntax?: boolean };}
复制代码


其他很多 bundler 为了追求功能完备性,而做出了很多糟糕的架构决策,最终导致整体性能下降。而我们正努力避免重蹈覆辙。


模块系统


目前仅支持 format: "esm"格式。我们打算后续逐步添加对其他模块系统和目标(如 iife)的支持。如果大家确有需求,我们也会考虑添加 cjs otuput 支持(支持 CommonJS 输入,但不支持输出)。


目标


我们目前支持三个“targets”目标,分别为“browser”(默认)、“bun”和“node”。


browser


  • TypeScript 和 JSX 将被自动转译为原始 JavaScript。

  • 在有可用模块时,通过 “browser” package.json "exports"执行模块解析。

  • Bun 在浏览器中导入时会自动填充某些 Node.js API,例如 node:crypto,这种行为与 Webpack 4 类似。Bun 自己的 API 目前禁止导入,但我们未来可能会重新考虑这个问题。


bun


  • Bun 和 Node.js APIs 仍受支持且将保持不变。

  • 通过 Bun 运行时所使用的默认解析算法进行模块解析。

  • 生成的捆绑包使用特殊的 // @bun 标注,表明它们是由 Bun 所生成。通过这种方式,Bun 运行时就能意识到该文件在执行前无需重新编译。


node


目前,node 的处理方式等同于 target: “bun”。未来,我们计划自动填充 Bun API,例如 Bun global 和 bun:* 内置模块。


文件类型


新 bundler 支持以下文件类型:


  • .js .jsx .ts .tsx – 各种 JavaScript 和 TypeScript 文件;

  • .txt — 纯文本文件,将被内联为字符串;

  • .json .toml — 这些格式将在编译时被解析并内联为 JSON。


其他一切都将被视为资产,资产会按原本被复制到 outdir,并使用该文件的相对路径或 URL(/images/logo.png)替换导出。


import logo from "./images/logo.png";console.log(logo);
复制代码


插件


与运行时本身一样,新 bundler 在设计上可通过插件实现扩展。实际上,运行时插件和 bundler 插件间没有任何区别。


import YamlPlugin from "bun-plugin-yaml";const plugin = YamlPlugin();// register a runtime pluginBun.plugin(plugin);// register a bundler pluginBun.build({  entrypoints: ["./src/index.ts"],  plugins: [plugin],});
复制代码


构建输出


Bun.build 函数会返回一个 Promise,具体定义为:


interface BuildOutput {  outputs: BuildArtifact[];  success: boolean;  logs: Array<object>; // see docs for details}interface BuildArtifact extends Blob {  kind: "entry-point" | "chunk" | "asset" | "sourcemap";  path: string;  loader: Loader;  hash: string | null;  sourcemap: BuildArtifact | null;}
复制代码


其中 outputs 数组中包含构建所生成的所有文件。每个 artifact 均实现 Blob 接口。


const build = await Bun.build({  /* */});for (const output of build.outputs) {  output.size; // file size in bytes  output.type; // MIME type of file  await output.arrayBuffer(); // => ArrayBuffer  await output.text(); // string}
复制代码


Artifacts 还包含以下附加属性:



与 BunFile 类似,BuildArtifact 对象也可以被直接传递至 new Response( ) 当中。


const build = Bun.build({  /* */});const artifact = build.outputs[0];// Content-Type is set automaticallyreturn new Response(artifact);
复制代码


Bun 运行时在记录 BuildArtifact 对象时会提供更精美的输出效果,让调试过程更加轻松。


// build.tsconst build = Bun.build({/* */});const artifact = build.outputs[0];console.log(artifact);
复制代码


服务器组件


Bun 的 bundler 目前通过—server-components 标志对 React 服务器组件提供实验性支持。我们将在本周之内发布额外的说明文档和示例项目。


摇树机制


Bun bundler 支持对未使用代码进行摇树,且在捆绑过程中始终执行摇树精简。


package.json “sideEffects” 字段


Bun 在 package.json 当中支持"sideEffects": false,相当于提示 bundler 当前包没有副作用,可以积极消除其中的无用代码。


PURE 注释


Bun 支持 PURE 注释:


function foo() {  return 123;}/** #__PURE__ */ foo();
复制代码


由于 foo 没有副作用,因此这会产生一个空文件:output.js。


请参阅 Webpack 说明文档,了解更多细节信息。


https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free


process.env.NODE_ENV 与 --define


Bun 支持 NODE_ENV 环境变量和—define CLI 标志。这些一般用于按特定条件在生产构建中包含代码。


如果 process.env.NODE_ENV 被设置为"production",则 Bun 会自动删除包含在 if (process.env.NODE_ENV !== “production”) { … }中的代码。


if (process.env.NODE_ENV !== "production") {  module.exports = require("./cjs/react.development.js");} else {  module.exports = require("./cjs/react.production.min.js");}
复制代码


ES 模块摇树


ESM 和 CommonJS 输入文件均支持 ESM 摇树。Bun bundler 将在安全的情况下,自动删除 ESM 文件中未使用的导出。


import { foo } from "./foo.js";console.log(foo);
复制代码


未使用的 bar 导出被删除,因此:


// foo.jsvar $foo = 456;console.log($foo);
复制代码


CommonJS 摇树


在某些受限情况下,Bun bundler 会自动以零运行时开销自动将 CommonJS 转换为 ESM。考虑以下简单示例:


import { foo } from "./foo.js";console.log(foo);
复制代码


Bun 会自动将 foo.js 转换为 ESM,并摇树精简未使用的 exports 对象。


// foo.jsvar $foo = 123;// entry.jsconsole.log($foo);
复制代码


注意,在大多数情况下,CommonJS 的动态特性会令摇树难以实现。例如考虑以下三个文件:entry.js、foo.js、bar.js。


// entry.jsexport default require("./foo");
复制代码


Bun 无法在不执行 foo.js 的情况下静态确定其导出(Object.assign 可能被覆盖掉,基本导致无法进行静态分析)。在这种情况下,Bun 不会对 exports 对象执行摇树;相反,它会注入 CommonJS 运行时代码以确保其按预期工作。


CommonJS打包器
复制代码


Sourcemaps


新 bundler 同时支持内联与外部 sourcemaps。


const build = await Bun.build({  entrypoints: ["./src/index.ts"],  // generates a *.js.map file alongside each output  sourcemap: "external",  // adds a base64-encoded `sourceMappingURL` to the end of each output file  sourcemap: "inline",});console.log(await build.outputs[0].sourcemap.json()); // => { version: 3, ... }
复制代码


Minifier


没有 minifier 的 JavaScript bundler 显然是不完整的。新版本引入了 Bun 中内置的全新 JavaScript minifier。使用 minify: true 即可启用 minification 功能,通过以下选项具体配置 minification 行为:


{  minify?: boolean | {    identifiers?: boolean; // default: false    whitespace?: boolean; // default: false    syntax?: boolean; // default: false  }}
复制代码


Minifier 能够删除无用代码、重命名标识符、删除空格并智能压缩和内联常量值。


// This comment will be removed!console.log("this" + " " + "text" + " will" + " be " + "merged");
复制代码


在 React 中使用新 bundler


我们已经更新了以下 React bun create 模板,可在后台使用 Bun.build。运行下列命令,即可构建一个由 Bun bundler 支持的简单 React 项目。


# a React single-page appbun create react ./myapp# a Next.js-like app with a /pages directory# with SSR and client-side hydrationbun create react-ssr ./myapp
复制代码


先睹为快:Bun.App


Bundler 只是我们更多开发计划的前提和基础。在未来几个月中,我们还将发布 Bun.App——一个“超级 API”同,能够将 Bun 的原生高速 bundler、HTTP 服务器和文件系统路由程序融合为统一的整体。


其目标是通过几行代码,轻松使用 Bun 表达任何类型的应用程序:


new Bun.App({ bundlers: [   {     name: "static-server",     outdir: "./out",   }, ], routers: [   {     mode: "static",     dir: "./public",     build: "static-server",   }, ],});app.serve();app.build();
复制代码


此 API 仍在积极讨论当中,后续可能随时有所更改。


参考链接:

https://bun.sh/blog/bun-bundler


相关阅读:

Bun 会是 Webpack 之后的下一件大事吗?

比 Node.js 快三倍,新 JavaScript 运行时 Bun 火了

亲身试用新 JS 运行时 Bun 后,我觉得未来可期

疑为针对最近大火的“Bun”

2023-05-30 10:423386

评论

发布
暂无评论
发现更多内容

为应用赋能!博云容器云产品族正式发布

BoCloud博云

容器 云原生 容器云

以区块链技术推进应急管理体系现代化

CECBC

固定资产投资管理系统解决方案

低代码小观

资产管理 CRM系统 客户关系管理系统 企业设备管理 设备巡检管理系统

uniapp 如何将输入值转成大写

CRMEB

MBTI 剧透人生,你的天选职业是什么?(免费测)

融云 RongCloud

Fastjson官方再次披露高危漏洞,包括rocketmq、jeecg-boot等近15%的github开源项目受影响

墨菲安全

安全 idea插件 Fastjson 依赖漏洞检测 墨菲安全

fastposter v2.8.2 发布 电商海报生成器

物有本末

2021年证券类APP更新迭代监测专题分析(中)发布

易观分析

证券

YARN Federation技术解析及应用

移动云大数据

YARN

智能汽车领域的开源软件供应链安全检测工具分享

墨菲安全

idea插件 工具分享 开源安全 墨菲安全 软件供应链

TreeMap源码分析-新增

zarmnosaj

5月月更

网络攻击盯上民生领域,应对DDoS和APT攻击,如何有效防御?

郑州埃文科技

IP地址 网络资产保护 网络攻击防御

netty系列之:在netty中使用TCP协议请求DNS服务器

程序那些事

Java Netty 程序那些事 5月月更

网页在线帮助中心的搭建策略

小炮

帮助中心

小区适合投放自助洗车机吗?

共享电单车厂家

自助洗车加盟 小区投放自助洗车机

自助手动洗车设备洗车怎么样?

共享电单车厂家

自助洗车加盟 自助洗车机洗车 自助手动洗车设备

如何用Apifox 发送接口请求?

Liam

开发者 测试 后端 开发 Postman

数据库厂家有哪些?排名怎么样?

行云管家

数据库 IT运维 运维审计 数据库审计

互联网通信安全之终端数据保护

融云 RongCloud

数字人民币智慧学生证来了,对于特定群体硬钱包或大有可为

CECBC

重磅首发!火线安全发布《云安全攻防技术期刊》

火线安全

安全 云安全

更全、更精准,美创科技实现Caché数据库M语言精细化审计

美创科技

cache 数据安全 数据库审计

模块二

Geek_2ce415

是开自助洗车店还是传统洗车店好?

共享电单车厂家

自助洗车加盟 开自助洗车店 传统洗车店

避免惊群以及负载均衡的原理与具体实现

C++后台开发

nginx 负载均衡 后端开发 C++后台开发 惊群

《Mybatis 手撸专栏》第9章:细化XML语句构建器,完善静态SQL解析

小傅哥

源码分析 小傅哥 源码学习 手写Mybatis 源码实践

从流量交换到共享联盟,开放银行如何助力金融数字转型?

CECBC

集成底座内外网访问配置说明

agileai

k8s 集成底座 企业服务总线 身份管理平台 主数据平台

等保二级和等保三级的三大区别讲解-行云管家

行云管家

网络安全 等保 等级保护 等保2.0 等保二级

前端监控的搭建步骤,别再一头雾水了!

杨成功

架构 大前端 5月月更

高危!Fastjson反序列化远程代码执行漏洞风险通告,请尽快升级

葡萄城技术团队

json 安全 Fastjson

Bun发布全新Bundler:比Webpack快220倍_大前端_InfoQ精选文章