你好!这周我一直在写一些 Javascript,和往常一样,当我开始一个新的前端项目时,我面临着一个问题:我应该使用构建系统吗?
我想谈谈构建系统对我有什么吸引力,为什么我(通常)仍然不使用它们,以及为什么我对某些前端 Javascript 库要求您使用构建系统感到沮丧。
我写这篇文章是因为我看到的大多数关于 JS 的文章都假设你正在使用构建系统,对于像我这样编写不需要构建系统的非常简单的小型 Javascript 项目的人来说,这可能很难导航.
什么是构建系统?
这个想法是你有一堆 Javascript 或 Typescript 代码,你想在把它放到你的网站上之前把它翻译成不同的 Javascript 代码。
构建系统可以做很多有用的事情,比如:
- 将 100 个 JS 文件组合成一个大包(出于效率原因)
- 将 Typescript 翻译成 Javascript
- 打字稿
- 缩小
- 添加 polyfill 以支持旧版浏览器
- 编译 JSX
- treeshaking(删除未使用的 JS 代码以减小文件大小)
- 构建 CSS(就像tailwind一样)
- 可能还有很多其他重要的事情
因此,如果您今天要构建一个复杂的前端项目,您可能正在使用像 webpack、rollup、esbuild、parcel 或 vite 这样的构建系统。
许多这些功能对我很有吸引力,我过去曾使用过构建系统,原因如下:例如,Mess With DNS使用esbuild
来翻译 Typescript 并将大量文件组合成一个大文件。
目标:轻松更改旧的微型网站
我做了很多简单的小网站,我对其中任何一个的维护精力都大约为 0,而且我很少更改它们。
我的目标是,如果我有一个 3 或 5 年前创建的网站,我希望能够在 20 分钟内:
- 在新电脑上从 github 获取源代码
- 做一些改变
- 放到网上
但是我在构建系统(不仅仅是 Javascript 构建系统!)方面的经验是,如果您有一个已有 5 年历史的站点,重新构建该站点通常会非常痛苦。
而且因为我的大多数网站都非常小,所以使用构建系统的优势非常小——我真的不需要 Typescript 或 JSX。我只需要一个 400 行的script.js
文件就可以了。
示例:尝试构建 SQL 游乐场
我的网站之一( sql playground )使用构建系统(它使用 Vue)。我最后一次编辑那个项目是在 2 年前,在另一台机器上。
让我们看看我今天是否仍然可以在我的机器上轻松地构建它。首先,我们必须运行npm install
。这是我得到的输出。
$ npm install [lots of output redacted] npm ERR! code 1 npm ERR! path /Users/bork/work/sql-playground.wizardzines.com/node_modules/grpc npm ERR! command failed npm ERR! command sh /var/folders/3z/g3qrs9s96mg6r4dmzryjn3mm0000gn/T/install-b52c96ad.sh npm ERR! CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/surface/init.o npm ERR! CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/avl/avl.o npm ERR! CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/backoff/backoff.o npm ERR! CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/channel/channel_args.o npm ERR! CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/channel/channel_stack.o npm ERR! CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/channel/channel_stack_builder.o npm ERR! CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/channel/channel_trace.o npm ERR! CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/channel/channelz.o
构建grpc
时出现某种错误。没问题。反正我真的不需要那种依赖,所以我可以花 5 分钟把它拆掉并重建。现在我可以npm install
并且一切正常。
现在让我们尝试构建项目:
$ npm run build ? Building for production...Error: error:0308010C:digital envelope routines::unsupported at new Hash (node:internal/crypto/hash:71:19) at Object.createHash (node:crypto:130:10) at module.exports (/Users/bork/work/sql-playground.wizardzines.com/node_modules/webpack/lib/util/createHash.js:135:53) at NormalModule._initBuildHash (/Users/bork/work/sql-playground.wizardzines.com/node_modules/webpack/lib/NormalModule.js:414:16) at handleParseError (/Users/bork/work/sql-playground.wizardzines.com/node_modules/webpack/lib/NormalModule.js:467:10) at /Users/bork/work/sql-playground.wizardzines.com/node_modules/webpack/lib/NormalModule.js:499:5 at /Users/bork/work/sql-playground.wizardzines.com/node_modules/webpack/lib/NormalModule.js:356:12 at /Users/bork/work/sql-playground.wizardzines.com/node_modules/loader-runner/lib/LoaderRunner.js:373:3 at iterateNormalLoaders (/Users/bork/work/sql-playground.wizardzines.com/node_modules/loader-runner/lib/LoaderRunner.js:214:10) at iterateNormalLoaders (/Users/bork/work/sql-playground.wizardzines.com/node_modules/loader-runner/lib/LoaderRunner.js:221:10) at /Users/bork/work/sql-playground.wizardzines.com/node_modules/loader-runner/lib/LoaderRunner.js:236:3 at runSyncOrAsync (/Users/bork/work/sql-playground.wizardzines.com/node_modules/loader-runner/lib/LoaderRunner.js:130:11) at iterateNormalLoaders (/Users/bork/work/sql-playground.wizardzines.com/node_modules/loader-runner/lib/LoaderRunner.js:232:2) at Array.<anonymous> (/Users/bork/work/sql-playground.wizardzines.com/node_modules/loader-runner/lib/LoaderRunner.js:205:4) at Storage.finished (/Users/bork/work/sql-playground.wizardzines.com/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:43:16) at /Users/bork/work/sql-playground.wizardzines.com/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:79:9
这个堆栈溢出答案建议运行export NODE_OPTIONS=--openssl-legacy-provider
来修复这个错误。
这行得通,最后我可以npm run build
来构建项目。
这并不是真的那么糟糕(我只需要删除一个依赖项并传递一个有点神秘的节点选项!),但我不想被那些构建错误所困扰。
对我来说,构建系统不值得用于小型项目
对我来说,对于 500 行的小型项目来说,复杂的 Javascript 构建系统似乎并不值得——这意味着放弃在未来轻松更新项目的能力,以换取一些相当边际的好处。
esbuild 看起来更稳定一点
我想给 esbuild 一个快速的 shoutout:我在 2021 年了解了 esbuild并用于一个项目,目前看来它确实是一种更可靠的构建 JS 项目的方式。
我刚刚尝试在一台新计算机上构建一个我 8 个月前最后一次接触的esbuild
项目,它成功了。但我不能确定我是否能够在 2 年内轻松构建该项目。也许会,我希望如此!
不使用构建系统通常很容易
下面是导入所有库的nginx playground代码部分:
<script src="js/vue.global.prod.js"></script> <script src="codemirror-5.63.0/lib/codemirror.js"></script> <script src="codemirror-5.63.0/mode/nginx/nginx.js"></script> <script src="codemirror-5.63.0/mode/shell/shell.js"></script> <script src="codemirror-5.63.0/mode/javascript/javascript.js"></script> <link rel="stylesheet" href="codemirror-5.63.0/lib/codemirror.css"> <script src="script.js "></script>
这个项目也使用了 Vue,但它只是导入了一个 Javascript 文件——前端没有构建过程。
使用 Vue 的无构建系统模板
一些人问如何在没有构建系统的情况下开始编写 Javascript。当然,如果你愿意,你可以编写 vanilla JS,但我常用的框架是 Vue 3。
这是我为启动没有构建系统的 Vue 3 项目构建的一个小模板。它只有 2 个文件和 ~30 行 HTML/JS。
一些库要求您使用构建系统
这个构建系统的东西最近一直在我的脑海里,因为这周我在一个新项目中使用 CodeMirror 5,我看到有一个新版本,CodeMirror 6。
所以我想——很酷,也许我应该使用 CodeMirror 6 而不是 CodeMirror 5。但是——似乎你不能在没有构建系统的情况下使用 CodeMirror 6(根据这个 github 问题)。所以我将坚持使用 CodeMirror 5。
同样,您过去只能将 Tailwind 作为一个巨大的 CSS 文件下载,但Tailwind 3似乎不再作为一个大 CSS 文件提供,您需要运行 Javascript 来构建它。所以我现在将继续使用 Tailwind 2。
当然,库开发人员有权以他们认为最好的方式分发他们的库——也许分发非构建系统版本会给库增加很多额外的复杂性,而维护者认为不值得。或者,也许库的设计意味着出于某种原因无法分发非构建系统版本。
我希望前端库继续提供非构建系统版本
我当然从未维护过大型 Javascript 库,因此我不会就他们应该做出的设计选择做出任何重大声明。
但我要说的是,对于我的大多数项目来说,使用 JS 构建系统的权衡并不值得,如果我想使用的库继续提供我可以在没有构建的情况下使用的版本,这对我来说会更方便系统。
原文: https://jvns.ca/blog/2023/02/16/writing-javascript-without-a-build-system/