
什么是 AMP Camp?
作为一名开发者倡导者,谈论如何使用 AMP 来创建快速、交互式网站是一回事。而实际构建一个网站则是另一回事!因此,我们中的一些人决定创建一个简单但功能齐全的电子商务网站,涵盖从头到尾的所有内容。我们希望了解创建这些交互所涉及的细微差别,为他人创建指南,并提出一些不错的功能请求。
于是,AMP CAMP 演示网站 诞生了!
在制作这个网站的过程中,我们学到了很多东西,我们想与你分享。在这一系列文章中,我们将解释我们如何构建网站并创建其交互。你还可以观看本文末尾的演讲。
首先:让我们从一篇关于 AMP Camp 构建流程的文章开始。
我们为什么要使用构建流程?
通常会将软件从一组源文件编译到生产中使用的文件中。这称为构建流程。有时,使用 HTML 执行此操作很方便 - 以更方便的形式创建资源,然后自动将其编译为提供给浏览器的 HTML。
使用 AMP 时,构建流程尤其方便。毕竟,呈现 AMP 网页所需的信息都存储在一个文件中。其 CSS 包含在 <style> 标签中的 HTML 中。如果你不使用 <amp-script>,甚至不会提供单独的 JavaScript 资源。相比之下,几乎所有非 AMP 网页都引用许多其他 CSS 和 JS 文件。AMP 更简单!
尽管如此,在创建 AMP 页面时,你可能不想在单个文件中创建每个页面,除非你的网站非常简单。至少,除非你故意在 JSX 或 Web 组件中组合 CSS 和 HTML,否则使用包含 CSS 和 HTML 的源文件会很混乱。你可能至少希望在单独的文件中创建 CSS 和 HTML,然后使用构建流程将它们组合在一起。
进一步思考,您的网页通常会共享很多相同的 HTML。例如,它们可能具有相同的导航菜单或类似的页脚。从一页复制相同的 HTML 并不是最佳做法。如果您想更改该菜单怎么办?您必须在整个网站上复制并粘贴新的 HTML!该菜单应该保存在其自己的文件中。更普遍地说,您希望从 HTML 部分构建页面。由于 AMP 是一个 HTML 框架,其中 HTML 描述用户交互甚至可以包含逻辑,因此这一点尤其正确。
同样,将所有 CSS 写在一个大文件中并让每个页面加载它几乎不是最佳做法。您可能会争辩说,一旦加载此大文件,它很可能会被缓存,因此当用户浏览您的网站时,他们不会在每个页面上遇到 200K 的渲染阻塞。但如果第一页加载缓慢,用户可能永远无法进入第二页!您真的希望每个页面加载一个较小的 CSS 文件,其中主要只包含该页面上使用的样式。
如果您希望 AMP 页面通过验证,则不能使用超过 75K 的 CSS。此外,该 CSS 必须包含在 HTML 中以节省渲染阻塞网络调用!因此,最好只将 CSS 添加到所需的页面。如果您使用构建过程从部分组装 CSS,然后将其合并到每个 HTML 文件中,那么这一切会容易得多。
因此,就像使用构建过程从较小的部分组装网页通常更轻松、更方便一样,对于 AMP 网页来说也更容易、更方便。作为奖励,已经创建了许多专门针对 AMP 的构建工具,这些工具可以使创建 AMP 页面变得更容易,或者使用户浏览速度更快!要了解更多信息,让我们来看看 AMP Camp 演示网站 中使用的构建过程。
AMP Camp 网站使用 node.js 和 gulp 构建。在本文中,我们将参考 github 上的代码,尤其是 gulpfile。我们还将参考一些方法,帮助你构建出比我们更好的构建流程!
构建我们的 HTML
const fileinclude = require('gulp-file-include');
Code language: JavaScript (javascript)
AMP Camp 从部分内容构建其 HTML,与上面讨论的方式非常相似。由于我们的网站相对简单,我们使用了 fileinclude。也就是说,如果我们稍微扩展一下项目,我们可能需要迁移到更强大的工具。
要查看实际操作,请查看 index.html 的开头,其中包括 <head>、页面页眉、导航菜单和一些其他内容的单独部分
<!doctype html>
%%include('../partials/copyright.html')
<html ⚡="" lang="en">
<head>
%%include('../partials/head.html', {
"pageType": "index"
})
</head>
<body>
%%include('../partials/header.html', {
"pageType": "index"
})
%%include('../partials/menu.html')
Code language: HTML, XML (xml)
其中一些部分包含其他部分。值得注意的是,我们决定将我们的分析内容放入其自己的部分 analytics.html 中,然后 header.html 导入该部分。
构建我们的 CSS
AMP Camp 的 head.html 部分也从子部分构建。这些子部分不是 HTML 文件,而是 CSS 文件。head.html 包含每个页面通用的 CSS 文件
<style amp-custom>
%%include('../../css/global.css')
%%include('../../css/header.css')
%%include('../../css/menu.css')
%%include('../../css/footer.css')
%%include('../../css/social.css')
Code language: PHP (php)
以及每个页面特定的 CSS
%%if (context.pageType == 'index') {
%%include('../../css/index.css')
}
Code language: PHP (php)
要构建更有效的 CSS,你可以将 HTML 分成更小的部分和子部分,并将适当的 CSS 与每个部分关联起来。这样,网站的每个页面真正只包含它所需的 CSS。例如,amp.dev 使用 原子设计 来组织其 CSS,这是一个系统,其中较大的 UI 设计元素包含逐渐更小的元素,一直到“原子”。在此处查看!另一个选择是使用类似 Next.js 的框架,它允许你进行 React 风格的 CSS/HTML 关联。(我们鼓励你在此处了解 Next.js 的 AMP 支持 - 或尝试本教程。)
const sass = require('gulp-sass');
Code language: JavaScript (javascript)
AMP Camp 从 SASS 构建其 CSS,这是一种流行的高级语言,可编译为 CSS。它与 AMP 页面一起使用,就像与非 AMP 页面一起使用一样!
但是,如果您的 SASS 碰巧包含扩展字符,SASS 处理器将自动输出规则以指定字符编码
@charset "UTF-8";
Code language: CSS (css)
不幸的是,此类规则并非适用于位于 <style> 标记中的 CSS 的标准。因此,此规则会激发 AMP 验证器(见下文)抛出错误!
我们的解决方案并不漂亮,但它简单且健壮:在 SASS 完成其工作后,我们 对生成的 CSS 进行后处理 以移除任何此类规则
gulp.task('styles', function buildStyles() {
const cssEncodingDirective = '@charset "UTF-8";';
return gulp.src(paths.css.src)
.pipe(plumber())
.pipe(sass(options.env === 'dist' ? { outputStyle: 'compressed' } : {}))
.pipe(options.env === 'dev' ? replace(cssEncodingDirective, '') : noop())
.pipe(autoprefixer('last 10 versions'))
.pipe(mergeMediaQuery({log: true}))
.pipe(gulp.dest(paths.css.dest));
});
Code language: JavaScript (javascript)
AMP 特有工具
const gulpAmpValidator = require('gulp-amphtml-validator');
Code language: JavaScript (javascript)
说到 AMP 验证,我们希望确保我们的页面始终符合 AMP 的标准,以便它们有资格使用 AMP 缓存,这样我们就可以避免错误,还可以提供快速、可访问的页面。因此,我们的构建流程 包括 AMP 验证器。我们已对其进行设置,以便当任何页面不是有效的 AMP 时,构建就会中断。
gulp.task('validate', function validate() {
return gulp.src(paths.html.dest + '/**/*.html')
.pipe(gulpAmpValidator.validate())
.pipe(gulpAmpValidator.format())
.pipe(gulpAmpValidator.failAfterError());
});
Code language: JavaScript (javascript)
如果我们不希望任何无效页面中断构建,我们可以省略上述 failAfterError() 步骤。
请注意,AMP Camp 的一些页面是从服务器上的模板呈现的。我们不想在服务器中运行验证器!幸运的是,由于我们代入这些模板的内容简单且高度可预测,因此我们有信心对这些模板运行验证。在较大的项目中,在构建过程中呈现一些示例页面并测试它们的有效性会更安全。
const ampOptimizer = require('@ampproject/toolbox-optimizer');
Code language: JavaScript (javascript)
最后,我们出于多种目的使用 AMP 优化器!
- 许多 AMP 组件需要它们自己的小型脚本才能发挥作用。开发人员需要为每个页面跟踪这些脚本,并确保每个脚本都包含在 <head> 中。这就是为什么对于此项目,我们开发了 amphtml-autoscript gulp 模块,它可以检测页面使用哪些组件并自动插入必要的脚本!此功能现已并入 AMP 优化器。
- AMP 页面 包含样板文本,它会隐藏页面,直到 AMP 运行时加载、解析并执行。启动时,AMP 运行时对 DOM 执行各种转换,然后取消隐藏页面。AMP 缓存会预先执行这些转换,将修改后的 HTML 直接提供给您的浏览器,并大幅加快速度。AMP 优化器在您的源代码上执行此操作!这可以让 AMP 页面在您的源代码上 快两倍,因此我们认为它非常宝贵。
- 最后,它会自动插入 强制性 AMP 标记,这样我们就不必这么做了。
AMP Camp 在编译模板的构建过程中运行 AMP 优化器。这意味着我们的模板定界符不能包含尖括号,如 <% 和 %>,因为优化器会将它们解析为 HTML。我们改用方括号 ([% 和 %])。
AMP 优化器也可以在运行时在服务器中使用。如果您这样做,则应缓存经过优化的页面,以避免服务器负载过大。
就是这样
我们希望 AMP Camp 使用的构建过程有助于使您自己的 AMP 项目变得更简单!再次提醒,要了解大型网站的构建过程,请查看 amp.dev 的构建方式。或者,要了解基于 React 的有趣方法,请查看 Concert 示例 或 Article 示例。
敬请期待 AMP CAMP 系列的下一篇文章——我们在客户端和服务器上使用模板的方式。
构建愉快!
作者:Ben Morss,开发者倡导者