Chris Wanstrath(@defunkt)访谈,pjax创造者

Carson Gross

我非常激动能够采访@defunkt,他是pjax的作者。pjax是一个早期的面向超媒体的JavaScript库,启发了intercooler.js,后者后来演变为htmx。当然他还做了其他事情,比如联合创立GitHub,但本次访谈我将聚焦于pjax:它是如何诞生的、受何影响以及它又影响了什么。

感谢@defunkt接受采访!

问:首先,请向读者简要介绍您的专业和技术背景:

我想用两个小故事概括我的技术背景:

  1. 六年级"展示与讲述"课上,我带了制作的网页打印稿——包括源代码。我想象全班同学都印象深刻。

  2. 七年级刚结束,一群吵闹的高中生带我去本地大学的Linux安装大会,在我家旧电脑上安装了Red Hat。这台电脑成了我整个高中的主力机。

所以从一开始,我就是个热爱UNIX的网页开发者。

编程方面,我在祖父母地下室用IBM PC(运行OS/2)的QBasic起步。后来沉迷MUD游戏(以及MUSHes/MUXes/MOOs...),它们用C编写且通常有自定义脚本语言。写C是"硬编码",写脚本是"软编码"。当时我完全不懂C,但特别喜欢"软编码"。

那些介绍我接触Linux的高中生给了我O'Reilly的骆驼书让我学Perl。我没爱上它。但他们又展示了php3,突然一切豁然开朗:HTML结合MUD式的软编码。我彻底着迷了。

高中时期尝试过ASP 3.0和Visual Basic,但PHP始终是我的最爱。我痴迷于制作动态网页和搭建Linux服务器。高中时和朋友运营过某个喜剧网站(名字就不提了),在博客软件流行前,我独自编写了整个mysql/php后端。乐趣无穷。

大学一年级转用Gentoo,着迷于其用Python编写的包管理器。你能用它编写真正的Linux工具,这很棒,但当时其Web生态薄弱。

我买了厚重的Python O'Reilly书正在啃时,偶然发现了Ruby on Rails。它像闪电般击中我,瞬间终结了我的PHP和Python时代。

同时,Web 2.0概念刚被提出,JavaScript仿佛在说:"嘿各位,我一直在这儿呢。"所以学Rails时我也在学JavaScript。Rails有封装JS的辅助工具,但我真心(大部分)喜欢这门语言,想不依赖框架/库来掌握它。

自主管理Linux服务器、用Rails写后端、用JavaScript写前端的经历,让我更深入爱上了Web平台,并接触到REST/HATEOAS等概念——对写过十多年HTML的人来说,这既自然又合理。

2008年GitHub上线时(惊喜!)由Gentoo、Rails和JavaScript驱动。但由于GitHub不仅是Rails社区更是编程社区的集合,我很快成了技术多面手。

我回头学了Python,参加过Django Dash等编程比赛,在不同PyCon演讲。学了Objective-C开发Mac(后转iPhone)应用。学了Scheme和Lisp,最终从Vim转Emacs并写了大量Emacs Lisp。回头搞懂了Perl的所有符号含义。接着是Lua、Java、C++、C甚至C#——我想尝试一切。

至今我仍如此。用Go、Rust、Haskell、OCaml、F#、各类Lisp方言(Chicken Scheme/Clojure/Racket/Gambit)做过项目。写过十几种编程语言,包括几个真正能用的。现在正在学Zig。

但我总会回归Web。这就是为什么我用Web技术创建Atom编辑器,为什么会有Electron,以及为什么我最近与Andreas Kling联合创立Ladybird浏览器计划,开发独立开源的Ladybird网页浏览器。

问:能否谈谈pjax的诞生历程?

一切始于XMLHttpRequest(Ajax)。我成长时期网络很简单:点击链接,加载新页面。朴素但美好。

后来人们用<frames>等在HTML中构建电邮客户端等应用式程序。不太美好也不太优秀,但有其价值。

幸运的是,2000年代中期Gmail和Ajax改变了一切。Hotmail存在已久,但Gmail更快。通过XMLHttpRequest无整页刷新更新内容,可打造媲美桌面应用的体验。虽然Gmail之前也有Ajax应用,但其普及真正让该技术崭露头角。

很快,Ajax与圆角设计开启了Web 2.0时代。到2010年,越来越多开发者将代码移入JavaScript并用Ajax加载动态内容。但有个关键问题:在原始Web模型中,每个页面有唯一URL,可在任意环境加载内容——这是Web的创新。而使用Ajax时URL不变,更糟的是它无法更改(至少服务器无法读取)。Web被破坏了。

传统上,开发者用变通方案绕过限制。#!时代由Facebook/Twitter等重度Ajax网站开创。访问个人主页时,浏览器地址栏显示http://twitter.com/#!/htmx_org而非http://twitter.com/htmx_org。#传统用于锚点链接(定位页面子章节),可被JavaScript修改。这些Web 2.0先驱利用#的可塑性,将其代表可通过内联更新存在的永久内容,类似真实URL。唯一问题是服务器请求中看不到#部分,因此后端架构也需调整。

哦,而且它漏洞百出。

作为HTTP纯粹主义者,我厌恶#!。但当时没有更好方案。

时光流逝,解决方案悄然出现。神奇的一天,#!从Facebook消失,被传统URL取代。难道他们放弃了Web 2.0?不...他们找到了更好方案。

history.pushState()history.replaceState()刚被加入主流浏览器。Facebook迅速利用此API在Ajax更新内容时同步修改浏览器完整URL,让Web重焕荣光。

缺失的环节就此补全。

问题解决了,但新问题出现:GitHub不是SPA,我也不希望它是。到2011年我写JavaScript已六年——足够明白过多JS是灾难。2009年左右最初的GitHub问题跟踪器是纯JS开发的Gmail风格应用,对开发者、用户和我都是糟糕体验。

尽管如此,我仍相信Ajax能大幅加速页面UI并提升体验。只是不想为此编写大量(或任何)JavaScript。我喜欢Web构建的简单请求/响应范式。

于是Pjax诞生了。它通过Ajax加载新页面(非整页)加速GitHub UI,正确更新URL且除Pjax库外无需额外JS。开发者只需用[data-pjax]标记链接,后端应用自动渲染无布局页面内容,快速获取所需数据而无需浏览器重载未变化的JS/CSS/HTML。它(基本)支持后退键(如常规网页),若需深入"黑暗面"写自定义功能也提供JS API。

Pjax首次提交是2011年2月26日,2011年3月底公开——当时我们已用它驱动GitHub.com一段时间。

问:我记得它在Rails社区影响很大。Turbolinks的出现是否影响其采用?

我的目标并非推广这个库。如果是,我可能会花精力解耦它与jQuery。当时我专注于GitHub建设,对既有开源项目维护不足。

我更希望推广这个理念——让人们知道pushState()的存在,知道除纯手写JS外还有其他建站方式。服务器端全页/局部渲染依然可行,且能用现代技术加速。

Turbolinks诞生并集成进Rails令人惊喜,但也意料之中。GitHub之前我就是Sam Stephenson作品的忠实粉丝,我们对HTTP和Web理念高度一致。我的部分思路受他和Rails社区影响,而吸引我加入Rails社区的正是对Web精髓的共识。

除依赖jQuery外,pjax方案也很局限。它是个简单库。我知道别人能走得更远,而他们确实做到了。

问:pjax有多少"理论"基础?构建时是否深入思考超媒体、REST等?(我是在构建intercooler后才接触理论,好奇您的经历!)

不多。最初给每个请求追加?pjax=1,发布前改为发送X-PJAX头。相当高级。

早期GitHub开发者Rick Olson(@technoweenie)也是Rails社区成员,是他向我介绍HATEOAS并在GitHub API中贯彻该理念。pjax任何优点都归功于他和另一位Rails先驱Josh Peek。

我的焦点主要在用户体验、开发者体验以及坚持Web的卓越特性。

</>