AMP

AMP Camp 构建流程

网站

什么是 AMP Camp?

作为一名开发者倡导者,谈论如何使用 AMP 来创建快速、交互式网站是一回事。而实际构建一个网站则是另一回事!因此,我们中的一些人决定创建一个简单但功能齐全的电子商务网站,涵盖从头到尾的所有内容。我们希望了解创建这些交互所涉及的细微差别,为他人创建指南,并提出一些不错的功能请求。

于是,AMP CAMP 演示网站 诞生了!

https://blog.amp.org.cn/wp-content/uploads/2020/03/AMP-Camp-blog-post-video-compressed-by-Paul-1-2.mp4

在制作这个网站的过程中,我们学到了很多东西,我们想与你分享。在这一系列文章中,我们将解释我们如何构建网站并创建其交互。你还可以观看本文末尾的演讲。

首先:让我们从一篇关于 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.jsgulp 构建。在本文中,我们将参考 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,开发者倡导者