打造我一直想要的 SSG:11ty、Vite 和 JAM 三明治

已发表: 2022-03-10
快速总结 ↬早在 2020 年 1 月,Ben Holmes 就开始着手做几乎每个 Web 开发人员每年都会做的事情:重建他的个人网站。 在这篇文章中,他分享了他如何从绝对零开始构建自己的构建管道并创建 Slinkity 的故事。

我不了解你,但我已经被我们这些天拥有的所有 Web 开发工具所淹没。 无论你喜欢 Markdown、纯 HTML、React、Vue、Svelte、Pug 模板、Handlebars、Vibranium——你都可以将它与一些 CMS 数据混合起来,得到一个不错的静态站点鸡尾酒。

我不会告诉你应该使用哪些 UI 开发工具,因为它们都很棒——取决于你项目的需要。 这篇文章是关于为任何场合寻找完美的静态网站生成器; 让我们可以使用 markdown 之类的无 JS 模板来启动,并根据需要引入组件驱动的交互性“孤岛”。

我在这里将一年的学习经验提炼成一篇文章。 我们不仅要讨论代码(又名 duct-taping 11ty 和 Vite 一起),而且我们还将探索为什么这种方法对 Jamstackian 问题如此普遍。 我们会谈到:

  • 静态站点生成的两种方法,以及我们为什么要弥合差距;
  • Pug 和 Nunjucks 等模板语言仍然有用;
  • 当 React 或 Svelte 等组件框架应该发挥作用时;
  • Vite 的全新热重载世界如何帮助我们以几乎零配置将 JS 交互性带入我们的 HTML;
  • 这如何补充 11ty 的数据级联,将 CMS 数据带入您可能需要的任何组件框架或 HTML 模板。

因此,事不宜迟,以下是我关于可怕的构建脚本、捆绑器突破和意大利面条代码管道磁带的故事(最终)给了我我一直想要的 SSG:一个名为 Slinkity 的 11ty、Vite 和 Jam 三明治!

静态站点生成的巨大差异

在深入研究之前,我想讨论一下静态站点生成中的两个“阵营”。

在第一个阵营中,我们有“简单”的静态站点生成器。 这些工具不会带来 JavaScript 包、单页应用程序以及我们所期待的任何其他流行语。 他们只是确定了 Jamstack 的基础:从您喜欢的任何 CMS 的 JSON blob 中提取数据,并将该数据滑入纯 HTML 模板 + CSS。 Jekyll、Hugo 和 11ty 等工具在这个阵营中占主导地位,让您将降价和流动文件的目录变成一个功能齐全的网站。 主要优势:

  • 学习曲线浅
    如果您了解 HTML,那么您就可以开始了!
  • 快速构建时间
    我们不会处理任何复杂的事情,因此每条路线都可以快速构建。
  • 即时互动
    客户端上没有(或很少)要解析的 JavaScript。

现在在第二个阵营,我们有“动态”静态站点生成器。 这些引入了 React、Vue 和 Svelte 等组件框架,为您的 Jamstack 带来交互性。 这些实现了在构建时将 CMS 数据与您的站点路由相结合的相同核心承诺。 主要优势:

  • 为交互性而生
    需要动画图像轮播? 多步骤形式? 只需添加 HTML、CSS 和 JS 的组件化块。
  • 状态管理
    Svelte 商店的 React Context 之类的东西允许在路由之间无缝共享数据。 例如,您的电子商务网站上的购物车。

这两种方法都有明显的优点。 但是,如果你从第一个阵营中选择了一个 SSG,比如 Jekyll,只是在你的项目开始六个月后才意识到你需要一些组件式交互性怎么办? 或者你为那些强大的组件选择了 NextJS 之类的东西,只是为了适应 React 的学习曲线,或者静态博客文章中不必要的 JavaScript 知识库?

在我看来,很少有项目完全适合一个阵营或另一个阵营。 它们存在于一个范围内,随着项目需求的发展,不断地支持新的功能集。 那么我们如何找到一个解决方案,让我们第一个阵营的简单工具开始,在需要时从第二个阵营逐渐添加功能?

好吧,让我们来看看我的学习之旅。

注意:如果您已经购买了使用 11ty 构建静态网站的静态模板,请随时跳到多汁的代码演练。

跳跃后更多! 继续往下看↓

从组件到模板和 Web API

早在 2020 年 1 月,我就着手做几乎每个 Web 开发人员每年都会做的事情:重建我的个人网站。 但这一次会有所不同。 我挑战自己,双手绑在背后建立一个网站,不允许任何框架或构建管道!

作为一个 React 爱好者,这不是一件简单的事情。 但是我昂首挺胸,开始从绝对零开始构建自己的构建管道。 我可以从我的个人网站的 v1 中分享很多写得不好的代码……但如果你这么勇敢,我会让你点击这个自述文件。 相反,我想专注于我学到的更高层次的外卖,让我自己饿死我的 JS 内疚的乐趣。

模板比您想象的要远得多

我在这个项目中遇到了一个正在恢复的 JavaScript 垃圾。 我喜欢使用基于组件的框架来满足一些与静态站点相关的需求:

  1. 我们想将我的网站分解为可重用的 UI 组件,这些组件可以接受 JS 对象作为参数(也称为“道具”)。
  2. 我们需要在构建时获取一些信息以进入生产站点。
  3. 我们需要从文件目录或内容的胖 JSON 对象生成一堆 URL 路由

列表取自我个人博客上的这篇文章。

但是您可能已经注意到……这些都不需要客户端 JavaScript。 像 React 这样的组件框架主要是为了处理状态管理问题而构建的,比如 Facebook Web 应用程序首先激发了 React。 如果您只是将您的网站分解为一口大小的组件或设计系统元素,那么像 Pug 之类的模板也可以很好地工作!

以这个导航栏为例。 在 Pug 中,我们可以定义一个“mixin”来接收数据作为 props:

 // nav-mixins.pug mixin NavBar(links) // pug's version of a for loop each link in links a(href=link.href) link.text

然后,我们可以在我们网站的任何地方应用该 mixin。

 // index.pug // kinda like an ESM "import" include nav-mixins.pug html body +NavBar(navLinksPassedByJS) main h1 Welcome to my pug playground

如果我们用一些数据“渲染”这个文件,我们将得到一个漂亮的index.html来提供给我们的用户。

 const html = pug.render('/index.pug', { navLinksPassedByJS: [ { href: '/', text: 'Home' }, { href: '/adopt', text: 'Adopt a Pug' } ] }) // use the NodeJS filesystem helpers to write a file to our build await writeFile('build/index.html', html)

当然,这并没有为你的 mixin 提供范围 CSS 或你想要的有状态的 JavaScript 之类的细节。 但它比 React 之类的东西有一些非常强大的好处:

  1. 我们不需要我们不了解的精美捆绑器。
    我们只是手动编写了pug.render调用,并且我们已经准备好部署站点的第一条路线。
  2. 我们不会向最终用户发送任何 JavaScript。
    使用 React 通常意味着发送一个大的 ole 运行时供人们的浏览器运行。 通过在构建时调用pug.render类的函数,我们将所有 JS 保留在我们身边,同时在最后发送一个干净的.html文件。

这就是为什么我认为模板是静态网站的一个很好的“基础”。 尽管如此,能够接触到我们真正从中受益的组件框架会很好。 稍后再谈。

推荐阅读:Zara Cooper如何使用 Pug 创建更好的 Angular 模板

您不需要框架来构建单页应用程序

当我在做的时候,我还想在我的网站上进行一些性感的页面转换。 但是我们如何在没有框架的情况下完成这样的事情呢?

带有垂直擦除过渡的交叉淡入淡出
带有垂直擦除过渡的交叉淡入淡出。 (大预览)

好吧,如果每个页面都是它自己的.html文件,我们就不能这样做。 当我们从一个 HTML 文件跳转到另一个 HTML 文件时,整个浏览器都会刷新,所以我们不能有很好的淡入淡出效果(因为我们会简单地将两个页面显示在彼此的顶部)。

我们需要一种方法来“获取”我们要导航到的任何地方的 HTML 和 CSS,并使用 JavaScript 将其动画化到视图中。 这听起来像是单页应用程序的工作! 为此,我使用了一个简单的浏览器 API 组合:

  1. 使用事件侦听器拦截所有链接点击。
  2. fetch API 获取您要访问的任何页面的所有资源,然后将我想要动画化的部分抓取到视图中:导航栏之外的内容(我希望在动画期间保持静止)。
  3. 网络动画 API 将新内容动画化为关键帧。
  4. history API 使用window.history.pushState({}, 'new-route')更改浏览器 URL 栏中显示的路由。 否则,看起来您从未离开过上一页!

为清楚起见,这里是使用简单的查找和替换(源文章)的单页应用程序概念的可视化说明:

逐步的客户端路由过程: 1. 返回中等稀有汉堡包,2. 我们使用 fetch API 请求一个做得好的汉堡包,3. 我们按摩响应,4. 我们提取 'patty' 元素并应用它到我们的当前页面。
逐步的客户端路由过程: 1. 返回中等稀有汉堡包,2. 我们使用 fetch API 请求一个做得好的汉堡包,3. 我们按摩响应,4. 我们提取 'patty' 元素并应用它到我们的当前页面。 (大预览)

注意您也可以从我的个人网站访问源代码。

当然,React et al 和你选择的动画库的一些配对可以做到这一点。 但是对于像淡入淡出过渡这样简单的用例……Web API 本身就非常强大。 如果您想在 Pug 或纯 HTML 等静态模板上实现更强大的页面转换,Swup 等库将为您提供很好的服务。

11ty 带来了什么

在这一点上,我对我的小 SSG 感觉很好。 当然,它无法在构建时获取任何 CMS 数据,并且不支持按页面或按目录的不同布局,也没有优化我的图像,也没有增量构建。

好吧,我可能需要一些帮助。

鉴于我从 v1 中学到的所有东西,我认为我有权放弃“无第三方构建管道”规则并使用现有工具。 事实证明,11ty 拥有我需要的功能宝库!

  • 在构建时使用.11ydata.js文件获取数据;
  • 来自_data文件夹的全局数据可用于我的所有模板;
  • 在开发过程中使用 browsersync 进行热重载;
  • 支持精美的 HTML 转换;
  • …以及无数其他好东西。

如果您尝试过 Jekyll 或 Hugo 等简单的 SSG,您应该对 11ty 的工作原理有一个很好的了解。 只有区别吗? 11ty 完全使用 JavaScript。

11ty 基本上支持所有模板库,因此很高兴将我所有的 Pug 页面呈现为.html路由。 它的布局链接选项也有助于我的人造单页应用程序设置。 我只需要一个用于所有路线的script ,以及一个“全局”布局来导入该脚本:

 // _includes/base-layout.html <html> <body> <!--load every page's content between some body tags--> {{ content }} <!--and apply the script tag just below this--> <script src="main.js"></script> </body> </html> // random-blog-post.pug --- layout: base-layout --- article h2 Welcome to my blog p Have you heard the story of Darth Plagueis the Wise?

只要main.js完成了我们探索的所有链接拦截,我们就有了页面转换!

哦,还有数据级联

所以 11ty 帮助清理了我从 v1 开始的所有意大利面条代码。 但它带来了另一个重要的部分:一个干净的 API 来将数据加载到我的布局中。 这是 Jamstack 方法的基础。 除了使用 JavaScript + DOM 操作在浏览器中获取数据之外,您还可以:

  1. 在构建时使用 Node.js 获取数据。
    这可能是对某些外部 API 的调用、本地 JSON 或 YAML 导入,甚至是您站点上其他路由的内容(想象一下,每当添加新路由时都会更新目录)。
  2. 将这些数据放入您的路线中。 回想一下我们之前编写的.render函数:
 const html = pug.render('/index.pug', { navLinksPassedByJS: [ { href: '/', text: 'Home' }, { href: '/adopt', text: 'Adopt a Pug' } ] })

…但不是每次都用我们的数据调用pug.render ,我们让 11ty 在幕后执行此操作。

当然,我的个人网站没有太多数据。 但是为我所有的个人项目创建一个.yaml文件感觉很棒:

 # _data/works.yaml - title: Bits of Good Homepage hash: bog-homepage links: - href: https://bitsofgood.org text: Explore the live site - href: https://github.com/GTBitsOfGood/bog-web text: Scour the Svelt-ified codebase timeframe: May 2019 - present tags: - JAMstack - SvelteJS - title: Dolphin Audio Visualizer ...

并通过任何模板访问该数据:

 // home.pug .project-carousel each work in works h3 #{title} p #{timeframe} each tag in tags ...

来自使用 create-react-app 的“客户端渲染”世界,这是一个相当大的启示。 不再向浏览器发送 API 密钥或大型 JSON Blob。

我还为我网站的版本 1 添加了一些用于 JavaScript 获取和动画改进的好东西。 如果你很好奇,这里是我的 README 所在的位置。

在这一点上我很高兴,但有些东西不见了

我放弃了基于 JS 的组件并采用了模板(通过动画页面转换来启动),这让我走得很远。 但我知道这不会永远满足我的需求。 还记得我把我们踢开的那个巨大的鸿沟吗? 好吧,在我的构建设置(坚定地在 #1 阵营)和 JS 化交互的天堂(Next、SvelteKit 和 #2 阵营的更多)之间显然仍然存在沟壑。 说我要添加:

  • 带有打开/关闭切换的弹出模式,
  • 一个基于组件的设计系统,如 Material UI,具有范围样式,
  • 一个复杂的多步形式,可能由状态机驱动。

如果您是纯 JS 纯粹主义者,那么您可能对所有这些用例都有无框架的答案。 但是 JQuery 不再是常态是有原因的! 创建离散的、易于阅读的 HTML 组件、作用域样式和 JavaScript“状态”变量片段具有吸引力。 React、Vue、Svelte 等为调试和测试提供了如此多的细节,以至于直接的 DOM 操作无法完全匹配。

所以这是我的百万美元问题:

我们可以使用直接的 HTML 模板开始,然后在我们想要的地方逐步添加 React/Vue/Svelte 组件吗?

答案是肯定的。 让我们试试看。

11ty + Vite:天作之合️

这是我在这里想象的梦想。 无论我想在哪里插入一些交互的东西,我都想在我的模板中留下一个小标志来“把 X React 组件放在这里”。 这可能是 11ty 支持的简码语法:

 # Super interesting programming tutorial Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example! {% react './components/FancyLiveDemo.jsx' %}

但请记住,一体式 11ty(故意)避免:一种捆绑所有 JavaScript 的方法。 来自捆绑的 OG 公会,您的大脑可能会跳到在这里构建 Webpack、Rollup 或 Babel 进程。 构建一个大的 ole 入口点文件,并输出一些漂亮的优化代码,对吗?

好吧,是的,但这可能会涉及很多。 例如,如果我们使用 React 组件,我们可能需要一些 JSX 加载器,一个用于转换所有内容的精美 Babel 进程,一个用于 SASS 和 CSS 模块导入的解释器,帮助实时重新加载的东西等等。

如果有一个工具可以查看我们的.jsx文件并确切地知道如何处理它们。

输入:维特

Vite 最近一直是全城的话题。 它旨在成为使用 JavaScript 构建几乎任何东西的多合一工具。 这是您在家尝试的示例。 让我们在机器上的某个地方创建一个空目录并安装一些依赖项:

 npm init -y # Make a new package.json with defaults set npm i vite react react-dom # Grab Vite + some dependencies to use React

现在,我们可以创建一个index.html文件作为我们应用程序的“入口点”。 我们将保持非常简单:

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>Hello Vite! (wait is it pronounced "veet" or "vight"...)</h1> <div></div> </body> </html>

唯一有趣的是中间的div id="root" 。 这将是我们的 React 组件的根!

如果您愿意,您可以启动 Vite 服务器以在浏览器中查看我们的纯 HTML 文件。 只需运行vite (或npx vite ,如果您的终端中没有配置该命令),您将看到以下有用的输出:

 vite vX.XX dev server running at: > Local: http://localhost:3000/ > Network: use `--host` to expose ready in Xms.

就像 Browsersync 或其他流行的开发服务器一样,每个.html文件的名称对应于我们服务器上的一个路由。 所以如果我们将index.html重命名为about.html ,我们将访问http://localhost:3000/about/ (是的,你需要一个斜杠!)

现在让我们做一些有趣的事情。 除了那个index.html文件,添加某种基本的 React 组件。 我们将在这里使用 React 的useState来演示交互性:

 // TimesWeMispronouncedVite.jsx import React from 'react' export default function TimesWeMispronouncedVite() { const [count, setCount] = React.useState(0) return ( <div> <p>I've said Vite wrong {count} times today</p> <button onClick={() => setCount(count + 1)}>Add one</button> </div> ) }

现在,让我们将该组件加载到我们的页面上。 这就是我们必须添加到我们的index.html的全部内容:

 <!DOCTYPE html> ... <body> <h1>Hello Vite! (wait is it pronounced "veet" or "vight"...)</h1> <div></div> <!--Don't forget type="module"! This lets us use ES import syntax in the browser--> <script type="module"> // path to our component. Note we still use .jsx here! import Component from './TimesWeMispronouncedVite.jsx'; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('root'); ReactDOM.render(React.createElement(Component), componentRoot); </script> </body> </html>

是的,就是这样。 无需自己将我们的.jsx文件转换为浏览器就绪的.js文件! 无论 Vite 在哪里看到.jsx导入,它都会自动将该文件转换为浏览器可以理解的内容。 在开发中工作时甚至没有distbuild文件夹; Vite 动态处理所有内容——每次我们保存更改时都会重新加载热模块。

好的,所以我们有一个非常强大的构建工具。 我们怎样才能把它带到我们的 11ty 模板中?

与 11ty 一起运行 Vite

在我们开始讨论好东西之前,让我们讨论一下并排运行 11ty 和 Vite。 继续将 11ty 作为开发依赖项安装到上一节中的同一项目目录中:

 npm i -D @11ty/eleventy # yes, it really is 11ty twice

现在让我们做一点飞行前检查,看看 11ty 是否正常工作。 为避免混淆,我建议您:

  1. 从之前删除那个index.html文件;
  2. TimesWeMispronouncedVite.jsx移动到新目录中。 说, components/
  3. 为我们的网站创建一个src文件夹;
  4. 将模板添加到该src目录以供 11ty 处理。

例如,包含以下内容的blog-post.md文件:

 # Hello world! It's markdown here

您的项目结构应如下所示:

 src/ blog-post.md components/ TimesWeMispronouncedVite.jsx

现在,从终端运行 11ty,如下所示:

 npx eleventy --input=src

如果一切顺利,您应该会看到如下构建输出:

 _site/ blog-post/ index.html

其中_site是我们的默认输出目录,而blog-post/index.html是我们为浏览而精心转换的 markdown 文件。

通常,我们会运行npx eleventy --serve来启动开发服务器并访问该/blog-post页面。 但是我们现在正在使用 Vite 作为我们的开发服务器! 这里的目标是:

  1. 让 110 构建我们的 markdown、Pug、nunjucks _site目录。
  2. 将 Vite 指向同一个_site目录,这样它就可以处理 React 组件、花哨的样式导入以及 11ty 没有处理的其他内容。

所以这是一个两步构建过程,11ty 交付了 Vite。 这是你需要在“watch”模式下同时启动 11ty 和 Vite 的 CLI 命令:

 (npx eleventy --input=src --watch) & npx vite _site

您还可以在两个单独的终端中运行这些命令,以便于调试。

运气好的话,您应该能够访问http://localhost:3000/blog-post/ (同样,不要忘记尾部的斜杠!)以查看已处理的 Markdown 文件。

使用简码进行部分补水

让我们简要介绍一下短代码。 是时候重新审视之前的语法了:

 {% react '/components/TimesWeMispronouncedVite.jsx' %}

对于那些不熟悉短代码的人:它们与函数调用大致相同,函数返回一个 HTML 字符串以滑入您的页面。 我们的简码的“解剖”是:

  • {% … %}
    包装器表示短代码的开始和结束。
  • react
    我们稍后将配置的短代码函数的名称。
  • '/components/TimesWeMispronouncedVite.jsx'
    我们的简码函数的第一个(也是唯一一个)参数。 你可以有尽可能多的参数。

让我们连接我们的第一个短代码! 将.eleventy.js文件添加到项目的基础中,并为我们的react短代码添加此配置条目:

 // .eleventy.js, at the base of the project module.exports = function(eleventyConfig) { eleventyConfig.addShortcode('react', function(componentPath) { // return any valid HTML to insert return `<div>This is where we'll import ${componentPath}</div>` }) return { dir: { // so we don't have to write `--input=src` in our terminal every time! input: 'src', } } }

现在,让我们用我们的新短代码为我们的blog-post.md 。 将此内容粘贴到我们的降价文件中:

 # Super interesting programming tutorial Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example! {% react '/components/TimesWeMispronouncedVite.jsx' %}

如果你运行一个快速的npx eleventy ,你应该在/blog-post/index.html下的_site目录中看到这个输出:

 <h1>Super interesting programming tutorial</h1> <p>Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example!</p> <div>This is where we'll import /components/TimesWeMispronouncedVite.jsx</div>

编写我们的组件简码

现在让我们用那个短代码做一些有用的事情。 还记得我们在试用 Vite 时编写的script标签吗? 好吧,我们可以在我们的简码中做同样的事情! 这次我们将使用componentPath参数来生成导入,但其余部分几乎相同:

 // .eleventy.js module.exports = function(eleventyConfig) { let idCounter = 0; // copy all our /components to the output directory // so Vite can find them. Very important step! eleventyConfig.addPassthroughCopy('components') eleventyConfig.addShortcode('react', function (componentPath) { // we'll use idCounter to generate unique IDs for each "root" div // this lets us use multiple components / shortcodes on the same page idCounter += 1; const componentRootId = `component-root-${idCounter}` return ` <div></div> <script type="module"> // use JSON.stringify to // 1) wrap our componentPath in quotes // 2) strip any invalid characters. Probably a non-issue, but good to be cautious! import Component from ${JSON.stringify(componentPath)}; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('${componentRootId}'); ReactDOM.render(React.createElement(Component), componentRoot); </script> ` }) eleventyConfig.on('beforeBuild', function () { // reset the counter for each new build // otherwise, it'll count up higher and higher on every live reload idCounter = 0; }) return { dir: { input: 'src', } } }

现在,调用我们的短代码(例如{% react '/components/TimesWeMispronouncedVite.jsx' %} )应该输出如下内容:

 <div></div> <script type="module"> import Component from './components/FancyLiveDemo.jsx'; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('component-root-1'); ReactDOM.render(React.createElement(Component), componentRoot); </script>

使用(npx eleventy --watch) & vite _site访问我们的开发服务器,我们应该会找到一个精美的可点击计数器元素。

流行语警报——部分水化和岛屿建筑

我们只是以最简单的形式展示了“岛屿架构”。 这就是我们的交互式组件树不必消耗整个网站的想法。 相反,我们可以在整个应用程序中根据我们实际需要交互性的位置来创建迷你树或“岛屿”。 有一个基本的链接登陆页面,没有任何状态需要管理? 伟大的! 不需要交互式组件。 但是你有一个可以从 X React 库中受益的多步骤表单吗? 没问题。 使用类似react短代码的技术来启动Form.jsx岛。

这与“部分补水”的想法密切相关。 如果您使用像 NextJS 或 Gatsby 这样的组件式 SSG,您可能已经听说过“水合作用”这个词。 简而言之,这是一种方法:

  1. 首先将您的组件渲染为静态 HTML。
    这使用户在最初访问您的网站时可以查看一些内容。
  2. 用交互性“水合”这个 HTML。
    这是我们连接状态钩子和渲染器的地方,好吧,让按钮点击真正触发一些东西。

这种 1-2 的冲击使得 JS 驱动的框架对于静态站点是可行的。 只要用户在你的 JavaScript 解析完成之前有一些东西要查看,你就会在这些灯塔指标上获得不错的分数。

好吧,直到你不这样做。 “水合”整个网站可能会很昂贵,因为您需要准备好处理每个最后一个 DOM 元素的 JavaScript 包。 但是我们的杂乱无章的短代码技术并没有覆盖整个页面! 相反,我们“部分地”水合那里的内容,仅在必要时插入组件。

别担心,所有这些都有一个插件:Slinkity

让我们回顾一下我们在这里发现的内容:

  1. Vite 是一个非常强大的打包工具,无需额外配置即可处理大多数文件类型( jsxvuesvelte等等)。
  2. 简码是一种将 HTML 块插入到我们的模板中的简单方法,组件样式。
  3. 我们可以使用简码在任何我们想要使用部分水合的地方渲染动态的、交互式的 JS 包。

那么优化的生产构建呢? 正确加载作用域样式? 哎呀,使用.jsx创建整个页面? 好吧,我已经将所有这些(以及更多!)捆绑到一个名为 Slinkity 的项目中。 我很高兴看到社区对这个项目的热情接待,亲爱的读者,我希望你自己来试一试!

试试快速入门指南

Astro的也很棒

着眼于尖端技术的读者现在可能至少想到过一次 Astro。 而且我不能怪你! 它的构建考虑了一个非常相似的目标:从纯 HTML 开始,并在需要的地方插入有状态的组件。 哎呀,他们甚至可以让你开始Vue 中编写 React 组件或HTML 模板文件中编写 Svelte 组件! 这就像 MDX Xtreme 版。

但是,他们的方法有一个相当大的成本:您需要从头开始重写您的应用程序。 这意味着一种基于 JSX 的新模板格式(您可能不习惯),一个全新的数据管道,目前缺少一些细节,以及解决问题时的一般错误。

但是使用 Slinkity 之类的工具来调制 11ty + Vite 鸡尾酒? 好吧,如果您已经有一个 11ty 站点,Vite 应该无需任何重写就可以安装到位,并且短代码应该涵盖许多与.astro文件相同的用例。 我承认它现在远非完美。 但是,嘿,到目前为止它一直很有用,如果您想避免在站点范围内重写,我认为这是一个非常强大的选择!

包起来

到目前为止,这个 Slinkity 实验已经很好地满足了我的需求(你们中的一些人也是如此!)。 随意使用适用于您的 JAM 的任何堆栈。 我很高兴能分享我一年的构建工具放荡的结果,我很高兴看到我们如何弥合巨大的 Jamstack 鸿沟。

延伸阅读

想要更深入地研究部分水合作用、ESM 或 SSG? 检查这些:

  • 岛屿建筑
    Jason Format 的这篇博文真正开启了关于 Web 开发中“孤岛”和“部分水化”的讨论。 它充满了有用的图表和这个想法背后的哲学。
  • 使用定制的静态站点生成器简化您的静态
    另一篇 SmashingMag 文章将引导您从头开始制作基于节点的网站构建器。 这对我来说是一个巨大的启发!
  • ES Modules 如何重新定义 Web 开发
    一篇关于 ES Modules 如何改变 Web 开发游戏的个人帖子。 这进一步探讨了网络上导入语法的“当时和现在”。
  • Web组件简介
    关于什么是 Web 组件、影子 DOM 的工作原理以及 Web 组件在哪些方面被证明有用的出色演练。 使用本指南将自定义组件应用于我自己的框架!