跳转到主要内容

Electron 内部原理:消息循环集成

·阅读时长 4 分钟

这是关于 Electron 内部机制系列文章的第一篇。本文将介绍 Node 的事件循环是如何集成到 Electron 的 Chromium 中的。


曾有许多使用 Node.js 进行 GUI 编程的尝试,例如用于 GTK+ 绑定的 node-gui,以及用于 QT 绑定的 node-qt。但它们都无法在生产环境中使用,因为 GUI 工具包有自己的消息循环,而 Node.js 使用 libuv 进行自己的事件循环,主线程一次只能运行一个循环。因此,在 Node.js 中运行 GUI 消息循环的常用技巧是通过一个间隔非常小的定时器来驱动消息循环,这会使 GUI 界面响应缓慢并占用大量 CPU 资源。

在 Electron 的开发过程中,我们遇到了同样的问题,只是方向相反:我们需要将 Node 的事件循环集成到 Chromium 的消息循环中。

主进程和渲染器进程

在深入了解消息循环集成细节之前,我将首先解释 Chromium 的多进程架构。

在 Electron 中有两种类型的进程:主进程和渲染进程(实际上这已经极大简化了,完整视图请参见 多进程架构)。主进程负责 GUI 工作,例如创建窗口,而渲染进程仅负责运行和渲染网页。

Electron 允许使用 JavaScript 控制主进程和渲染器进程,这意味着我们必须将 Node 集成到这两个进程中。

用 libuv 替换 Chromium 的消息循环

我的第一个尝试是使用 libuv 重写 Chromium 的消息循环。

对于渲染器进程来说这很容易,因为它的消息循环只监听文件描述符和定时器,我只需要实现与 libuv 的接口。

然而,对主进程来说,这要困难得多。每个平台都有自己的 GUI 消息循环。macOS Chromium 使用 NSRunLoop,而 Linux 使用 glib。我尝试了许多技巧来从原生 GUI 消息循环中提取底层文件描述符,然后将它们提供给 libuv 进行迭代,但仍然遇到了无法处理的边界情况。

因此,我最终添加了一个定时器,以很小的间隔轮询 GUI 消息循环。结果是进程占用了恒定的 CPU 使用率,并且某些操作出现了长时间延迟。

在单独的线程中轮询 Node.js 的事件循环

随着 libuv 的成熟,可以采用另一种方法。

libuv 中引入了 backend fd 的概念,它是一个文件描述符(或句柄),libuv 会轮询它来处理事件循环。因此,通过轮询 backend fd,可以在 libuv 有新事件时收到通知。

因此,在 Electron 中,我创建了一个单独的线程来轮询后端文件描述符,并且由于我使用的是系统调用进行轮询而不是 libuv API,因此它是线程安全的。每当 libuv 的事件循环中有新事件时,就会向 Chromium 的消息循环发布一条消息,然后 libuv 的事件将在主线程中进行处理。

通过这种方式,我避免了修改 Chromium 和 Node,并且主进程和渲染器进程使用了相同的代码。

代码

你可以在 electron/atom/common/ 目录下的 node_bindings 文件中找到消息循环集成的实现。对于想要集成 Node.js 的项目来说,它可以很容易地被复用。

更新:实现已移至 electron/shell/common/node_bindings.cc

Electron 播客

·阅读时间 2 分钟

正在寻找 Electron 的入门介绍?最近有两期新播客发布,它们很好地概述了 Electron 是什么、为什么被创建以及它如何被使用。


现已发布

Hanselminutes:使用 Jessica Lord 创建跨平台 Electron 应用

Electron 是“仅在框架中运行的 Chrome”还是远不止于此?Jessica 为 Scott 指明了正确的方向,并解释了 Electron 平台在您的开发世界中究竟扮演着怎样的角色。


JavaScript Air:Electron 应用

Electron 正在成为使用 Web 技术构建跨平台桌面应用程序的一种越来越相关和流行的方式。让我们深入了解这项强大的技术,看看如何利用它来提升我们自己和用户在桌面上的体验。


如果您正在寻找 Electron 的入门介绍,可以听第一期。第二期将更详细地介绍使用 Nylas 的 Evan Morikawa 的精彩技巧构建应用程序。

我们目前正在制作另外两期播客,预计下个月发布,请关注 @ElectronJS Twitter 账户获取更新。

Electron 1.0

·阅读时长 4 分钟

在过去两年中,Electron 帮助开发者使用 HTML、CSS 和 JavaScript 构建跨平台桌面应用程序。现在,我们很高兴与大家分享我们框架和创造它的社区的一个重要里程碑。Electron 1.0 版本现已可在 electronjs.org 上获取。


Electron 1.0

Electron 1.0 代表了 API 稳定性和成熟度的重要里程碑。此版本允许你构建在 Windows、Mac 和 Linux 上具有真正原生外观和感觉的应用程序。借助新的文档、新的工具和一个引导你了解 Electron API 的应用程序,构建 Electron 应用比以往任何时候都更容易。

如果您已准备好构建您的第一个 Electron 应用程序,这里有一份 快速入门指南 助您开始。

我们很期待看到您接下来用 Electron 构建出什么。

Electron 的发展历程

我们在两年前推出 Atom 时就发布了 Electron。当时,Electron 称为 Atom Shell,是我们构建 Atom 的基础框架。在那个时代,Atom 是 Electron 所提供功能的驱动力,我们努力争取 Atom 的初步发布。

现在驱动 Electron 的是一个不断壮大的开发者和公司社区,他们构建了各种各样的应用,从 邮件聊天Git 应用SQL 分析工具种子客户端机器人

在过去两年中,我们看到公司和开源项目都选择 Electron 作为其应用程序的基础。仅在去年,Electron 的下载量就超过了 120 万次。 浏览 一些令人惊叹的 Electron 应用,如果你的应用还没有,也请添加进去。

Electron downloads

Electron API 演示

除了 1.0 版本,我们还发布了一个新应用程序,以帮助你探索 Electron API 并了解如何让你的 Electron 应用具有原生感觉。 Electron API Demos 应用程序包含代码片段,可以帮助你开始开发应用,并提供有效使用 Electron API 的技巧。

Electron API Demos

Devtron

我们还添加了一个新扩展,以帮助你调试 Electron 应用。 DevtronChrome 开发者工具 的一个开源扩展,旨在帮助你检查、调试和故障排除你的 Electron 应用。

Devtron

功能

  • 依赖图,帮助您在主进程和渲染进程中可视化应用程序的内部和外部库依赖关系
  • IPC 监视器,跟踪和显示应用程序进程之间发送和接收的消息
  • 事件检查器,显示您应用程序中核心 Electron API(如窗口、应用和进程)上注册的事件和监听器
  • 应用 Linter,检查您的应用程序是否存在常见错误和缺失功能

Spectron

最后,我们发布了 Spectron 的新版本,它是 Electron 应用程序的集成测试框架。

Spectron

Spectron 3.0 对整个 Electron API 提供了全面的支持,使你能够更快地编写测试,以验证应用程序在各种场景和环境中的行为。Spectron 基于 ChromeDriverWebDriverIO,因此它也拥有完整的页面导航、用户输入和 JavaScript 执行 API。

社区

Electron 1.0 是数百名开发人员社区共同努力的成果。除了核心框架之外,还发布了数百个库和工具,以使构建、打包和部署 Electron 应用程序更加容易。

现在有一个新的 社区 页面,列出了许多令人惊叹的 Electron 工具、应用、库和框架。你还可以查看 ElectronElectron Userland 组织,看看这些精彩的项目。

刚接触 Electron?观看 Electron 1.0 介绍视频

Electron 0.37 的新功能

·阅读时长 5 分钟

Electron 0.37 版本最近已 发布,其中包含从 Chrome 47 到 Chrome 49 的重大升级,以及几个新的核心 API。最新版本带来了 Chrome 48Chrome 49 中发布的所有新功能。这包括 CSS 自定义属性、增强的 ES6 支持、KeyboardEvent 改进、Promise 改进以及你可以在 Electron 应用中使用的许多其他新功能。


新增内容

CSS 自定义属性

如果您使用过 Sass 和 Less 等预处理器语言,您可能熟悉变量,它允许您为颜色方案和布局等内容定义可重用的值。变量有助于保持您的样式表 DRY(不要重复自己)且更易于维护。

CSS 自定义属性类似于预处理变量,因为它们是可重用的,但它们还具有一项独特的质量,使其更加强大和灵活:它们可以通过 JavaScript 进行操作。这种微妙但强大的功能允许动态更改视觉界面,同时仍能受益于 CSS 的硬件加速,并减少前端代码和样式表之间的代码重复。

有关 CSS 自定义属性的更多信息,请参阅 MDN 文章Google Chrome 演示

CSS 变量实战

让我们通过一个简单的变量示例来演示,该示例可以在您的应用中实时调整。

:root {
--awesome-color: #a5ecfa;
}

body {
background-color: var(--awesome-color);
}

变量值可以直接在 JavaScript 中检索和更改

// Get the variable value ' #A5ECFA'
let color = window
.getComputedStyle(document.body)
.getPropertyValue('--awesome-color');

// Set the variable value to 'orange'
document.body.style.setProperty('--awesome-color', 'orange');

变量值也可以从开发工具的样式部分进行编辑,以获得快速反馈和调整

CSS properties in Styles tab

KeyboardEvent.code 属性

Chrome 48 为 KeyboardEvent 事件添加了新的 code 属性,该属性将是按下的物理键,与操作系统键盘布局无关。

这应该能使您的 Electron 应用中自定义键盘快捷键的实现更准确,并在不同机器和配置上更一致。

window.addEventListener('keydown', function (event) {
console.log(`${event.code} was pressed.`);
});

请查看 此示例 了解其实际应用。

Promise 拒绝事件

Chrome 49 添加了两个新的 window 事件,允许你在未处理的 Promise 被拒绝时收到通知。

window.addEventListener('unhandledrejection', function (event) {
console.log('A rejected promise was unhandled', event.promise, event.reason);
});

window.addEventListener('rejectionhandled', function (event) {
console.log('A rejected promise was handled', event.promise, event.reason);
});

请查看 此示例 了解其实际应用。

V8 中的 ES2015 更新

Electron 中 V8 的版本包含了 91% 的 ES2015。以下是一些你无需标志或预编译器即可开箱即用的有趣功能——

默认参数

function multiply(x, y = 1) {
return x * y;
}

multiply(5); // 5

解构赋值

Chrome 49 添加了 解构赋值,可以更轻松地为变量和函数参数赋值。

现在,Electron 的 require 语句可以更清晰、更简洁地进行赋值

浏览器进程的 require
const { app, BrowserWindow, Menu } = require('electron');
渲染进程的 require
const { dialog, Tray } = require('electron').remote;
其他示例
// Destructuring an array and skipping the second element
const [first, , last] = findAll();

// Destructuring function parameters
function whois({ displayName: displayName, fullName: { firstName: name } }) {
console.log(`${displayName} is ${name}`);
}

let user = {
displayName: 'jdoe',
fullName: {
firstName: 'John',
lastName: 'Doe',
},
};
whois(user); // "jdoe is John"

// Destructuring an object
let { name, avatar } = getUser();

新的 Electron API

以下是一些新的 Electron API,您可以在 Electron 发行说明中查看每个新 API。

BrowserWindow 上的 showhide 事件

当窗口显示或隐藏时会发出这些事件。

const { BrowserWindow } = require('electron');

let window = new BrowserWindow({ width: 500, height: 500 });
window.on('show', function () {
console.log('Window was shown');
});
window.on('hide', function () {
console.log('Window was hidden');
});

app 上的 platform-theme-changed 事件,适用于 OS X

当系统的 深色模式主题切换时会发出此事件。

const { app } = require('electron');

app.on('platform-theme-changed', function () {
console.log(`Platform theme changed. In dark mode? ${app.isDarkMode()}`);
});

OS Xapp.isDarkMode()

如果系统处于深色模式,此方法将返回 true,否则返回 false

BrowserWindow 上的 scroll-touch-beginscroll-touch-end 事件,适用于 OS X

当滚动轮事件阶段开始或结束时会发出这些事件。

const { BrowserWindow } = require('electron');

let window = new BrowserWindow({ width: 500, height: 500 });
window.on('scroll-touch-begin', function () {
console.log('Scroll touch started');
});
window.on('scroll-touch-end', function () {
console.log('Scroll touch ended');
});

在 Electron 中使用 V8 和 Chromium 的功能

·阅读时间 2 分钟

构建 Electron 应用程序意味着你只需要创建一个代码库并为一个浏览器进行设计,这非常方便。但由于 Electron 会随着 Node.jsChromium 的发布而保持更新,因此你也可以利用它们提供的出色功能。在某些情况下,这可以消除你之前可能需要在 Web 应用中包含的依赖项。


有很多功能,我们将在此举例说明,但如果你有兴趣了解所有功能,可以关注 Google Chromium 博客Node.js 发行说明。你可以在 electronjs.org/#electron-versions 查看 Electron 使用的 Node.js、Chromium 和 V8 的版本。

通过 V8 支持 ES6

Electron 将 Chromium 的渲染库与 Node.js 相结合。两者共享同一个 JavaScript 引擎,即 V8。许多 ECMAScript 2015 (ES6) 功能已内置于 V8 中,这意味着你可以在 Electron 应用程序中使用它们,无需任何编译器。

以下是一些示例,但你还可以获得类(在严格模式下)、块作用域、Promise、类型化数组等。有关 V8 中 ES6 功能的更多信息,请查看 此列表

箭头函数

findTime () => {
console.log(new Date())
}

字符串插值

var octocat = 'Mona Lisa';
console.log(`The octocat's name is ${octocat}`);

New Target

Octocat() => {
if (!new.target) throw "Not new";
console.log("New Octocat");
}

// Throws
Octocat();
// Logs
new Octocat();

数组包含

// Returns true
[1, 2].includes(2);

Rest 参数

// Represent indefinite number of arguments as an array
(o, c, ...args) => {
console.log(args.length);
};

Chromium 功能

感谢 Google 和贡献者在 Chromium 上付出的辛勤努力,在构建 Electron 应用时,您还可以使用一些很棒的功能,包括(但不限于):

关注 Google Chromium 博客,了解新版本发布的功能,同样,你可以在 此处查看 Electron 使用的 Chromium 版本。

您对什么感到兴奋?

在 Twitter 上 @ElectronJS 与我们分享您最喜欢的 V8 或 Chromium 内置功能。

Electron 1.0 即将到来的 API 变更

·阅读时长 4 分钟

自 Electron(最初名为 Atom-Shell)诞生以来,我们一直在尝试为 Chromium 的内容模块和原生 GUI 组件提供一个不错的跨平台 JavaScript API。API 最初非常自然地形成,随着时间的推移,我们对最初的设计进行了几次更改以进行改进。


现在,随着 Electron 准备发布 1.0 版本,我们希望借此机会通过解决最后几个 API 细节来做出改变。下面描述的更改已包含在 **0.35.x** 版本中,旧 API 将会报告弃用警告,以便你可以为未来的 1.0 版本做好准备。Electron 1.0 版本将在几个月后发布,因此你还有一些时间来进行这些更改。

弃用警告

默认情况下,如果你使用的是已弃用的 API,将会显示警告。要关闭它们,你可以将 process.noDeprecation 设置为 true。要跟踪已弃用 API 用法的位置,你可以将 process.throwDeprecation 设置为 true 以抛出异常而不是打印警告,或者将 process.traceDeprecation 设置为 true 以打印弃用的堆栈跟踪。

使用内置模块的新方式

内置模块现在被分组到一个模块中,而不是分成独立的模块,因此你可以 在不与其他模块冲突的情况下 使用它们。

var app = require('electron').app;
var BrowserWindow = require('electron').BrowserWindow;

`require('app')` 的旧用法仍然受支持以向后兼容,但您也可以将其关闭。

require('electron').hideInternalModules();
require('app'); // throws error.

使用 `remote` 模块的更简便方法

由于内置模块的使用方式已更改,我们使得在渲染器进程中使用主进程模块更加容易。现在您可以直接访问 `remote` 的属性来使用它们。

// New way.
var app = require('electron').remote.app;
var BrowserWindow = require('electron').remote.BrowserWindow;

而不是使用长串的 `require` 调用。

// Old way.
var app = require('electron').remote.require('app');
var BrowserWindow = require('electron').remote.require('BrowserWindow');

拆分 `ipc` 模块

ipc 模块同时存在于主进程和渲染进程中,并且每个方面的 API 都不同,这对新用户来说非常令人困惑。我们将主进程中的模块重命名为 ipcMain,将渲染进程中的模块重命名为 ipcRenderer,以避免混淆。

// In main process.
var ipcMain = require('electron').ipcMain;
// In renderer process.
var ipcRenderer = require('electron').ipcRenderer;

对于 `ipcRenderer` 模块,在接收消息时添加了一个额外的 `event` 对象,以匹配 `ipcMain` 模块中消息的处理方式。

ipcRenderer.on('message', function (event) {
console.log(event);
});

标准化 `BrowserWindow` 选项

`BrowserWindow` 选项的风格因其他 API 的选项而异,并且由于名称中的 `-`,在 JavaScript 中使用起来有点困难。现在它们已标准化为传统的 JavaScript 名称。

new BrowserWindow({ minWidth: 800, minHeight: 600 });

遵循 DOM 的 API 名称约定

Electron 中的 API 名称以前偏好所有 API 名称使用驼峰式命名,例如 UrlURL,但 DOM 有其自己的约定,它们偏好 URL 而不是 Url,同时使用 Id 而不是 ID。我们已执行以下 API 重命名以匹配 DOM 的样式。

  • `Url` 已重命名为 `URL`
  • `Csp` 已重命名为 `CSP`

由于这些更改,您在使用 Electron v0.35.0 构建应用程序时会注意到大量弃用警告。解决这些问题的一个简单方法是将所有 `Url` 实例替换为 `URL`。

`Tray` 事件名称的更改

`Tray` 事件名称的风格与其他模块略有不同,因此已进行重命名以使其与其他模块保持一致。

  • `clicked` 已重命名为 `click`
  • `double-clicked` 已重命名为 `double-click`
  • `right-clicked` 已重命名为 `right-click`

Electron 上的 Mac App Store 和 Windows 自动更新程序

·阅读时间 2 分钟

最近 Electron 添加了两项令人兴奋的功能:兼容 Mac App Store 的构建以及内置的 Windows 自动更新程序。


Mac App Store 支持

v0.34.0 开始,每个 Electron 版本都包含一个与 Mac App Store 兼容的构建。以前,在 Electron 上构建的应用程序不符合 Apple 对 Mac App Store 的要求。其中大多数要求与使用私有 API 有关。为了沙箱化 Electron 以符合要求,需要删除两个模块。

  • crash-reporter
  • auto-updater

此外,在检测 DNS 更改、视频捕获和可访问性功能方面,一些行为也发生了变化。你可以在文档中阅读更多关于这些更改以及 提交你的应用程序到 Mac App Store 的信息。分发版本可以在 Electron 发行页面 上找到,前缀为 mas-

相关拉取请求:electron/electron#3108electron/electron#2920

Windows 自动更新程序

在 Electron v0.34.1 中,auto-updater 模块得到了改进,以便与 Squirrel.Windows 一起使用。这意味着 Electron 提供了在 OS X 和 Windows 上自动更新应用程序的便捷方法。你可以在文档中阅读更多关于 在 Windows 上设置应用程序以实现自动更新 的信息。

相关 Pull Request:electron/electron#1984

Electron 新功能

·阅读时长 4 分钟

最近,Electron 迎来了一些有趣的更新和演讲,这里为您做一个汇总。


来源

截至 v0.32.0,Electron 已更新至 Chrome 45。其他更新包括...

更好的文档

new docs

我们对文档进行了重构和标准化,使其看起来和阅读起来都更好。此外,还有社区贡献的文档翻译,例如日语和韩语。

相关拉取请求:electron/electron#2028electron/electron#2533electron/electron#2557electron/electron#2709electron/electron#2725electron/electron#2698electron/electron#2649

Node.js 4.1.0

v0.33.0 起,Electron 搭载 Node.js 4.1.0。

相关拉取请求: electron/electron#2817

node-pre-gyp

现在,依赖 node-pre-gyp 的模块在从源代码构建时可以 against Electron 编译。

相关拉取请求: mapbox/node-pre-gyp#175

ARM 支持

Electron 现在为 ARMv7 上的 Linux 提供构建。它可在 Chromebook 和 Raspberry Pi 2 等流行平台上运行。

相关问题:atom/libchromiumcontent#138electron/electron#2094electron/electron#366

Yosemite 风格无边框窗口

frameless window

@jaanus 提交的补丁已被合并,它像其他内置的 OS X 应用程序一样,允许在 OS X Yosemite 及更高版本上创建带有系统流量灯的无边框窗口。

相关拉取请求: electron/electron#2776

Google Summer of Code 打印支持

在 Google Summer of Code 之后,我们合并了 @hokein 的补丁,以改进打印支持,并增加了将页面打印成 PDF 文件的功能。

相关问题:electron/electron#2677electron/electron#1935electron/electron#1532electron/electron#805electron/electron#1669electron/electron#1835

Atom

Atom 已升级到 Electron v0.30.6,运行 Chrome 44。目前正在 atom/atom#8779 上进行升级到 v0.33.0 的工作。

演讲

GitHub 用户 Amy PalamountainNordic.js 的演讲中对 Electron 进行了精彩介绍。她还创建了 electron-accelerator 库。

Amy Palomountain:使用 Electron 构建原生应用程序

同样来自 Atom 团队的 Ben OgleYAPC Asia 上发表了关于 Electron 的演讲

Ben Ogle:使用 Web 技术构建桌面应用程序

Atom 团队成员 Kevin Sawicki 和其他人在最近的 Bay Area Electron 用户组聚会上就 Electron 进行了演讲。 视频已经发布,这里有两个。

Electron 的历史,作者:Kevin Sawicki

让 Web 应用感觉像原生应用,作者:Ben Gotow

GitHub 总部的 Electron 见面会

·一分钟阅读

9 月 29 日,加入我们在 GitHub 总部举行的 Electron 聚会,由 Atom 团队成员 @jlord@kevinsawicki 主持。将有演讲、小吃,以及交流和认识其他使用 Electron 做酷炫事情的人的时间。我们还将安排一些闪电演讲,感兴趣的人可以参加。希望在那里见到你!


演讲

  • 来自 JiboJonathan RossFrancois Laberge 将分享他们如何使用 Electron 为机器人赋予生命。
  • Jessica Lord 将分享关于使用 Electron 构建的教学工具 Git-it
  • Tom Moor 将分享使用 Electron 构建视频和屏幕共享应用的利弊,并介绍 speak.io
  • Ben Gotow 将预览 N1:Nylas 邮件客户端,并谈谈在 Electron 上开发它的经验。

详细信息

  • 地点: GitHub 总部,275 Brannan Street, San Francisco, CA, 94107
  • 日期: 2015年9月29日,星期二
  • 时间: 晚上6点 - 9点
  • 报名: ti.to/github-events/electron-meetup

electron-meetup-office-2

Electron 文档

·阅读时长 5 分钟

本周,我们为 Electron 的文档在 electronjs.org 上建立了家园。你可以访问 /docs/latest 获取最新文档。我们也会保留旧版本的文档,这样你就可以访问 /docs/vX.XX.X 来查看与你正在使用的版本对应的文档。


你可以访问 /docs 查看哪些版本可用,或者访问 /docs/all 在一页上查看最新版本的文档(方便使用 cmd + f 搜索)。

如果你想为文档内容做出贡献,可以在 Electron 仓库中进行,文档是从那里获取的。我们为每个次要版本获取它们,并将其添加到 Electron 网站仓库,该仓库是用 Jekyll 构建的。

如果您有兴趣了解更多关于我们如何将文档从一个仓库拉取到另一个仓库的信息,请继续阅读下面的内容。否则,请尽情享用 文档

技术细节

我们正在保留 Electron 核心仓库中的文档。这意味着 electron/electron 将始终拥有最新版本的文档。当发布新版本的 Electron 时,我们会将其复制到 Electron 网站仓库 electron/electronjs.org

script/docs

为了获取文档,我们使用 script/docs vX.XX.X(根据是否为最新版本,带或不带 --latest 选项)的命令行界面运行一个 脚本。我们的 获取文档的脚本 使用了几个有趣的 Node 模块。

测试 帮助我们了解所有组件是否按预期落地。

Jekyll

Electron 网站是一个 Jekyll 站点,我们为文档使用 Collections 功能,结构如下:

electron.atom.io
└── _docs
├── latest
├── v0.27.0
├── v0.26.0
├── so on
└── so forth

Front matter

为了让 Jekyll 渲染每个页面,它至少需要空的 front matter。我们将在所有页面上使用 front matter,因此在流式传输 /docs 目录时,我们会检查文件是否为 README.md 文件(在这种情况下,它会收到一个 front matter 配置),或者是否是任何其他具有 markdown 扩展名的文件(在这种情况下,它会收到略有不同的 front matter)。

每个页面都接收这组 front matter 变量:

---
version: v0.27.0
category: Tutorial
title: 'Quick Start'
source_url: 'https://github.com/electron/electron/blob/master/docs/tutorial/quick-start.md'
---

README.md 文件会额外获得一个 permalink,这样它的 URL 根目录就是 index.html,而不是一个不方便的 /readme/

permalink: /docs/v0.27.0/index.html

配置和重定向

在站点的 _config.yml 文件中,每次使用 --latest 标志获取文档时,都会设置一个 latest_version 变量。我们还添加了已添加到网站的所有版本的列表,以及我们希望为整个文档集设置的永久链接。

latest_version: v0.27.0
available_versions:
- v0.27.0
collections:
docs: { output: true, permalink: '/docs/:path/' }

我们站点根目录中的 latest.md 文件为空,只有 front matter,这使得用户可以通过访问 URL electron.atom.io/docs/latest 来查看最新版本文档的索引(即 README),而不是使用最新的版本号(尽管你也可以这样做)。

---
permalink: /docs/latest/
redirect_to: /docs/{{ site.data.releases[0].version }}
---

布局

docs.html 布局模板中,我们使用条件语句来显示或隐藏标题和面包屑中的信息。

{% raw %} {% if page.category != 'ignore' %}
<h6 class="docs-breadcrumb">
{{ page.version }} / {{ page.category }} {% if page.title != 'README' %} / {{
page.title }} {% endif %}
</h6>
{% endif %} {% endraw %}

为了创建一个显示可用版本的页面,我们只需要遍历站点根目录 versions.md 文件中的配置列表。此外,我们为该页面设置了永久链接:/docs/

{% raw %} {% for version in site.available_versions %} - [{{ version
}}](/docs/{{ version }}) {% endfor %} {% endraw %}

希望你喜欢这些技术细节!如果你对使用 Jekyll 构建文档网站感兴趣,可以看看 GitHub 的文档团队如何使用 GitHub 来记录 GitHub