原文地址:https://css-tricks.com/comparing-the-new-generation-of-build-tools/
在过去的一年里,出现了一批新的开发工具,它们正在紧跟过去几年主导前端开发的工具,包括 webpack、 Babel、 Rollup、 Parcel、 create-react-app。
这些新的工具并不是为了完成完全相同的功能而设计的,每个工具都有不同的目标和功能。尽管存在差异,但这些工具确实有一个共同的目标: 提高开发人员的体验。
具体来说,我想对每一个进行评估,概述它们做什么,为什么我们需要它们,以及它们的用例。我意识到比较并不总是公平的。再次强调,我们在这篇文章中看到的并不是直接的竞争对手。事实上,Snowpack 和 Vite 实际上在某些任务中使用 esbuild。我们的目标更多的是为了更好地了解运行任务以使我们的工作更加容易的开发人员工具。通过这种方式,我们可以看到有哪些选择以及它们是如何叠加起来的,这样我们就可以在需要的时候做出最好的选择。
当然,所有这些都会被我使用 React 和 Preact 的经验所影响。我对这些框架库比较熟悉,但是我们也会看看它们对其他前端框架的支持。
关于这些新的开发工具,已经有很多很棒的文章、流媒体和播客。为了获得更多的背景信息,我推荐几集 ShopTalk Show: Episode 454讨论了 Vite 和 Episode 448,分别介绍了 wmr 和 Snowpack 的创作者。从这些插曲中突出的一点是,大量的工作已经投入到构建这些工具来使我们的开发环境现代化。
Why are these tools all arriving now?为什么这些工具现在都到了?
在某种程度上,我认为这些工具的出现是对 JavaScript 工具疲劳的一种反应---- 在这篇关于2016年学习 JavaScript 的文章中很好地抓住了这一点。它们还填补了一个缺失的中间地带,一方面是编写一个普通的 JavaScript 文件,另一方面是在编写一行自己的代码之前必须下载200mb 的工具附件。它们包括电池——没有依赖列表,是 JavaScript 生态系统崩溃层趋势的一部分。
和 wmr 都是通过浏览器中的原生 JavaScript 模块启用的。早在2018年,Firefox 60发布时默认启用了 ECMAScript 2015模块。从那时起,所有主流的浏览器引擎都支持原生的 JavaScript 模块。还在2019年11月发布了本地 JavaScript 模块。我们仍然在寻找2021年本地 JavaScript 模块解锁的可能性。
How are these different from existing tools?
这些工具与现有工具有何不同?
无论我们使用 webpack、 Rollup 还是 Parcel 作为开发服务器,这个工具都将我们的整个代码库与源代码和一个 node _ modules 文件夹捆绑在一起,通过 Babel、 TypeScript 或 PostCSS 等构建过程运行,然后将捆绑的代码推送到我们的浏览器。这些都需要花费大量的工作,并且会使开发服务器在更大的代码库中慢慢爬行,甚至在所有的工作都用于缓存和优化之后也是如此。
Snowpack、 Vite 和 wmr 开发服务器不遵循这个模型。相反,它们会一直等待,直到浏览器找到一个 import 语句,并为模块发出 HTTP 请求。只有在发出这个请求之后,工具才会将转换应用到请求的模块和模块的导入树中的任何叶节点,然后将这些转换应用到浏览器中。这大大加快了工作速度,因为推送到开发服务器的过程中工作量很少。
你会注意到这张图片中缺少了一个网页。它首先是一个捆绑机。它不会像其他工具那样绕开捆绑。相反,esbuild 通过避免昂贵的转换、利用并行化和使用 Go 语言来极快地编写流程代码。
The experiment
实验
我从 React 文档中选取了一个示例应用程序,并用本文中介绍的每个工具重新构建了它。我参与的项目是 Yogita Verma 的 Snap Shot。这里有一个链接到原来的回购,和一个链接到我的回购与四个版本的管理单元拍摄,每个使用不同的建设工具。稍后我们将比较每个构建步骤的输出。重新构建这个应用程序使我能够测试开发人员在将一些非常标准的 React dependencies 引入到工具中的经验,包括 React Router 和 axios。
Comparable features
类似的功能
在我们详细讨论每个工具之前,它们都支持以下开箱即用的特性(不同程度地) :
- First-class support for native JavaScript modules对原生 JavaScript 模块的一流支持
- TypeScript compilation (but not type checking)编译打字稿(但不进行类型检查)
- JSX联合交易所
- Plugin API for extensibility扩展性插件 API
- A built-in development server内置的开发服务器
- CSS bundling and support for CSS-in-JS librariesCSS 捆绑和对 CSS-in-js 库的支持
所有这些工具都可以将打字稿编译成 JavaScript,但即使存在类型错误也可以这样做。为了进行正确的类型检查,需要安装 TypeScript 并在根 JavaScript 文件上运行 tsc-- noEmit,或者使用编辑器插件来检查类型错误。
好的,让我们来看看每个工具。
esbuild
Esbuild 是由 Evan Wallace (Figma 的 CTO)创建的。它的主要特点是提供了一个比基于 node 的捆绑机快10 ×-100 × 的构建步骤(根据他们自己的基准)。它没有为开发人员提供创建-反应-应用程序之类的方便。但是越来越多的 esbuild 启动器出现了,填补了这些空白,包括 create-react-app-esbuild,estrella 和 Snowpack,它使用 esbuild 作为构建步骤。
Esbuild 是非常新的。它还没有达到1.0版本,还没有完全准备好投入生产使用ーー但也不远了。它为你提供了直观的 JavaScript 和带有智能默认值的命令行 api。
Use cases
用例
Esbuild 完全改变了 bundler 的游戏规则。在大型代码库中,esbuild 和节点捆绑器之间的速度差异会被乘以,这将是最有用的。当 esbuild 达到1.0时,它将在大型生产站点中非常有用,并将为团队节省大量等待构建完成的时间。不幸的是,大型生产站点将不得不等待 esbuild 变得稳定。与此同时,为你的捆绑式副业项目增加一些速度也是不错的。
Esbuild 闪电般的速度,对于你们所做的任何工作,都是一种奖励。减少等待构建运行的时间对开发人员的体验总是有好处的!考虑到这一点,如果你正在构建快速应用程序的原型,你可能希望从比 esbuild 更高层次的应用程序开始,否则,在获得 JavaScript 生态系统所期望的便利之前,你需要花费一些时间来获取依赖关系和配置环境。另外,如果您想尽可能地减小 bundle 的大小,您可能希望使用 Rollup 和 terser,这将产生稍小的 bundle 大小。
Setup
设置
我决定以一种天真的方式启动 esbuild 中的 React 项目: npm 安装 esbuild、 React 和 ReactDOM。我创建了一个 src/app.jsx 文件和一个 dist/index. html 文件。然后,我使用以下命令将应用程序编译成 dist/bundle.js 文件:
代码语言:javascript复制`./node_modules/.bin/esbuild src/app.jsx --bundle --platform=browser --outfile=dist/bundle.js`
当我在浏览器中托管并打开 index. html 时,我遇到了“白屏死机”和“ Uncaught ReferenceError: process is not defined”控制台错误。文档和 CLI 都详细解释了如何避免这种情况的发生,但是对于初学者来说这可能有点“抓住你了”,因为捆绑时需要额外的参数。 React:
代码语言:javascript复制`--define:process.env.NODE_ENV="production"`
或者,如果你在 npm 脚本中包含 esbuild,像这样编写来转义引用:
代码语言:javascript复制`--define:process.env.NODE_ENV=\"production\"`
对于需要节点环境变量的浏览器的任何绑定库,都需要这个 define 参数。Vue 2.0也期待这些。在 Preact 中不会遇到同样的问题,因为它不期望任何环境变量,并且默认情况下提供给浏览器。
在使用 define 参数运行命令之后,我的“ Hello world”React 应用程序运行得非常好。联合材料 x 工程的盒子与。Jsx 档案。也就是说,React 需要手动导入,然后将 JSX 转换为 React.createElement。但是,有一些方法可以在 JSX 中添加自动导入,或者为 Preact 配置 JSX。
(#usage)Usage用法
Esbuild 为开发服务器提供了一个服务选项。这绕过了文件系统,直接从内存服务于模块,确保浏览器不会拖动旧版本的模块。然而,它并不包括实时/热点重载,所以你会发现自己在保存之后刷新浏览器,这并不是一个理想的体验。
我决定使用最新发布的手表功能。这告诉 esbuild 在每次保存源文件时重新编译代码。但是我们仍然需要一个服务器来查看我们保存的更改。我们可以引入一个开发服务器包,比如 Luke Jackson 的 servor:
代码语言:javascript复制`npm install servor --save-dev`
然后我们可以使用 esbuild Javascript API 作为服务器启动,同时运行 esbuild 的监视模式。让我们在我们的项目的根目录下创建一个名为 watch.js 的文件:
代码语言:javascript复制// watch.js
const esbuild = require("esbuild");
const servor = require("servor");
esbuild.build({
// pass any options to esbuild here...
entryPoints: ["src/app.jsx"],
outdir: "dist",
define: { "process.env.NODE_ENV": '"production"' },
watch: true,
});
async function serve(){
console.log("running server from: http://localhost:8080/");
await servor({
// pass any options to servor here...
browser:true,
root: "dist",
port: 8080,
});
}
serve();
现在在命令行中运行 node watch.js。这为我们提供了一个很好的开发服务器,但是同样,它并没有提供热模块替换或快速刷新(也就是说,客户端状态不会被保留)。但这对我的测试需求来说已经足够了。
尽管我们每次保存文件时都会重新绑定整个应用程序,但是在 esbuild 变慢之前,我们需要有一个非常庞大的应用程序。在我设置了这个工具之后,我从更改中得到了即时的反馈。我的电脑使用的是2012年的 intel i7,所以它肯定不是一台顶级的电脑。
如果您需要一个带有实时重载和一些 React 默认值的预配置 esbuild 版本,您可以克隆这个 repo。
(#supported-files)Supported files支持的文件
可以在 JavaScript 中导入 CSS,如果这是你的风格的话。它将把 CSS 编译成与主输出 JavaScript 文件同名的输出文件。默认情况下,它还可以捆绑 CSS@import 语句。没有对 CSS 模块的支持,但是已经有了相应的计划。
用于 esbuild 的插件社区正在不断壮大。例如,有针对 Vue 单文件组件和 Svelte 组件的插件。
Esbuild 可以使用 JSON 文件,并且可以将它们捆绑到 JavaScript 模块中,而不需要任何配置。
它还可以在 JavaScript 中导入图像,可以选择将图像转换为数据 url,也可以将图像复制到输出文件夹。这个行为在默认情况下不会启用,但是你可以在你的 esbuild 配置对象中添加以下选项来启用这两个选项:
代码语言:javascript复制loader: { '.png': 'dataurl' } // Converts to data url in JS bundle
loader: { '.png': 'file' } // Copies to output folder
代码拆分看起来是一项正在进行的工作,但大多数情况下是以 ESM 输出格式进行的,而且看起来确实是项目的优先事项。还值得一提的是,摇树是默认内置在 esbuild 中的,不能关闭。
(#production-build)Production build生产建设
在 esbuild 命令中使用“ minify”和“ bundle”选项不会创建一个像 Rollup/Terser 管道那么小的 bundle。这是因为 esbuild 牺牲了一些 bundle 大小的优化,以便在尽可能少的传递中完成代码。然而,这种差异可能是微不足道的,值得提高捆绑速度,这取决于您的项目。在我对 Snap Shot 应用程序的克隆中,esbuild 创建了一个177 KB 的包,这个包比 Vite 生成的165KB 大不了多少,Vite 使用了汇总和简洁。
(#overall)Overall整体而言
**esbuild** | |
---|---|
Templates for multiple front end frameworks多个前端框架的模板 | ❌ |
Hot module replacement development server热模块替换开发服务器 | ❌ |
Streaming imports流媒体导入 | ❌ |
Preconfigured production build 预先配置的生产构建 | ❌ |
Automatic PostCSS and preprocessor conversion自动 PostCSS 和预处理器转换 | ❌ |
HTM transformHTM 变换 | ❌ |
Rollup plugin support支持汇总插件 | ❌ |
Size on disk (default install)磁盘大小(默认安装) | 7.34 MB |
Esbuild 是一个非常强大的工具。但是,如果您习惯于零配置设置,这可能会很困难。如果你需要更多,那么你可能想看看下一个工具,Snowpack,它使用 esbuild。
(#snowpack)Snowpack积雪
积雪是由 Skypack 和 Pika 的创造者设计的一个建造工具。它提供了一个非常棒的开发服务器,并且是以“非捆绑式开发”的理念创建的。引用文档中的话: “您应该能够使用捆绑器,因为您想要这样做,而不是因为您需要这样做。”
默认情况下,Snowpack 的构建步骤不会将文件绑定到单个包中,而是提供在浏览器中运行的非绑定 esmodule。实际上 esbuild 是作为一个依赖项包含在其中的,但是我们的想法是使用 JavaScript 模块,并且只在需要的时候与 esbuild 绑定。
有一些非常漂亮的文档,包括一个与 JavaScript 框架一起使用的指南列表,以及一些模板。有些指南还在完善中,但是像 React 这样的指南非常清晰。它看起来也像是雪堆把 Svelte 当成了一个第一类物件。事实上,我第一次听说 Snowpack 是在2020年 Svelte 峰会上 Rich Harris 的“未来网络发展”演讲中。也就是说,即将推出的 Svelte 元框架 SvelteKit 原本应该由 Snowpack 提供支持,但现在已经转向 Vite (我们将在下面对其进行评论)。
(#use-cases)Use cases用例
如果你想在非绑定部署上加倍下注,积雪是个不错的选择。您可能使用少量模块编写源代码。这意味着您不会使用非绑定版本创建一个大的请求瀑布。如果你不需要额外的复杂性和捆绑的技术债务,那么 Snowpack 是一个很好的选择。一个好的用例是,如果您正在增量地将前端框架采用到服务器呈现或静态应用程序中。您可以从节点生态系统中获得尽可能少的工具,但是仍然可以获得声明性前端框架的好处。
其次,我认为 Snowpack 是一个很棒的 esbuild 包装器。如果您想尝试 esbuild,但是又想要一个开发服务器和预先编写的前端框架模板,那么使用 Snowpack 就不会出错。在 Snowpack 配置的构建步骤中启用 esbuild,你就可以开始了。
就目前的情况来看,我认为 Snowpack 不会是像 create-react-app 这样的零配置工具的最佳替代品,因为如果你有一个大型应用程序,并且需要一个超级花哨的优化生产准备构建步骤,那么你需要引入插件并自己配置它们。
(#setup)Setup设置
让我们跳到命令行,用 Snowpack 开始一个项目:
代码语言:javascript复制mkdir snowpackproject
cd snowpackproject
npm init #fill with defaults
npm install snowpack
现在,让我们在 package.json 中添加以下内容:
代码语言:javascript复制// package.json
"scripts": {
"start": "snowpack dev",
"build": "snowpack build"
},
接下来,我们将创建一个配置文件:
代码语言:javascript复制// Mac or Linux
touch snowpack.config.js
// Windows
new-item snowpack.config.js
我认为 Snowpack 最神奇的部分是在配置文件中设置一个看起来无害的键值对。将其粘贴到配置文件中,例如:
代码语言:javascript复制// Mac or Linux
touch snowpack.config.js
// Windows
new-item snowpack.config.js
远程启用了一种叫做流导入的东西。通过流导入,Snowpack 可以将裸导入(例如,import React from‘ React’;)转换为来自 Skypack 的 CDN 导入,从而绕过 npm 安装。
接下来,让我们创建一个索引文件:
代码语言:javascript复制<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">>
<title>Snowpack streaming imports</title>
</head>
<body>
<div id="root"></div>
<!-- Note the type="module". This is important for JavaScript module imports. -->
<script type="module" src="app.js"></script>
</body>
</html>
最后,我们将添加一个 app.jsx 文件:
代码语言:javascript复制// app.jsx
import React from 'react'
import ReactDOM from 'react-dom'
const App = ()=>{
return <h1>Welcome to Snowpack streaming imports!</h1>
}
ReactDOM.render(<App />,document.getElementById('root')); 0
注意,我们在任何阶段都没有安装 React 或 ReactDOM。但是如果我们像这样启动 Snowpack 开发服务器:
./node_modules/.bin/snowpack dev
我们的应用还能用!
Snowpack 没有从 node _ modules 文件夹下拉 npm 包,而是从 Skypack 下拉 npm 包,这是一个包含 npm 注册表的 CDN,它经过了预先优化,可以在浏览器中工作。然后,积雪把它装在一个。/_ snowpack/pkg URL.
(#usage)Usage用法
这是远离基于 Node/npm 的工作流的一大步,我们实际看到的是一个新的 CDN/JavaScript 模块化的工作流。
然而,如果我们的应用程序按原样运行并运行一个生产版本,Snowpack 会抛出一个错误。这是因为它需要知道在构建时使用 React 和 ReactDOM 的哪个版本。你可以通过写一个 snowpack.deps.json 来解决这个问题,它可以通过运行以下命令自动创建:
./node_modules/.bin/snowpack add react ./node_modules/.bin/snowpack add react-dom
这不会从 npm 下载软件包,但是它会记录 Snowpack 构建所使用的软件包的版本。
一个警告是,我们错过了开发人员错误消息,因为 Skypack 将发送生产版本的包。
即使我们不使用流导入,Snowpack 开发服务器也会将 node 模块的每个依赖项捆绑到一个 JavaScript 文件中,将这些文件转换成本地 JavaScript 模块,然后提供给浏览器。这意味着浏览器可以缓存这些脚本,并且只有在它们发生更改时才重新请求它们。开发服务器在保存时自动刷新,但不保留客户端状态。无论是使用遗留模块格式还是使用节点 api (比如我们在 esbuild 中遇到的问题 process.env) ,来自节点的所有依赖关系似乎都可以马上解决。
在 React 中保存客户端状态需要 React-refresh,这需要一些 Babel 包作为依赖项。默认情况下不包括这些,但是可以使用更多的最大化反应模板。该模板引入 React-refresh、 Prettier、 Chai 和 React Testing Library,总体 Node 依赖包的容量为80mb:
npx create-snowpack-app my-react-project --template @snowpack/app-template-react
(#supported-files)Supported files支持的文件
支持 JSX,但是同样,只支持。默认情况下使用 jsx 文件。如果使用 React 或 Preact,Snowpack 会自动检测,并相应地决定使用哪个呈现函数进行 JSX 变换。然而,如果我们想要定制比这更进一步的 JSX,我们需要通过他们的插件拉入 Babel。还有一个 Snowpack 插件可用于 Vue 单文件组件,当然也可用于 Svelte 组件。此外,Snowpack 编译了打字稿,但是对于类型检查我们需要打字稿插件。
可以导入到 JavaScript 中,并且在运行时被抛入到文档 < head > 中。CSS 模块也支持开箱即用的作用域,只要它们具有。模块化 css 扩展。
导入的 JSON 文件将被强制转换为一个 JavaScript 模块,该模块使用一个对象作为默认导出。Snowpack 支持图片并将其复制到生产文件夹中。与其非捆绑的理念一样,Snowpack 在捆绑中不包含图片作为数据 url。
(#production-build)Production build生产建设
默认的 snowpack build 命令基本上将确切的源文件结构复制到输出文件夹中。用于编译成 JavaScript 的文件(例如: TypeScript、 JSX、 JSON、。真的吗。Svelte) ,它将每个单独的文件转换为一个单独的浏览器友好的 JavaScript 模块。
这种方法工作得很好,但对于生产来说并不好,因为如果源代码被分割成许多文件,那么可能会导致请求的大瀑布。在 Snap Shot 应用程序中,我最终得到了184KB 的源文件,这些文件会请求另外105kb 的来自 Skypack 的依赖项,这就形成了一个非常巨大的瀑布。
然而,Snowpack 将 esbuild 作为一个依赖项,我们可以通过在 Snowpack 配置中添加一个“优化”对象来使 esbuild 捆绑、缩小和编译我们的代码:
代码语言:javascript复制// snowpack.config.js
module.exports = {
optimize: {
bundle: true,
minify: true,
target: 'es2018',
},
};
这使用 esbuild 提供的优化特性运行代码,因此只需添加这些选项,我们就可以得到与前面使用 esbuild 时相同的构建。
由于 esbuild 还没有达到1.0,Snowpack 建议使用 webpack 或 Rollup 插件进行生产构建,这两者都需要配置。
(#overall)Overall整体而言
Snowpack 提供了轻量级开发人员体验,包括功能齐全的开发服务器、详细的文档和易于安装的模板。您可以决定是否要捆绑应用程序以及如何捆绑应用程序。如果您想要一个既能提供开发服务器又能提供更加固执的构建步骤的工具,那么您可能需要查看一下 Vite,这是我们列表中的下一个工具。
**Snowpack积雪** | |
---|---|
Templates for multiple front end frameworks多个前端框架的模板 | ✅ |
Hot module replacement development server热模块替换开发服务器 | ✅ (when using templates)Something (在使用模板时) |
Streaming imports流媒体导入 | ✅ |
Preconfigured production build 预先配置的生产构建 | ❌ |
Automatic PostCSS and preprocessor conversion自动 PostCSS 和预处理器转换 | ❌ |
HTM transformHTM 变换 | ❌ |
Rollup plugin support支持汇总插件 | ✅ (when using Something (使用时[snowpack-plugin-rollup-bundle](https://github.com/ParamagicDev/snowpack-plugin-rollup-bundle) for build step)构建步骤) |
Size on disk (default install)磁盘大小(默认安装) | 16 MB16mb |
(#vite)Vite
Vite 是由 Vue creator (和 Hades speedrunner) Evan You 开发的。Esbuild 专注于构建步骤,Snowpack 专注于开发服务器,Vite 提供两者: 一个完整的开发服务器和一个使用 Rollup 的优化构建命令。
(#use-cases)Use cases用例
如果你想要一个严肃的创建-反应-应用程序或 Vue CLI 的竞争对手,Vite 是最接近的一个,因为它带有电池的功能。快速的开发服务器和零配置优化的生产构建意味着您可以从零到生产不需要任何配置。Vite 是一个工具,可用于微小的副项目或大型生产应用程序。对于 Vite 来说,一个很好的用例就是任何一个可观的单页应用程序。
你为什么不用 Vite?Vite 是一个固执己见的工具,你可能不同意它的观点。您可能不希望在构建时使用 Rollup (我们已经讨论过 esbuild 的速度有多快) ,或者您可能希望您的工具能够为您提供 Babel、 eslint 以及开箱即用的 webpack 装载器生态系统的全部功能。
此外,如果您想要零配置服务器端呈现元框架,那么在 Vite 服务器端呈现的故事更完整之前,您最好继续使用基于 webpack 的框架,如 Nuxt.js 和 Next.js。
(#setup)Setup设置
比起 esbuild 和 Snowpack,Vite 有更多自以为是的默认值。它的文件是清楚和详细的。我们得到了对 Vue 的全力支持,因为 Evan 是创建者,所以 Vite 对 Vue 开发人员来说无疑是一条快乐的道路。也就是说,Vite 可以与任何前端框架一起使用,甚至可以提供一个模板列表来帮助您入门。
(#usage)Usage用法
的开发服务器非常强大。Vite 将一个项目的所有依赖关系预先捆绑到一个带有 esbuild 的本地 JavaScript 模块中,然后通过一个大量缓存的 HTTP 标头提供服务。这意味着在加载第一个页面之后,不会浪费时间编译、服务或请求导入的依赖项。Vite 还提供了清晰的错误消息传递,打印准确的代码块和排除故障的行号。对于 Vite,我没有遇到任何拉入使用节点 api 或遗留格式的依赖关系的问题。它们似乎都被嵌入了一个浏览器可接受的 esmodule。
的 React 和 Vue 模板都引入了支持热模块替换的插件。Vue 模板为单个文件组件引入了 Vue 插件,为 JSX 引入了 Vue 插件。React 模板引入了 React-refresh 插件。无论哪种方式,都将为您提供热模块替换和客户端状态保存。当然,他们添加了更多的依赖项,包括 Babel 包,但是,当在 Vite 中使用 JSX 时,Babel 实际上并不是必需的。默认情况下,JSX 的工作方式与 esbuild 相同ー它转换为 React.createElement。它不会自动导入 React,但是可以配置它的行为。
同时,Vite 不支持类似 Snowpack 和 wdo 先生这样的流媒体导入。这意味着 npm-像往常一样安装依赖项。
一个很酷的事情是,Vite 包含了对服务器端渲染的实验支持。选择您所选择的框架并生成直接发送到客户机的静态 HTML。目前,看起来我们需要自己构建这个架构,但是,这仍然是一个在 Vite 之上构建元框架的好机会。已经有一个名为 viteppress 的工作在进行中,它可以用 Vite 的好处来替代 vueppress。同时,Sveltekit 也将 Vite 添加到了它的依赖列表中。看起来 CSS 代码分割包含是 Sveltekit 转向 Vite 的部分原因。
(#supported-files)Supported files支持的文件
对于 CSS,Vite 提供了我们所看到的所有工具中最多的特性。它支持捆绑 CSS 导入和 CSS 模块。但是我们也可以 npm 安装 PostCSS 插件并创建一个 PostCSS.config.js 文件,Vite 会自动开始将这些转换应用到 CSS 中。
我们可以安装和使用 CSS 预处理器ーー只需 npm 安装预处理器并将文件重命名为正确的扩展名(例如。Scss)和 Vite 将开始应用相应的预处理器。而且,正如我们在概述中所说的,Vite 支持 CSS 代码分割。
图片导入默认为一个公共 URL,但是我们也可以通过使用?在 URL 字符串末尾的 raw 参数。
JSON 文件可以在源代码中导入,并转换为导出单个对象的 esmodule。我们还可以提供一个命名的导入,Vite 将在 JSON 文件的根字段中查找导入和 treeshake 的其余部分。
(#production-build)Production build生产建设
Vite 使用 Rollup 进行预先配置的生产构建,并进行了大量优化。它有意地提供了一个零配置构建,这对于大多数用例来说应该足够了。
这个版本带有我们期望的 Rollup 特性: 捆绑、缩小和摇树。但是我们也会得到额外的东西,比如代码分割动态导入和一种叫做“异步块加载”的东西,这是一种花哨的说法,如果我们请求一个导入另一个模块的 JavaScript 模块,构建将被预先优化,以便同时(异步)加载两个模块。
使用 Snap Shot 应用程序运行 Vite 的默认构建我最终得到了一个5KB 的 JavaScript 文件和一个160KB 的 JavaScript 文件(总计为165KB) ,并且项目中的所有 CSS 都被自动缩小为一个2.71 KB 的小文件。
(#overall)Overall整体而言
固执己见的性质使其成为我们当前工具的一个严重的竞争对手。许多工作已经完成,使开发人员的体验真正无缝,并使生产准备构建的盒子。
**Vite** | |
---|---|
Templates for multiple front end frameworks多个前端框架的模板 | ✅ |
Hot module replacement development server热模块替换开发服务器 | ✅ (when using templates)Something (在使用模板时) |
Streaming imports流媒体导入 | ❌ |
Preconfigured production build 预先配置的生产构建 | ✅ |
Automatic PostCSS and preprocessor conversion自动 PostCSS 和预处理器转换 | ✅ |
HTM transformHTM 变换 | ❌ |
Rollup plugin support支持汇总插件 | ✅ |
Size on disk (default install)磁盘大小(默认安装) | 17.1 MB |
(#wmr)wmr先生
与 Vite 一样,wmr 是另一个固执的构建工具,它既提供了开发服务器,也提供了构建步骤。它是由 Preact 的创建者 Jason Miller 建造的,所以对于 Preact 开发者来说,这无疑是一条快乐的道路。当杰森 · 米勒作为嘉宾出现在 JS Party 播客上时,他解释了先生背后的想法:
Preact 很小,如果你想做一个轻量级的项目,它真的很好。我们的工具在哪里?我们有一个基于 webpack 的工具,在生产中被一些高知名度的网站使用,但那是重量级的工具。原型开发工具在哪里?那是一只手。另一方面是我自己和其他一些碰巧在 Preact 团队中的人; 我们已经有一段时间处于捆绑器生态系统的边缘,敦促人们,试图就一个方向达成共识,我们可以进一步推进编写现代代码和发布现代代码的想法。
这告诉我们,wmr 完全是关于编写和发布现代代码,从而在项目中实现更轻量级的工具。
你可能想知道“先生”代表什么?没什么!“ Web 模块运行时”和“湿模块替换”的名称是浮动的,但它是一个假的缩写,类似于 npm。
Wmr 先生与 Preact 一样使用了无情的 bundle 大小清洗,所以它很小ーー重量只有2.6 MB ーー并且包含正好为零的 npm 依赖项。尽管如此,它还是包含了许多非常棒的特性,包括一个热模块替换开发服务器和一个优化的生产构建。
(#use-cases)Use cases用例
如果我想尽快使用 Preact 创建一个原型,我会使用 wmr。没有配置,下载只需要几秒钟。这感觉就像使用一个增压静态文件服务器。通过优化构建步骤 TypeScript 和静态 HTML 呈现,wmr 提供了发布中小型应用程序所需的一切。它的小尺寸也非常适合快速尝试一个库或演示一个想法。
如果您不使用 Preact、 React 或 vanilla JavaScript,那么 wmr 可能不是您的工具。Preact 团队还没有为其他框架提供模板。文档也不像我们看到的其他工具那样详细。这意味着你离快乐的道路越远,你就会越深入地挖掘源头。因此,如果需要大量的定制,我不能推荐它。
(#setup)Setup设置
如果您使用 preact,那么除了快速安装 npm 之外,绝对不需要任何安装。使用 React with wmr 而不是 Preact,目前有两个步骤。首先,alias htm/preact to htm/react,and react to es-react in your package.json:
代码语言:javascript复制"alias": {
"htm/preact": "htm/react",
"react": "es-react"
},
然后添加来自 es-react 的导入到组件中:
代码语言:javascript复制// ReactDOM only needed on root render
import { React, ReactDOM,} from 'es-react';
这意味着我们实际上不使用正常的反应包你可能会习惯,而是拉在反应从 es-反应。这是因为 wmr 依赖于与原生 JavaScript 模块兼容的包。默认情况下,React 不使用本机模块,而是使用一种称为 UMD 模块的较老的模块样式。Es-React 是一个软件包,可以引入 React,但是提供与 web 平台兼容的输出。
这说明了先生使用 web 平台原语的哲学,而不是使用工具来回避和抽象它。
另一个选择是在我们的应用程序中使用 Skypack 导入,它也经过了预先优化,可以在浏览器中使用:
代码语言:javascript复制import React from 'https://cdn.skypack.dev/react';
import ReactDOM from 'https://cdn.skypack.dev/react-dom';
Wmr 先生希望你正在编写在浏览器中运行的现代代码,这意味着如果你引入使用节点 api 或遗留模块系统的依赖项,你可能需要做一些配置。为了让 Snap Shot 应用程序正常工作,我需要深入到节点模块中,并转换一两个库来使用本地 JavaScript 模块语法。如果您使用较旧的库,这可能会降低您的速度。所有的 Preact 生态系统都在浏览器中进行了优化,不需要任何按摩。这也是为什么我们要坚持先生的快乐道路的原因。
先生的插件。它公开了一个插件 API,支持构建步骤的 Rollup 插件。文档中有越来越多的特定于先生的例子,包括一个缩小 HTML 的插件和一个基于文件系统路由的插件。
Wmr 先生支持不同的框架,但是没有为它们预先构建的模板。起初,我发现配置 JSX 转换相当困难。尽管如此,Jason 已经确认有计划使 JSX 更具可配置性,并且 wmr 打算成为框架不可知论者。JSX 计划在常规的 JavaScript 文件中开箱即用。
(#usage)Usage用法
首先,你可以在命令行中运行这个命令:
npm init wmr your-project-name
或者,你也可以运行这些命令手动构建你的应用程序:
代码语言:javascript复制npm init -y
npm install wmr
mkdir public
touch public/index.html
touch public/index.js
然后在索引的主体中添加一个脚本导入(同样要确保使用 type = “ module”) :
代码语言:javascript复制<script type="module" src="./index.js"></script>
现在你可以在你的 index.js 文件中写一个 Preact hello world:
代码语言:javascript复制import { render } from 'preact';
render(<h1>Hello World!</h1>, document.body);
最后启动你的开发服务器:
node_modules/.bin/wmr
现在我们有了一个完整的热模块替换开发服务器,它将立即响应对源代码的任何更改。
Wmr 先生在转换 JSX 时使用一个名为 htm 的工具,它提供了一些很棒的好处。假设我们在 wmr 中使用 Preact 来写一个计数器,并且犯了一个错误:
代码语言:javascript复制import { render } from 'preact';
import { useState } from 'preact/hooks';
function App() {
const [count,setCount] = useState(0)
return <>
<button onClick={()=>{setCount(cout 5)}}>Click to add 5 to count</button> // HIGHLIGHT
<p>count: {count}</p>
</>
}
render(<App />, document.body);
Count 在 onClick 处理程序函数中拼写错误,因此运行此函数将导致错误。通常,我们必须依靠工具和源地图来收集关于 bug 位于何处的信息,但是 wmr 采用了不同的解决方案。使用 htm,通过使用带标记的模板文本,可以尽可能接近浏览器中的本机 JSX。所以,在哪里编写 React 或 Preact 代码通常是这样的:
代码语言:javascript复制<MyComponent>I am JSX. I am not actually valid Javascript</MyComponent>
... htm 看起来更像这样:
代码语言:javascript复制html`<${MyComponent}>I am about as close as it gets to JSX as you can get while being able to run in the browser</MyComponent>`
现在,如果我们调试我们的代码并在 DevTools 中打开“ Sources”面板,我们应该会看到一个脚本,它几乎与源代码在编辑器中的样子相同。
通过这种方式,我们可以正确地调查错误在浏览器中的位置,而不必使用 sourcemaps。当然,这个特定的例子是相当不自然的,但是您可以看到这是多么有用,因为这意味着 wmr 在您的开发环境中不需要源映射。
Wmr 先生默认情况下支持流导入,所以 bare 导入将从 npm 注册中心下载。这是通过一个复杂的过程来完成的,该过程检查 npm 包中的所有源代码,删除所有测试和元数据,并将其转换为单个本地 JavaScript 导入。类似于 Snowpack,不用 npm 安装任何东西就可以创建一个复杂的应用程序。事实上,wmr 先生是第一个支持这一观点的工具。
(#supported-files)Supported files支持的文件
至于 wmr 先生支持的其他类型的文件,CSS 文件可以用 JavaScript 导入,CSS 模块也受到支持。
对 Vue 单文件组件或 Svelte 组件没有任何内置支持。然而,wmr 先生的构建步骤可以用 Rollup 插件工作,开发服务器可以用 Polka/Express 中间件配置,因此可以使用这些来将导入转换为 Vue 和 Svelte 组件。实际上,我为 Vue Single file Components 编写了一个小插件来演示如何实现这一点。
在 wmr 中,如果没有插件,我们就不能将图片作为数据 url 导入 JavaScript。相反,我们需要使用语法上正确的 JavaScript 方法导入它们。因此,如果我们在公用文件夹中有一张狗的照片,我们可以将其包含在 Preact 组件中,如下所示:
代码语言:javascript复制function Dog() {
return <img src={new URL('./dog.jpg', import.meta.url)} alt="dog hanging out"></img>
}
一旦构建步骤运行,就可以从发布文件夹复制和访问映像。开发服务器中的图像有热模块替换,因此图像的更改会立即反映在浏览器中。
关于文件支持还有一点需要注意: 可以导入 JSON,并将其转换为 JavaScript 对象以供使用。但是在实际构建应用程序时,我们需要一个 Rollup JSON 插件。
(#production-build)Production build生产建设
Wmr 提供了一个生产构建步骤,其中包括捆绑、缩小和摇树,而没有任何额外的依赖关系。看看 wmr 的源代码,它看起来像是在引擎盖下面使用了 rollup 和 terser,而且这些的缩小版本包含在 wmr 包中。先生的 Snap Shot 应用程序的包是164KB,所以它创建的包只比 Vite 创建的两个 JavaScript 文件的总大小小一点点。
还有一种方法来配置先生是这样的一种方式,它使用 preact-iso 在浏览器上将应用程序渲染为静态 HTML 并加工。这意味着可以将 wmr 用作 Preact 的元框架,类似于 Next.js。
(#overall)Overall整体而言
我喜欢使用 wmr 来原型 React 和 Preact 应用程序的经验。开始使用一个小得离谱的工具感觉很棒,但它为开发人员提供了接近匹配的重量级捆绑机的便利。
**wmr先生** | |
---|---|
Templates for multiple front end frameworks多个前端框架的模板 | ✅ |
Hot module replacement development server热模块替换开发服务器 | ✅ |
Streaming imports流媒体导入 | ✅ |
Preconfigured production build 预先配置的生产构建 | ✅ |
Automatic PostCSS and preprocessor conversion自动 PostCSS 和预处理器转换 | ❌ |
HTM transformHTM 变换 | ✅ |
Rollup plugin support支持汇总插件 | ✅ |
Size on disk (default install)磁盘大小(默认安装) | 2.57 MB |
(#feature-comparison)Feature comparison功能比较
我们刚刚走了很多地方!与其上下滚动这篇文章来比较结果,我在这里编译了所有内容,看看这些工具是如何并排堆积起来的。我甚至为我们没有明确提到的特性添加了额外的比较。
(#use-cases)Use cases用例
**Tool工具** | **Use case用例** |
---|---|
esbuild | Large codebases. Not ready for production yet.大型码基,尚未投入生产 |
Snowpack积雪 | Small applications that don’t need bundling or applications where you want to choose which bundler you use. Also good for incrementally adopting JavaScript frameworks in server-rendered apps. 不需要捆绑的小应用程序,或者需要选择使用哪个捆绑程序的应用程序。在服务器渲染的应用程序中增量地采用 JavaScript 框架也很好 |
Vite | Replacement for Vue CLI/Create-React-App for producing single page applications. This is the happy path for Vue.用于生成单页应用程序的 Vue CLI/Create-React-App 的替换 |
wmr先生 | Prototypes. Good for small- to medium-size apps and can be used for either single page or server-rendered apps. This is the happy path for Preact.原型。适用于中小尺寸的应用程序,可以用于单页或服务器渲染的应用程序。这是 Preact 的幸福之路 |
(#setup)Setup设置
**esbuild** | **Snowpack积雪** | **Vite** | **wmr先生** | |
---|---|---|---|---|
Templates for multiple front end frameworks多个前端框架的模板 | ❌ | ✅ | ✅ | ❌ |
Size on disk (default install)磁盘大小(默认安装) | 7.34 MB | 16 MB16mb | 17.1 MB | 2.57 MB |
Zero-config production buildZero-config 生产构建 | ❌ | ❌ | ✅ | ✅ |
HMR Development Server with zero config零配置的 HMR 开发服务器 | ❌ | ✅ | ✅ | ✅ |
Process.env handling for node packages | ❌ | ✅ | ✅ | ✅ |
(#development-server)Development server开发服务器
**esbuild** | **Snowpack积雪** | **Vite** | **wmr先生** | |
---|---|---|---|---|
Hot module replacement热模块更换 | ❌ | ✅ | ✅ | ✅ |
CSS hot replacement热替换 | ❌ | ✅ | ✅ | ✅ |
npm dependency pre-bundlingNpm 依赖性预捆绑 | ❌ | ✅ | ✅ | ❌ |
Browser error messaging浏览器错误消息 | ❌ | ✅ | ✅ | ❌ |
HTM tranform热媒转型 | ❌ | ❌ | ❌ | ✅ |
(#production-build)Production build生产建设
**esbuild** | **Snowpack积雪** | **Vite** | **wmr先生** | |
---|---|---|---|---|
Output bundle size of Snap Shop appSnap Shop 应用程序的输出捆绑大小 | 177 KB177kb | 184 KB of multiple JavaScript files, plus 105 KB of Skypack CDN dependencies 184 KB 的多个 JavaScript 文件,外加105 KB 的 Skypack CDN 依赖项 | 165 KB (one 5 KB file and one 160 KB file)165 KB (一份5kb 的档案和一份160 KB 的档案) | 164 KB164kb |
Go-based bundling基于围棋的捆绑 | ✅ | ✅ when using esbuild is used in build step在构建步骤中使用 esbuild | ❌ | ❌ |
Preconfigured production build预先配置的生产构建 | ❌ | ❌ | ✅ | ✅ |
Asynchronous chunk loading异步块加载 | ❌ | ❌ | ✅ | ✅ |
Rollup plugin support支持汇总插件 | ❌ | ✅ | ✅ | ✅ |
(#other-features)Other features其他功能
**esbuild** | **Snowpack积雪** | **Vite** | **wmr先生** | |
---|---|---|---|---|
Streaming inputs流输入 | ❌ | ✅ | ❌ | ✅ |
Server-side rendering服务器端呈现 | ❌ | ❌ | ✅ (experimental)(实验性) | ✅ |
CSS Modules模块 | ❌ | ❌ | ✅ | ✅ |
Automatic PostCSS and preprocessor conversion自动 PostCSS 和预处理器转换 | ✅ | ✅ | ✅ | ❌ |
(#wrapping-up)Wrapping up结束了
我很高兴能够用我们刚刚看到的所有工具来构建 JavaScript 应用程序。无论我们是在编写一个小的副项目还是一个大的生产站点,所有这些工具都会加速反馈循环,提高生产力。他们打开了一扇门,问我们在 JavaScript 生态系统中需要什么,以及我们是否可以开始失去传统模块和浏览器带来的 cruft。这些工具提供了一个更精简、更快速的开发环境,在编写的代码和运行在浏览器中的代码之间减少了抽象,从而降低了新开发人员的进入门槛。
如果您厌倦了等待依赖项下载和构建步骤运行,我建议您尝试一下这个新一代的工具。
(#further-reading)Further reading进一步阅读
- “Comparisons with Other No-Bundler Solutions””与其他非打包机解决方案的比较” (Vite)(维特)
- “Let’s Learn esbuild! (with Sunil Pai)”“让我们学习 esbuild! (和 Sunil Pai)” (Jason Lengstorf)(詹森 · 兰斯托夫)
- Through the pipeline: an exploration of frontend bundlers通过管道: 前端捆绑机的探索 (Andrew Walpole)(沃波尔)
(#other-new-javascript-tooling-to-check-out)Other new JavaScript tooling to check out其他新的 JavaScript 工具可以查看
- Rome罗马 – A full toolchain including linting, compiling, bundling, test-running and formatting一个完整的工具链,包括镶边、编译、捆绑、测试运行和格式化
- SWC太阳能热水器 – A rust-based JavaScript/TypeScript compiler- 基于 rust 的 JavaScript/TypeScript 编译器
- Deno女名女子名 – A runtime for JavaScript and TypeScript (similar to Node.js)