ESBuild[1]是基于Go语言开发的JavaScript Bundler, 由Figma前CTO Evan Wallace开发, 并且也被Vite用于开发环境的依赖解析和Transform.
SWC[2]则是基于Rust的JavaScript Compiler(其生态中也包含打包工具spack), 目前为Next.JS/Parcel/Deno等前端圈知名项目使用.
因为...
大家可能在日常工作中遇到过, 项目的构建时间随着项目体积和复杂度逐渐递增, 有的时候本地编辑一个项目要等上个大几分钟(此处@Webpack)
这个是ESBuild官网对于其打包10份three.js的速度对比
SWC则宣称其比Babel快20倍(四核情况下可以快70倍)
# 编译
> build-esb
> esbuild ./src/app.jsx --bundle --outfile=out_esb.js --minify
# 构建产物的大小和构建时间
out_esb.js 27.4kb
⚡ Done in 13ms
# 运行产物
node out_esb.js
<h1 data-reactroot="">Hello, world!</h1>
# 编译
> build-wp
> webpack --mode=production
# 构建产物
asset out_webpack.js 25.9 KiB [compared for emit] [minimized] (name: main) 1 related asset
modules by path ./node_modules/react/ 8.5 KiB
./node_modules/react/index.js 189 bytes [built] [code generated]
./node_modules/react/cjs/react.production.min.js 8.32 KiB [built] [code generated]
modules by path ./node_modules/react-dom/ 28.2 KiB
./node_modules/react-dom/server.browser.js 227 bytes [built] [code generated]
./node_modules/react-dom/cjs/react-dom-server.browser.production.min.js 28 KiB [built] [code generated]
./src/app.jsx 254 bytes [built] [code generated]
./node_modules/object-assign/index.js 2.17 KiB [built] [code generated]
# 构建时间
webpack 5.72.0 compiled successfully in 1680 ms
npm run build-wp 2.79s user 0.61s system 84% cpu 4.033 total
# 运行
node out_webpack.js
<h1 data-reactroot="">Hello, world!</h1>
import * as React from 'react'
import * as ReactServer from 'react-dom/server'
const Greet = () => <h1>Hello, world!</h1>
console.log(ReactServer.renderToString(<Greet />))
然后我们来通过Webpack & ESBuild构建它
再来看看swc的编译效率
又是一段简单的ES6代码
// 一些变量声明
const PI = 3.1415;
let x = 1;
// spread
let [foo, [[bar], baz]] = [1, [[2], 3]];
const node = {
loc: {
start: {
line: 1,
column: 5
}
}
};
let { loc, loc: { start }, loc: { start: { line }} } = node;
// arrow function
var sum = (num1, num2) => { return num1 + num2; }
// set
const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
// class
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
yarn compile-babel
yarn run v1.16.0
warning package.json: No license field
$ babel src/es6.js -o es6_babel.js
✨ Done in 2.38s.
yarn compile-swc
yarn run v1.16.0
warning package.json: No license field
$ swc src/es6.js -o es6_swc.js
Successfully compiled 1 file with swc.
✨ Done in 0.63s.
// es6_babel
"use strict";
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
var PI = 3.1415;
var x = 1;
var foo = 1,
bar = 2,
baz = 3;
var node = {
loc: {
start: {
line: 1,
column: 5
}
}
};
var loc = node.loc,
start = node.loc.start,
line = node.loc.start.line;
var sum = function sum(num1, num2) {
return num1 + num2;
};
var s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(function (x) {
return s.add(x);
});
var Point = /*#__PURE__*/function () {
function Point(x, y) {
_classCallCheck(this, Point);
this.x = x;
this.y = y;
}
_createClass(Point, [{
key: "toString",
value: function toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}]);
return Point;
}();
// es6 swc
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for(var i = 0; i < props.length; i++){
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
var PI = 3.1415;
var x = 1;
var foo = 1, bar = 2, baz = 3;
var node = {
loc: {
start: {
line: 1,
column: 5
}
}
};
var loc = node.loc, start = node.loc.start, _loc = node.loc, line = _loc.start.line;
var sum = function(num1, num2) {
return num1 + num2;
};
var s = new Set();
[
2,
3,
5,
4,
5,
2,
2
].forEach(function(x1) {
return s.add(x1);
});
var Point = /*#__PURE__*/ function() {
"use strict";
function Point(x2, y) {
_classCallCheck(this, Point);
this.x = x2;
this.y = y;
}
_createClass(Point, [
{
key: "toString",
value: function toString() {
return "(" + this.x + ", " + this.y + ")";
}
}
]);
return Point;
}();
//# sourceMappingURL=es6_swc.js.map
从上面的数据可以看出
在打包代码的对比, ESBuild的速度(20ms)远快于Webpack(1680ms)
在编译代码的对比, swc也对babel有比较明显的性能优势(0.63s vs 2.38s).
需要额外说明的是, 用作实例的代码非常简单, 并且在对比中也没有充分使用各个构建工具所有的构建优化策略, 只是对比最基础的配置下几种工具的速度, 这个和各个工具所罗列的benchmark数据会有差异, 并且构建速度也和硬件性能/运行时状态有关.
ESBuild/swc这么快? 那是不是可以直接把Webpack/Babel扔掉了? 也别急, 目前的ESBuild和Swc可能还不能完全替代Webpack. 但是通过这篇分享我们也许可以对它们有一个更全面的认知, 也可以探索后边在工作中使用这些新一代前端工具的机会
由Go实现并编译成本地代码: 多数Bundler都是由JavaScript实现的, 但是CLI应用对于JIT编译语言来说是性能表现最不好的。每次运行Bundler的时候, JS虚拟机都是以第一次运行代码的视角来解析Bundler(比如Webpack)的代码, 没有优化信息. 当ESBuild在解析JavaScript的时候, Node还在解析Bundler的JS代码
重度使用并行计算: Go语言本身的设计就很重视并行计算, 所以ESBuild对这一点会加以利用. 在构建中主要有三个环节: 解析(Parsing), 链接(Linking)和代码生成(Code generation), 在解析和代码生成环节会尽可能使用多核进行并行计算
ESBuild 中的一切代码从零实现: 通过自行实现所有逻辑来避免第三方库带来的性能问题, 统一的数据结构可以减少数据转换开销, 并且可以根据需要改变架构, 当然最大的缺点就是工作量倍增.
令人想到了SpaceX这家公司, 大量零部件都是自己内部生产, 有效降低生产成本
对内存的高效使用: ESBuild在实现时尽量减少数据的传递以及数据的转换, ESBuild尽量减少了对整体AST的传递, 并且尽可能复用AST数据, 其他的Bundler可能会在编译的不同阶段往复转换数据格式(string -> TS -> JS -> older JS -> string...). 在内存存储效率方面Go也比JavaScript更高效.
# 用CLI方式调用, 将ts代码转化为js代码
echo 'let x: number = 1' | esbuild --loader=ts => let x = 1;
// 用JS模式调用build方法
require('esbuild').buildSync({
entryPoints: ['in.js'],
bundle: true,
outfile: 'out.js',
})
require('esbuild').buildSync({
entryPoints: ['app.js'],
bundle: true,
loader: { '.js': 'jsx' },
outfile: 'out.js',
})
// 来自于官网的插件示范
let envPlugin = {
name: 'env',
setup(build) {
// Intercept import paths called "env" so esbuild doesn't attempt
// to map them to a file system location. Tag them with the "env-ns"
// namespace to reserve them for this plugin.
build.onResolve({ filter: /^env$/ }, args => ({
path: args.path,
namespace: 'env-ns',
}))
// Load paths tagged with the "env-ns" namespace and behave as if
// they point to a JSON file containing the environment variables.
build.onLoad({ filter: /.*/, namespace: 'env-ns' }, () => ({
contents: JSON.stringify(process.env),
loader: 'json',
}))
},
}
// 使用插件
require('esbuild').build({
entryPoints: ['app.js'],
bundle: true,
outfile: 'out.js',
plugins: [envPlugin],
}).catch(() => process.exit(1))
const { ESBuildMinifyPlugin } = require('esbuild-loader')
module.exports = {
rules: [
{
test: /.js$/,
// 使用esbuild作为js/ts/jsx/tsx loader
loader: 'esbuild-loader',
options: {
loader: 'jsx',
target: 'es2015'
}
},
],
// 或者使用esbuild-loader作为JS压缩工具
optimization: {
minimizer: [
new ESBuildMinifyPlugin({
target: 'es2015'
})
]
}
}
# Transpile one file and emit to stdout
npx swc ./file.js
# Transpile one file and emit to `output.js`
npx swc ./file.js -o output.js
# Transpile and write to /output dir
npx swc ./my-dir -d output
swc的核心部分swc/core主要有三种API
swc也推出了swc/wasm模块, 可以让用户在浏览器环境使用wasm进行代码转换
如果你想在Webpack体系下使用swc(替代babel), 也可以使用swc-loader
Bundle
⚠️swc也支持进行打包功能, 但是目前功能还不很完备, 并且在使用中也有不少Bug. 笔者目前在本地尝试用spack打包一个简单的React应用目前还不成功, 还做不到开箱即用
目前swc的Bundle工具叫spack, 后续会改名为swcpack.
打包可以通过spack.config.js[7]文件进行配置
ESBuild/swc是用编译型语言编写的新一代前端工具, 对JS编写的构建工具有系统级的速度优势
ESBuild可以用于编译JS代码和模块打包, swc号称也都可以支持两者但是其打包工具还处于早期开发阶段
目前这两个工具还不能完全替代Webpack等主流工具这些年发展出的庞大生态
当已有的基础设施稳定并且替换成本较大时, 可以尝试渐进式的利用新工具(loader)或者Vite这种基于ESBuild二次封装的构建工具
持续关注前端生态新发展, 利用好开源社区提升研发效率和体验的新工具.
在使用新工具的同时, 了解或参与到其背后的技术原理, Go可以作为服务端语言, Rust可以作为系统编程语言, 学习新语言能打开新天地, 岂不美哉?
ESBuild https://esbuild.github.io/
SWC https://swc.rs/
Vite https://cn.vitejs.dev/
https://blog.logrocket.com/using-spack-bundler-in-rust-to-speed-up-builds/
https://datastation.multiprocess.io/blog/2021-11-13-benchmarking-esbuild-swc-typescript-babel.html
https://blog.logrocket.com/webpack-or-esbuild-why-not-both/
[1] ESBuild: https://esbuild.github.io/
[2] SWC: https://swc.rs/
[3] FAQ: https://esbuild.github.io/faq/
[4] 博客: https://swc.rs/blog/perf-swc-vs-babel
[5] esbuild-loader: https://github.com/privatenumber/esbuild-loader
[6] 配置文件: https://swc.rs/docs/configuration/swcrc
[7] spack.config.js: https://swc.rs/docs/configuration/bundling
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/9VaUq9FOm2_nKNCGaH-7rw
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。