@wxy
https://linux.cn/article-15666-1.html
This commit is contained in:
Xingyu Wang 2023-03-27 12:05:01 +08:00
parent e24f62e90b
commit 184a0edcac
2 changed files with 195 additions and 226 deletions

View File

@ -0,0 +1,195 @@
[#]: subject: "Writing Javascript without a build system"
[#]: via: "https://jvns.ca/blog/2023/02/16/writing-javascript-without-a-build-system/"
[#]: author: "Julia Evans https://jvns.ca/"
[#]: collector: "lkxed"
[#]: translator: "wxy"
[#]: reviewer: "wxy"
[#]: publisher: "wxy"
[#]: url: "https://linux.cn/article-15666-1.html"
在没有构建系统的情况下编写 Javascript
======
![][0]
嗨!这周我一直在写一些 Javascript和往常一样当我开始一个新的前端项目时我面临的问题是我是否应该使用构建系统
我想谈谈构建系统对我有什么吸引力,为什么我(通常)仍然不使用它们,以及一些前端 Javascript 库要求你使用构建系统时,为什么我觉得这让我感到沮丧。
我写这篇文章是因为我看到的大多数关于 JS 的文章都假定你正在使用构建系统,而对于像我这样的人来说,编写非常简单的、不需要构建系统的小型 Javascript 项目时,构建系统可能反而添加了很多麻烦。
#### 什么是构建系统?
构建系统的思路是,你有一堆 Javascript 或 Typescript 代码,你想在把它放到你的网站上之前把它翻译成不同的 Javascript 代码。
构建系统可以做很多有用的事情,比如:
- (出于效率的考虑)将 100 多个 JS 文件合并成一个大的捆绑文件
- 将 Typescript 翻译成 Javascript
- 对 Typescript 进行类型检查
- 精简化
- 添加 Polyfills 以支持旧的浏览器
- 编译 JSX
- <ruby>摇树优化<rt>Tree Shaking</rt></ruby>(删除不使用的 JS 代码以减少文件大小)
- 构建 CSS像 [tailwind][1] 那样)
- 可能还有很多其他重要的事情
正因为如此,如果你今天正在构建一个复杂的前端项目,你可能会使用 Webpack、Rollup、Esbuild、Parcel 或 Vite 等构建系统。
很多这些功能对我很有吸引力,我过去使用构建系统也是出于这样一些原因: 例如,[Mess With DNS][2] 使用 Esbuild 来翻译 Typescript并将许多文件合并成一个大文件。
#### 目标:轻松地对旧的小网站进行修改
我做了很多简单的小网站([之一][3]、[之二][4]、[之三][5]、[之四][6]),我对它们的维护精力大约为 0而且我改变它们的频率很低。
我的目标是,如果我有一个 3、5 年前做的网站,我希望能在 20 分钟内,
- 在一台新的电脑上从 GitHub 获取源代码
- 做一些修改
- 把它放到互联网上
但我对构建系统(不仅仅是 Javascript 构建系统!)的经验是,如果你有一个 5 年历史的网站,要重新构建这个网站会非常痛苦。
因为我的大多数网站都很小,所以使用构建系统的 *优势* 很小 —— 我并不真的需要 Typescript 或 JSX。我只要有一个 400 行的 `script.js` 文件就可以了。
#### 示例:尝试构建 SQL 实验场
我的一个网站([SQL 试验场][5])使用了一个构建系统(它使用 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
```
[这个 Stack Overflow 的答案][7] 建议运行 `export NODE_OPTIONS=--openssl-legacy-provider` 来解决这个错误。
这很有效,最后我得以 `npm run build` 来构建这个项目。
这其实并不坏(我只需要删除一个依赖关系和传递一个略显神秘的 Node 选项!),但我宁愿不被那些构建错误破坏。
#### 对我来说,对于小项目来说,构建系统并不值得
对我来说,一个复杂的 Javascript 构建系统对于 500 行的小项目来说似乎并不值得 —— 它意味着放弃了在未来能够轻松更新项目的能力,以换取一些相当微小的好处。
#### Esbuild 似乎更稳定一些
我想为 Esbuild 大声叫好: 我 [在 2021 年了解到 Esbuild][8],并用于一个项目,到目前为止,它确实是一种更可靠的构建 JS 项目的方式。
我刚刚尝试在一台新电脑上构建一个我最后一次改动在 8 个月前的 Esbuild 项目,结果成功了。但我不能肯定的说,两年后我是否还能轻松的建立那个项目。也许会的,我希望如此!
#### 不使用构建系统通常是很容易的
下面是 [Nginx 实验场][6] 代码中导入所有库的部分的样子:
```
<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。
[这是我做的一个小模板][9],用于启动一个没有构建系统的 Vue 3 项目。它只有 2 个文件和大约 30 行的 HTML/JS。
#### 有些库需要你使用构建系统
构建系统这些事情最近盘旋在我的脑海里,因为这周我正在用 CodeMirror 5 做一个新项目我看到有一个新版本CodeMirror 6。
所以我想 —— 很酷,也许我应该使用 CodeMirror 6 而不是 CodeMirror 5。但是 —— 似乎没有构建系统你就不能使用 CodeMirror 6根据 [迁移指南][10]),所以我打算坚持使用 CodeMirror 5。
同样地,你以前可以把 Tailwind 作为一个巨大的 CSS 文件下载,但是 [Tailwind 3][11] 似乎根本不能作为一个大的 CSS 文件使用,你需要运行 Javascript 来构建它。所以我现在要继续使用 Tailwind 2。我知道我知道你不应该使用大的 CSS 文件,但是它验收只有 300KB而且我真的不希望有构建步骤
(更正:看起来 Tailwind 在 2021 年发布了一个 [独立的命令行工具][12],这似乎是一个不错的选择)
我不完全确定为什么有些库不提供无构建系统版本 —— 也许发布无构建系统版本会给库增加很多额外的复杂性,而维护者认为这不值得。或者,库的设计意味着由于某种原因,不可能发布无构建系统版本。
#### 我希望有更多的无构建系统的 Javascript 技巧
到目前为止,我的主要策略是:
- 在某个库的网站上搜索 “CDN”找到一个单独的 Javascript 文件
- 使用 [https://unpkg.com][13] 来查看该库是否有一个我可以使用的内置版本
- 托管我自己的库的版本,而不是依赖可能崩溃的 CDN
- 编写我自己的简单集成方案,而不是拉入另一个依赖关系(例如,前几天我为 Vue 编写了自己的 CodeMirror 组件)。
- 如果我想要一个构建系统,就使用 Esbuild
还有一些看起来很有趣但我还没有研究过的东西:
- 这个 [关于 Javascript 注释中类型语法的 Typescript 建议][14]
- 一般来说ES 模块
--------------------------------------------------------------------------------
via: https://jvns.ca/blog/2023/02/16/writing-javascript-without-a-build-system/
作者:[Julia Evans][a]
选题:[lkxed][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://jvns.ca/
[b]: https://github.com/lkxed/
[1]: https://tailwindcss.com/
[2]: https://messwithdns.net/
[3]: https://css-examples.wizardzines.com/
[4]: https://questions.wizardzines.com
[5]: https://sql-playground.wizardzines.com/
[6]: https://nginx-playground.wizardzines.com/
[7]: https://stackoverflow.com/questions/69692842/error-message-error0308010cdigital-envelope-routinesunsupported
[8]: https://jvns.ca/blog/2021/11/15/esbuild-vue/
[9]: https://github.com/jvns/vue3-tiny-template
[10]: https://codemirror.net/docs/migration/
[11]: https://tailwindcss.com/docs/installation
[12]: https://tailwindcss.com/blog/standalone-cli
[13]: https://unpkg.com
[14]: https://devblogs.microsoft.com/typescript/a-proposal-for-type-syntax-in-javascript/
[0]: https://img.linux.net.cn/data/attachment/album/202303/27/120324jeqlswqte9exfxhh.jpg

View File

@ -1,226 +0,0 @@
[#]: subject: "Writing Javascript without a build system"
[#]: via: "https://jvns.ca/blog/2023/02/16/writing-javascript-without-a-build-system/"
[#]: author: "Julia Evans https://jvns.ca/"
[#]: collector: "lkxed"
[#]: translator: " "
[#]: reviewer: " "
[#]: publisher: " "
[#]: url: " "
Writing Javascript without a build system
======
Hello! Ive been writing some Javascript this week, and as always when I start
a new frontend project, I was faced with the question: should I use a build
system?
I want to talk about whats appealing to me about build systems, why I
(usually) still dont use them, and why I find it frustrating that some
frontend Javascript libraries require that you use a build system.
Im writing this because most of the writing I see about JS assumes that
youre using a build system, and it can be hard to navigate for folks like me
who write very simple small Javascript projects that dont require a build
system.
#### whats a build system?
The idea is that you have a bunch of Javascript or Typescript code, and you
want to translate it into different Javascript code before you put it on your
website.
Build systems can do lots of useful things, like:
- combining 100s of JS files into one big bundle (for efficiency reasons)
- translating Typescript into Javascript
- typechecking Typescript
- minification
- adding polyfills to support older browsers
- compiling JSX
- treeshaking (remove unused JS code to reduce file sizes)
- building CSS (like [tailwind][1] does)
- and probably lots of other important things
Because of this, if youre building a complex frontend project today, probably youre using a build system like webpack, rollup, esbuild, parcel, or vite.
Lots of those features are appealing to me, and Ive used build systems in the past for some of these reasons: [Mess With DNS][2] uses `esbuild` to translate Typescript and combine lots of files into one big file, for example.
#### the goal: easily make changes to old tiny websites
I make a lot [of][3][small][4][simple][5][websites][6], I have approximately 0 maintenance energy for any of them, and I change them very infrequently.
My goal is that if I have a site that I made 3 or 5 years ago, Id like to be able to, in 20 minutes:
- get the source from github on a new computer
- make some changes
- put it on the internet
But my experience with build systems (not just Javascript build systems!), is
that if you have a 5-year-old site, often its a huge pain to get the site
built again.
And because most of my websites are pretty small, the _advantage_ of using a
build system is pretty small I dont really need Typescript or JSX. I can
just have one 400-line `script.js` file and call it a day.
#### example: trying to build the SQL playground
One of my sites (the [sql playground][5]) uses a build system (its using Vue). I last edited that project 2 years ago, on a different machine.
Lets see if I can still easily build it today on my machine. To start out, we have to run `npm install`. Heres the output I get.
```
$ 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
```
Theres some kind of error building `grpc`. No problem. I dont
really need that dependency anyway, so I can just take 5 minutes to tear it out
and rebuild. Now I can `npm install` and everything works.
Now lets try to build the project:
```
$ 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
```
[This stack overflow answer][7] suggests running `export NODE_OPTIONS=--openssl-legacy-provider` to fix this error.
That works, and finally I can `npm run build` to build the project.
This isnt really that bad (I only had to remove a dependency and pass a slightly mysterious node option!),
but I would rather not be derailed by those build errors.
#### for me, a build system isnt worth it for small projects
For me, a complicated Javascript build system just doesnt seem worth it for
small 500-line projects it means giving up being able to easily update the
project in the future in exchange for some pretty marginal benefits.
#### esbuild seems a little more stable
I want to give a quick shoutout to esbuild: I [learned about esbuild in 2021][8] and used for a project, and
so far it does seem a more reliable way to build JS projects.
I just tried to build an `esbuild` project that I last touched 8 months ago on
a new computer, and it worked. But I cant say for sure if Ill be able to
easily build that project in 2 years. Maybe it will, I hope so!
#### not using a build system is usually pretty easy
Heres what the part of [nginx playground][6] code that imports all the libraries looks like:
```
<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>
```
This project is also using Vue, but it just uses a `<script src` to load Vue
theres no build process for the frontend.
#### a no-build-system template for using Vue
A couple of people asked how to get started writing Javascript without a build
system. Of course you can write vanilla JS if you want, but my usual framework
is Vue 3.
[Heres a tiny template I built][9]
for starting a Vue 3 project with no build system. Its just 2 files and ~30 lines of HTML/JS.
#### some libraries require you to use a build system
This build system stuff is on my mind recently because Im using CodeMirror 5
for a new project this week, and I saw there was a new version, CodeMirror 6.
So I thought cool, maybe I should use CodeMirror 6 instead of CodeMirror 5.
But it seems like you cant use CodeMirror 6 without a build system (according to [the migration guide][10]). So Im going to stick with CodeMirror 5.
Similarly, you used to be able to just download Tailwind as a giant CSS file,
but [Tailwind 3][11] doesnt seem to be available as a
big CSS file at all anymore, you need to run Javascript to build it. So Im
going to keep using Tailwind 2 for now. (I know, I know, youre not supposed to use the big CSS file, but its only 300KB gzipped and I really dont want a build step)
(edit: it looks like Tailwind released a [standalone CLI][12] in 2021 which seems like a nice option)
Im not totally sure why some libraries dont provide a no-build-system version
maybe distributing a no-build-system version would add a lot of additional
complexity to the library, and the maintainer doesnt think its worth it. Or
maybe the librarys design means that its not possible to distribute a
no-build-system version for some reason.
#### Id love more tips for no-build-system javascript
My main strategies so far are:
- search for “CDN” on a librarys website to find a standalone javascript file
- use [https://unpkg.com][13] to see if the library has a built version I can use
- host my own version of libraries instead of relying on a CDN that might go down
- write my own simple integrations instead of pulling in another dependency (for example I wrote my own CodeMirror component for Vue the other day)
- if I want a build system, use esbuild
A couple of other things that look interesting but that I havent looked into:
- this [typescript proposal for type syntax in Javascript comments][14]
- ES modules generally
--------------------------------------------------------------------------------
via: https://jvns.ca/blog/2023/02/16/writing-javascript-without-a-build-system/
作者:[Julia Evans][a]
选题:[lkxed][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://jvns.ca/
[b]: https://github.com/lkxed/
[1]: https://tailwindcss.com/
[2]: https://messwithdns.net/
[3]: https://css-examples.wizardzines.com/
[4]: https://questions.wizardzines.com
[5]: https://sql-playground.wizardzines.com/
[6]: https://nginx-playground.wizardzines.com/
[7]: https://stackoverflow.com/questions/69692842/error-message-error0308010cdigital-envelope-routinesunsupported
[8]: https://jvns.ca/blog/2021/11/15/esbuild-vue/
[9]: https://github.com/jvns/vue3-tiny-template
[10]: https://codemirror.net/docs/migration/
[11]: https://tailwindcss.com/docs/installation
[12]: https://tailwindcss.com/blog/standalone-cli
[13]: https://unpkg.com
[14]: https://devblogs.microsoft.com/typescript/a-proposal-for-type-syntax-in-javascript/