Skip to content

搞英语 → 看世界

翻译英文优质信息和名人推特

Menu
  • 首页
  • 作者列表
  • 独立博客
  • 专业媒体
  • 名人推特
  • 邮件列表
  • 关于本站
Menu

使用 esbuild 和 Nix 构建 Xeact 组件

Posted on 2023-04-09

Xeact已经成功实现了星际统治前端开发人员注意力空间的目标。它不仅是我真正理解前端开发的催化剂,它还是最流行的前端 femtoframework,如下图所示:

英雄形象博客/2023/xeact/star-history-202342

但是,我的 Xeact 组件部署过程依赖于deno bundle命令,该命令已被弃用:

 Warning "deno bundle" is deprecated and will be removed in the future. Use alternative bundlers like "deno_emit", "esbuild" or "rollup" instead.

我一直讨厌将 JavaScript 代码部署到互联网的过程。 npm 创建了大量的泥球,这些泥球在逻辑上非常烦人,无法梳理成浏览器可以加载的实际文件。围绕将 JavaScript 项目构建到真实文件中的工具历来是哲学复杂性的垃圾火,也是我避免深入研究前端开发工作原理的唯一原因。

凯蒂是咖啡
< Cadey > 确实,Node.js 的开发方式与浏览器实际支持的方式如此不同,这真的很糟糕。我知道获得导入地图支持的浏览器可以帮助解决这个问题,但如果这根本不是问题就好了。

我理解为什么 Deno 团队要摆脱deno bundle命令(在某种程度上,根据我所了解的,我已经让这一切在浏览器中开始工作,这实际上是相当惊人的),但只是抛弃了恐怖对毫无戒心的人进行 esbuild 在逻辑上令人沮丧。尤其是你需要对所有这些进行破解。

凯蒂是咖啡
< Cadey > 我真的不希望所有这些听起来都是消极和可恨的。但实际上,从习惯于使用通常编译为单个二进制文件的语言进行分发打包的人的角度来看,Node 生态系统是一个巨大的痛苦。有一次 Debian 试图强制执行一项政策,将每个单独的依赖项编译到它自己的未版本化的包中。当他们意识到不同的节点包将依赖于单独的传递依赖项的不言而喻的行为时,所有这一切都崩溃了。这导致他们放弃并运送销售的node_modules文件夹。

你能明白为什么我喜欢 Rust 作为分发包吗?除了确保构建二进制文件并且我可以将其打包到包中之外,我不需要处理任何问题。相比之下,这太容易了。

但是,当我升级 Deno 时,我真的不希望我的构建在未来某个不确定的时间点随机开始崩溃。所以,我感到无聊,然后决定将我的整个构建系统转换为esbuild 。这是整个堆栈以及我如何让它为我的构建工作。

英雄形象灵感-共鸣 Image generated by Ligne Claire v1 — 1girl,绿头发,绿眼睛,t恤,运动裤,长发,全身,坐姿,户外,风景,色差,微笑,侧视,背包,太空针

Deno 和 esbuild

苍井空
< Aoi > 那么,如果 esbuild 是您应该使用的东西,您为什么不想使用它呢?您没有使用 NPM 或其他东西吗?

你是对的,我狡猾的朋友,我根本没有使用 NPM 甚至 node.js。我正在使用Deno ,这是一种替代的 JavaScript/TypeScript 运行时,它是用 Rust 编写的,使依赖管理变得更加容易。它使依赖管理更容易的主要方法之一是让您从运行普通静态文件服务器的 URL 中提取包,而不是必须将所有内容放入 NPM,然后希望 NPM 不会宕机。

凯蒂是咖啡
< Cadey > 是的,是的,这确实意味着您需要希望托管您的依赖项的其他文件服务器不会出现故障。然而,当本文稍后将 Nix 等人引入这种情况时,这就不再是问题了。

当你用 Deno 安装一个包时,它会将所有相关的 JavaScript 和 TypeScript 文件下载到磁盘上的某个位置,并根据它们的源服务器和 SHA256 校验和存储它们。这与 NPM 所做的非常不同。作为比较,这是 NPM 安装Xeact的文件树:

 ./node_modules/ `-- @xeserv `-- xeact |-- CODE_OF_CONDUCT.md |-- LICENSE |-- README.md |-- default.nix |-- jsx-runtime.js |-- package.json |-- shell.nix |-- site | |-- gruvbox.css | |-- index.html | `-- index.js |-- types | |-- jsx-runtime.d.ts | `-- xeact.d.ts |-- xeact.js `-- xeact.ts

下面是 Deno 的本地文件树:

 /deno-dir/deps/ `-- https `-- xena.greedo.xeserv.us |-- 15c8dd50d4aede83901b65e305f1eca8dd42955da363aca395949ce932023443 |-- 15c8dd50d4aede83901b65e305f1eca8dd42955da363aca395949ce932023443.metadata.json |-- 6291a9332210dc73f237e710bb70d6aab7f8cd66ea82cb680ed70f83374b34a3 `-- 6291a9332210dc73f237e710bb70d6aab7f8cd66ea82cb680ed70f83374b34a3.metadata.json

您可以看到这会给现有工具带来很多麻烦。

幸运的是, esbuild支持插件。这些可以让您覆盖行为,例如 esbuild 如何查找依赖项。有一个用于 esbuild 的Deno 插件,但它的文档长期不足。这是我如何让它工作的。

首先,我将 esbuild 和 deno 插件添加到我的导入映射中:

 { " imports ": { " @esbuild ": " https://deno.land/x/[email protected]/mod.js ", " @esbuild/deno ": " https://deno.land/x/[email protected]/mod.ts ", } } 

马拉是黑客
< Mara > 您可以为此使用任何您想要的名称,但@esbuild和@esbuild/deno看起来很酷。

然后编写一个名为build.ts的文件,其中包含以下内容:

 import * as esbuild from " @esbuild "; import { denoPlugin } from " @esbuild/deno ";  
const result = await esbuild . build ({ plugins: [ denoPlugin ({ importMapURL: new URL (" ./import_map.json ", import .meta.url), })], entryPoints: Deno .args, outdir: Deno .env. get (" WRITE_TO ") ? Deno .env. get (" WRITE_TO ") : " ../../static/xeact ", bundle: true , splitting: true , format: " esm ", minifyWhitespace: !! Deno .env. get (" MINIFY "), inject: [" xeact "], jsxFactory: " h ", }); console. log ( result .outputFiles);  
esbuild . stop (); 

马拉是黑客
< Mara > 不要忘记esbuild.stop调用。如果不这样做,脚本将无限挂起。这是在飞行中发现的“乐趣”。

这将执行以下操作:

  • 配置 esbuild 以使用导入映射从我们的 Deno 依赖项中读取
  • 将所有命令行参数设置为构建输入,因此您可以使用deno run -A build.ts **/*.tsx调用它并让它神奇地构建./components中的所有文件
  • 设置输出路径以及是否应根据环境变量(在 Nix 构建中使用)缩小输出

这会正确构建所有内容,并将每个组件放在我的网站希望为其提供服务的自己的.js文件中。这在以后很重要。

尼克斯

现在是有趣的部分,让所有这些在 Nix 中确定性地工作,这样我就不可避免地会忘记所有这些是如何工作的,因为这一切都发生在幕后。当我使用 Nix 构建我的网站前端时,我使用我的deno2nix分支来自动设置我的网站所依赖的所有依赖项的本地副本的过程。

deno2nix internal.mkDepsLink函数允许您获取deno.lock文件并将其转换为 Nix 商店中的文件夹。这完成了在 Nix 中构建 Deno 的所有困难部分。它将deno.lock文件转换为Deno 创建的文件夹结构。

只有一个小问题:我从esm.sh中提取依赖项,有时您会在其路径中包含带有@ (at 符号)的文件。例如:

 http://esm.sh/@xeserv/[email protected]

这将作为/nix/store/[email protected]被拉入 Nix 商店,由于此错误而不起作用:

 error: store path '[email protected]' contains illegal character '@'

有两种方法可以解决这个问题:

  • 修复 deno2nix,使其从 URL 的基本名称(最终路径组件)中去除@
  • 利用esm.sh工作方式从确切的文件而不是父级别重新导出

当您从esm.sh读取时,您会得到一个文件,该文件为http://esm.sh/@xeserv/[email protected]重新导出实际的 NPM 包:

 /* esm.sh - @xeserv/[email protected] */ export * from " https://esm.sh/v114/@xeserv/[email protected]/es2022/xeact.mjs "; export { default } from " https://esm.sh/v114/@xeserv/[email protected]/es2022/xeact.mjs ";

这意味着您只需将导入更改为路径https://esm.sh/v114/@xeserv/[email protected]/es2022/xeact.mjs而不是使其导入顶级/@xeserv/[email protected] ,这将起作用,因为基本名称是xeact.mjs ,而不是[email protected] 。这将使它适合 Nix 商店。

在更改所有导入路径以从确切的文件而不是顶级包中提取后, deno2nix使用旧的构建流程。现在剩下的就是运行esbuild包装器。经过一段时间的摸索,我想出了这个推导:

 frontend = pkgs.stdenv.mkDerivation rec { pname = "xesite-frontend"; inherit (bin) version; dontUnpack = true; src = ./src/frontend; buildInputs = with pkgs; [ deno jq nodePackages.uglify-js ]; ESBUILD_BINARY_PATH = "${pkgs.esbuild}/bin/esbuild";  
 buildPhase = '' export DENO_DIR="$(pwd)/.deno2nix" mkdir -p $DENO_DIR ln -s "${pkgs.deno2nix.internal.mkDepsLink ./src/frontend/deno.lock}" $(deno info --json | jq -r .modulesCache) export MINIFY=yes  
 mkdir -p dist export WRITE_TO=$(pwd)/dist  
 pushd $(pwd) cd $src deno run -A ./build.ts **/*.tsx popd '';  
 installPhase = '' mkdir -p $out/static/xeact cp -vrf dist/* $out/static/xeact ''; };

这使用internal.mkDepsLink函数来创建我们需要的一切,缩小输出,将其全部写入名为dist的文件夹,最后将所有内容插入$out/static/xeact ,例如MastodonShareButton.js 。

它奏效了,当它奏效时我松了一口气。

移民

现在我有能力构建我所有的动态组件,我不得不花点时间来设计我一直想做的东西,Xeact 组件模型。在高层次上,Xeact 是为无状态组件构建的。这些组件在功能上与 React 组件相同:接受属性并将它们转换为 HTML 节点的函数。

马拉是黑客
< Mara > 在更多的计算机科学术语中,我们可以称这些为单态。单态是接受一个参数并产生一个结果的函数,例如 JavaScript 中的(x) -> x + 1 。国家真的把水搅浑了,但我们暂时不要考虑这个。

下面是一个 Xeact 组件示例,该组件处理讨论页的“不允许有趣”按钮:

 import { c } from " xeact ";  
const onclick = () => {  Array . from ( c (" xeblog-slides-fluff ")). forEach ((el) =>    el .classList. toggle (" hidden ") ); };  
export default function NoFunAllowed () {  const button = ( < button      class =""      onclick ={() => onclick ()} > No fun allowed </button> ); return button; }

这将创建一个名为NoFunAllowed函数,该函数显示一个按钮,上面写着"No fun allowed" 。当用户点击它时,它会在每个元素上使用 CSS 类xeblog-slides-fluff切换“隐藏”类。当我写演讲时,我通常使用我的幻灯片作为工具来帮助我直观地解释正在发生的事情。结合健康的超现实主义,这意味着有些人可能会发现我演讲的书面形式不和谐,因为所有推文长度的段落与模因和荒诞主义相结合,比如我最喜欢的幻灯片制成:

14-smol.png

凯蒂是咖啡
< Cadey > 在某种程度上,我真的明白人们不喜欢这样。作为一名艺术家,当我知道这么多人并没有真正看到我付出如此多努力的艺术价值时,我有点沮丧,但我明白了。幽默很难。抽象幽默更难。许多人会错过关于抽象之上的抽象幽默。我喜欢使用荒诞主义/超现实主义幽默来真正向人们传达我们行业内在的超现实主义。对于许多人来说,这基本上只是挥杆和失误。我会活着。

迁移所有其他动态组件是一个简单的复制/粘贴/ useState作业。然后在服务器端连接起来。

服务器

让我们回到 Xeact 组件的真正含义:采用属性并返回 HTML 节点的函数。当我为服务器端组件编写 HTML 时,我实际上是在 markdown 中编写如下内容:

 < xeblog-conv name =" Mimi " mood =" coffee ">As a large language model, I can serve to provide some example text. I don't know what "Hipster Ipsum" is. But the Lorem Ipsum text...</ xeblog-conv >

这将扩展为您在文档中使用lol_html看到的内容:

咪咪是咖啡
< Mimi > 作为大型语言模型,我可以提供一些示例文本。我不知道“Hipster Ipsum”是什么。但是 Lorem Ipsum 文本……

所以在某种程度上我需要做以下事情来支持 Xeact 组件:

  • 创建一个 HTML 包装器,导入组件并将其放入具有唯一 UUID 的 HTML 树中
  • 有某种<noscript>标签来警告人们他们需要启用 JavaScript
  • 导入组件并使用从 Rust 传递的 JSON 执行它的一点 hacky JavaScript

我想我的xeact_component模板中有大部分。它创建一个唯一 ID (UUIDv4),将数据从 Rust 序列化为 JSON,以便它可以用作 Xeact 组件的输入,然后将组件函数的结果放入元素树中。

我使用这个基本过程来移植我的其他动态组件,例如视频播放器:

葵是咖啡
< Aoi > 此动态组件需要 JavaScript 才能运行,抱歉!
凯蒂是恩比
< Cadey > 我计划在完成 Returnal 后写一篇关于 Returnal 的评论。这绝对是杰作。

我希望这将使我更容易维护和扩展我网站上的其他组件。最终我想制作一个类似于<xeact-component xeact_filename="Thing" foo="bar"> HTML 标记,然后让堆栈的所有其余部分做正确的事情,但这需要更多的创造力我现在可以集合了。

我真的很高兴这一切都有效,这不仅让我更容易运行我的网站,将来扩展它应该更容易。

凯蒂是咖啡
< Cadey > 这开始打破我给自己设定的“无结构化 JavaScript”规则,但实际上这是整个生态系统的发展方向。我不喜欢这会降低与其他浏览器(如 SerenityOS 的 LibWeb)的兼容性,但我需要访问精美的玩具才能进行实验。

我很乐意最终在waifud中重用这个逻辑。它的管理面板也容易受到同样的最终破坏,我怀疑我也将不可避免地在那里重用这个构建逻辑。更不用说 Xeact 组件模型和useState允许我在那里简化很多逻辑。

原文: https://xeiaso.net/blog/xeact-esbuild

本站文章系自动翻译,站长会周期检查,如果有不当内容,请点此留言,非常感谢。
  • Abhinav
  • Abigail Pain
  • Adam Fortuna
  • Alberto Gallego
  • Alex Wlchan
  • Answer.AI
  • Arne Bahlo
  • Ben Carlson
  • Ben Kuhn
  • Bert Hubert
  • Bits about Money
  • Brian Krebs
  • ByteByteGo
  • Chip Huyen
  • Chips and Cheese
  • Christopher Butler
  • Colin Percival
  • Cool Infographics
  • Dan Sinker
  • David Walsh
  • Dmitry Dolzhenko
  • Dustin Curtis
  • Elad Gil
  • Ellie Huxtable
  • Ethan Marcotte
  • Exponential View
  • FAIL Blog
  • Founder Weekly
  • Geoffrey Huntley
  • Geoffrey Litt
  • Greg Mankiw
  • Henrique Dias
  • Hypercritical
  • IEEE Spectrum
  • Investment Talk
  • Jaz
  • Jeff Geerling
  • Jonas Hietala
  • Josh Comeau
  • Lenny Rachitsky
  • Liz Danzico
  • Lou Plummer
  • Luke Wroblewski
  • Matt Baer
  • Matt Stoller
  • Matthias Endler
  • Mert Bulan
  • Mostly metrics
  • News Letter
  • NextDraft
  • Non_Interactive
  • Not Boring
  • One Useful Thing
  • Phil Eaton
  • Product Market Fit
  • Readwise
  • ReedyBear
  • Robert Heaton
  • Ruben Schade
  • Sage Economics
  • Sam Altman
  • Sam Rose
  • selfh.st
  • Shtetl-Optimized
  • Simon schreibt
  • Slashdot
  • Small Good Things
  • Taylor Troesh
  • Telegram Blog
  • The Macro Compass
  • The Pomp Letter
  • thesephist
  • Thinking Deep & Wide
  • Tim Kellogg
  • Understanding AI
  • 英文媒体
  • 英文推特
  • 英文独立博客
©2025 搞英语 → 看世界 | Design: Newspaperly WordPress Theme