你的JavaScript可能不需要构建系统

56 阅读6分钟

在没有构建系统的情况下编写JavaScript

当我开始一个新的前端项目时,我总是面临一个问题:是否应该使用构建系统?今天,我想谈谈构建系统对我的吸引力,以及为什么我(通常)仍然不使用它们,以及为什么我觉得有些前端JavaScript库要求你使用构建系统令人沮丧。

我写这篇文章是因为我看到大多数关于JS的文章都假设你使用构建系统,对于像我这样编写非常简单的小型JavaScript项目的人来说,导航可能会有些困难,而这些项目不需要构建系统。

什么是构建系统?

构建系统的概念是,你有一堆JavaScript或TypeScript代码,希望在将其放在网站上之前将其转换为不同的JavaScript代码。

构建系统可以执行许多有用的任务,比如:

  • 将100多个JS文件合并为一个大的捆绑包(出于效率原因)
  • 将TypeScript翻译成JavaScript
  • 对TypeScript进行类型检查
  • 最小化
  • 添加多兼容性支持旧浏览器的polyfills
  • 编译JSX
  • 剪枝(删除未使用的JS代码以减小文件大小)
  • 构建CSS(例如,Tailwind所做的)
  • 还有可能的其他重要任务

因此,如果你今天正在构建一个复杂的前端项目,你可能正在使用像webpack、rollup、esbuild、parcel或vite这样的构建系统。

目标:轻松更改旧的小型网站

我制作了许多小型、简单的网站,我几乎没有为它们中的任何一个提供维护能力,并且我很少更改它们。

我的目标是,如果我有一个在3年或5年前制作的站点,我希望在20分钟内能够:

  • 在新计算机上从GitHub获取源代码
  • 进行一些更改
  • 将其上传到网上

但是,根据我的经验,如果使用构建系统(不仅仅是JavaScript构建系统!),如果你有一个5年前的站点,要使站点重新构建通常会非常麻烦。

而且由于我的大多数网站都很小,使用构建系统的优势相对较小——我不需要TypeScript或JSX。我只需有一个400行的script.js文件,就能搞定。

示例:尝试构建SQL游乐场

我有一个网站(SQL游乐场),它使用构建系统(使用Vue)。我上次编辑该项目是2年前,而且是在不同的计算机上。

让我们看看我今天是否还能轻松在我的计算机上构建它。首先,我们必须运行npm install。下面是我得到的输出。

$ npm install
[很多输出已省略]
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

这里出现了一个错误,显示“error:0308010C:digital envelope routines::unsupported”。这个堆栈溢出答案建议运行export NODE_OPTIONS=--openssl-legacy-provider来修复此错误。

这个方法有效,最后我可以运行npm run build来构建项目。

这并不算太糟糕(我只需要删除一个依赖项并传递一个稍微神秘的节点选项!),但我宁愿不被这些构建错误拖住。

对我来说,对于小项目,构建系统通常不值得

对于我来说,复杂的JavaScript构建系统对于小型500行的项目来说通常并不值得——这意味着为了一些较小的好处而放弃了未来轻松更新项目的能力。

esbuild似乎更加稳定

我想快速提一下esbuild:我在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,但它只使用<script src>来加载Vue——前端没有构建过程。

使用Vue的无构建系统模板

一些人询问如何开始编写没有构建系统的JavaScript。当然,如果你愿意,可以编写纯JS,但我的常用框架是Vue 3。

这是一个我创建的微型模板,用于启动不使用构建系统的Vue 3项目。它只有2个文件和约30行HTML/JS。

一些库要求你使用构建系统

最近我在使用CodeMirror 5进行新项目时考虑到构建系统的问题,并且我看到有一个新版本CodeMirror 6。

因此,我认为——很酷,也许我应该使用CodeMirror 6而不是CodeMirror 5。但是——看起来你不能在没有构建系统的情况下使用CodeMirror 6(根据迁移指南)。因此,我将继续使用CodeMirror 5。

类似地,你以前可以只下载Tailwind作为一个巨大的CSS文件,但是Tailwind 3似乎不再作为一个大的CSS文件提供,你需要运行JavaScript来构建它。因此,我现在将继续使用Tailwind 2。(我知道,我知道,你不应该使用大的CSS文件,但它只有300KB经过gzip压缩,而且我真的不想要构建步骤)

(编辑:看起来Tailwind在2021年发布了一个独立的CLI,这似乎是一个不错的选择)

我不太确定为什么有些库不提供无构建系统版本——也许提供无构建系统版本会给库增加很多额外的复杂性,而维护者认为这不值得。或者也许库的设计意味着由于某种原因不可能分发无构建系统版本。

我想要更多关于无构建系统JavaScript的提示

到目前为止,我的主要策略包括:

  • 在库的网站上搜索“CDN”以查找独立的JavaScript文件
  • 使用unpkg.com查看是否可以使用构建版本的库
  • 托管自己的库版本,而不依赖可能会崩溃的CDN
  • 编写自己的简单集成,而不是引入其他
  • 如果需要用构建工具,那就用esbuild