前言esbuild是新一代的JavaScript打包工具。他的作者是Figma的CTO——EvanWallace。esbuild以速度快着称,只占用webpack的2%到3%的时间。esbuild项目的主要目标是:开创构建工具性能的新时代,并创建易于使用的现代捆绑器。它的主要功能:无需缓存的极速ES6和CommonJS模块ES6模块的Treeshaking用于JavaScript和GoTypeScript和JSX语法的API源图MinificationPlugins现在很多工具都内置了它,例如众所周知的:vite,snowpack具有esbuild的出色性能,vite就像一只加了翅膀的猛虎,几乎蓄势待发。今天我们将探讨:为什么esbuild如此之快。今日主要内容:几组性能数据对比为什么esbuild这么快?esbuild即将上线的roadmapesbuild在vite中的使用为什么生产环境还需要打包?为什么vite不用esbuild打包?文中总结,先看一组对比:使用10个threeJS生产包,对比默认配置下不同打包工具的打包速度。webpack5排在最后,耗时55.25秒。esbuild只用了0.37秒。差别很大。以及更多比较:webpack5表示很痛:我打不过webpack4?...为什么esbuild这么快?有几个原因。(为保证内容的准确性,以下内容翻译自esbuild官网。)1.Go语言编写,可编译成本地代码。大多数打包器都是用JavaScript编写的,但命令行应用程序对于JIT编译语言的性能最差。每次运行捆绑器时,JavaScriptVM都会看到没有任何优化提示的捆绑器代码。当esbuild忙于解析JavaScript时,node正忙于解析bundler的JavaScript。当节点完成解析加壳代码时,esbuild可能已经退出并且您的加壳器甚至还没有开始加壳。此外,Go是为并行而设计的,而JavaScript不是。Go在线程之间共享内存,而JavaScript必须在线程之间序列化数据。Go和JavaScript都有并行垃圾收集器,但Go的堆是所有线程共享的,而对于JavaScript,每个JavaScript线程中都有一个单独的堆。根据测试,这似乎将JavaScript工作线程的并行度减少了一半,大概是因为一半的CPU内核忙于为另一半收集垃圾。2.大量使用并行操作。esbuild中的算法经过精心设计,可以充分利用CPU资源。大致分为三个阶段:解析链接代码生成解析和代码生成是大部分工作,可以完全并行化(在大多数情况下,链接本质上是一项串行任务)。由于所有线程共享内存,因此在捆绑导入相同JavaScript库的不同入口点时可以轻松共享工作。大多数现代计算机都有多个内核,因此并行性是一个巨大的胜利。3.代码是自己写的,没有使用第三方依赖。自己编写一切,而不是使用第三方库,可以带来很多性能优势。您可以从一开始就牢记性能,您可以确保一切都使用一致的数据结构以避免昂贵的转换,并且您可以在必要时进行大量的架构更改。当然,缺点是需要做更多的工作。例如,许多打包器使用官方的TypeScript编译器作为解析器。然而,它是为了满足TypeScript编译器团队的目标而构建的,并没有将性能放在首位。4.高效利用内存。理想情况下,编译器的复杂度为O(n),具体取决于数据的长度。如果您正在处理大量数据,内存访问速度会严重影响性能。转换数据所需的遍数越少(以及将数据转换成的不同表示形式越少),编译器就会越快。例如,esbuild只触及整个JavaScriptAST3次:用于词法分析、解析、范围界定和声明过程绑定符号的符号,从而精简了语法。例如:将JSX/TS转换为JS,将ES转换为es5。最少的标识符、最少的空间、生成的代码。当AST数据在CPU缓存中仍处于活动状态时,AST数据重用最大化。其他包装商在单独的通道中执行这些步骤,而不是将它们交织在一起。它们还可以在数据表示之间进行转换,将多个库组合在一起(例如:字符串→TS→JS→字符串,然后是字符串→JS→旧JS→字符串,然后是字符串→JS→缩小JS→字符串)。这会使用更多内存并且会减慢速度。Go的另一个好处是它可以将东西紧凑地存储在内存中,从而允许它使用更少的内存并在CPU缓存中容纳更多内容。所有对象字段的类型和字段都紧密地打包在一起,例如几个布尔标志每个只占用一个字节。Go还具有值语义,其中一个对象可以直接嵌入到另一个对象中,因此它是“免费的”,无需额外分配。JavaScript没有这些特性,并且还有其他缺点,例如JIT开销(例如隐藏的类槽)和低效的表示(例如非整数与指针堆分配)。以上每一个因素都可以在一定程度上提高编译速度。当它们一起工作时,效果比当今常用的其他捆绑器快几个数量级。上面的内容比较繁琐,有网友对此做了一个简单的总结:用Go语言写的,可以编译成本地代码。Go很快。一般来说,JS的操作是毫秒级的,而Go是纳秒级的。解析、生成最终包文件、生成sourcemaps等操作都完全并行化,无需昂贵的数据转换,所有操作只需几步即可完成。该库以提高编译速度为编写代码的首要原则,并尽量避免不必要的内存分配。仅供参考。Upcomingroadmap的以下功能已经在进行中,它们是首要任务:代码拆分(#16,文档)CSS内容类型(#20,文档)插件API(#111)以下担心更有用的潜力,但还不确定:HTML内容类型(#31)降为ES5(#297)捆绑顶级await(#253)有兴趣的可以继续关注。esbuild在vite中的使用esbuild在vite中应用广泛,这里简单分享两个点。optimirmport{build,BuildOptionsasEsbuildBuildOptions}from'esbuild'//...constresult=awaitbuild({entryPoints:Object.keys(flatIdDeps),bundle:true,format:'esm',external:config.optimizeDeps?.排除,logLevel:'错误',拆分:true,sourcemap:true,outdir:cacheDir,treeShaking:'ignore-annotations',图元文件:true,定义,插件:[...plugins,esbuildDepPlugin(flatIdDeps,flatIdToExports,config)],...esbuildOptions})constmeta=result.metafile!//`meta.outputs`中的路径是相对于`process.cwd()`constcacheDirOutputPath=path.relative(process.cwd(),cacheDir)for(constidindeps){constentry=deps[id]data.optimized[id]={文件:normalizePath(path.resolve(cacheDir,flattenId(id)+'.js')),src:entry,needsInterop:needsInterop(id,idToExports[id],meta.outputs,cacheDirOutputPath)}}writeFile(dataPath,JSON.stringify(data,null,2))处理.ts文件为什么生产环境还需要打包?尽管现在原生ESM得到了广泛支持,但由于嵌套导入导致的额外网络往返,在生产环境中发布未打包的ESM仍然效率低下(即使使用HTTP/2)为了在生产中获得最佳加载性能,最好使用tree-shake、延迟加载和块拆分您的代码(以获得更好的缓存)。确保开发服务器和生产构建之间的最佳输出和行为并不容易。为了解决这个问题,Vite自带了一套开箱即用的构建优化构建命令。为什么vite没有和esbuild一起打包?虽然esbuild的速度出奇地快,并且已经是构建库的优秀工具,但构建应用程序的一些重要功能仍在开发中——特别是代码拆分和CSS处理。目前来看,Rollup在应用打包方面更加成熟和灵活。不过,等未来这些功能稳定下来后,不排除使用esbuild作为productionbuilder。综上所述,esbuild带来了提升构建效率的希望,esm的数量也在快速增加:希望esm生态尽快完善,造福前端。--今天的内容就这些,希望对大家有所启发。文中如有错误,请指正,谢谢。参考链接https://esbuild.github.io/get...https://esbuild.github.io/faq/https://twitter.com/skypackjs...
