【2020年1月】在Raspberry Pi 4的Node-RED中插入Angular Elements并从Hugo上进行部署
去年开始的DJ服务,因为没有化妆而感到不舒服。
去年在圣诞倒数日历活动中创建的一个服务,利用语音识别API实现了通过声音向DJ提出点歌请求的功能。

是的,这是一个完全没有设计的素颜HTML。
虽然这是一个很棒的DJ请求表单,但我想能不能再做点什么…
我正在考虑将一些主题元素嵌入其中,让它变得更有魅力一些。
然而Angular基本上是用于创建单页面应用程序的框架,因此将“主题化的东西”(如页面和组件)称为“样板代码”,需要大量投入。
嗯,不对,不要这样复杂,能不能更简单地组装起来呢…
另外,在另一个方面可以说是”快速找到主题”的是静态网站生成器(Static Site Generator = SSG),但我也尝试了一些好用的SSG。
Jekyll、Gatsby、Hugo…最近的热门服务是Hugo,想在Hugo的网站中混合使用Angular,或者希望Hugo也支持PWA…我正在探索各种可能性。
-
- Hugo のような静的なコンテンツを扱うフレームワークを利用している際に部分的に動的なガジェットが欲しくなることがあります。
- Angular Elements で作ったアプリケーションを Hugo に埋め込む方法をまとめます。 – nananao blog
如何在靜態內容中部分嵌入Angular?
角度元素,这岂不是。
所以,我想要尝试一下“在搭载了树莓派4的Node-RED中,插入Angular Elements组件并使用Hugo生成的HTML进行部署的步骤”。如往常一样,充满了挑战。
目标环境
操作系统:Raspbian Buster 4.19
Node-RED版本:1.0.3
Angular版本:8.2.14
Hugo版本:0.62.1 linux/arm
我们在树莓派上搭建了Angular和Hugo的环境。我们通过VSCode的Remote SSH在树莓派上进行操作。
1. 安装Hugo
有很多方法可以安装Hugo,但考虑到未来,让我们从Snap上安装它。
所以,我们来从Snap上安装吧。
1-1. 安装 Snap
根据Snap官方网站的指导进行安装。
- Installing snap on Raspbian
话虽如此,命令很简单。只需要使用apt安装snapd即可。
$ sudo apt update
$ sudo apt install snapd
在 树莓派4 上安装 snap 完毕。
1-2. 安装Hugo
我們將從Snap進行Hugo的安裝。
- Install Hugo for Linux using the Snap Store | Snapcraft
$ sudo snap install hugo
2019-12-30T12:58:33Z INFO Waiting for restart...
hugo 0.61.0 from Hugo Authors installed
1-3. 霍果的调整?
尽管Hugo已在上述过程中成功安装完成,但当运行hugo命令时却出现了奇怪的错误?
$ hugo new site quickstart
ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libarmmem-${PLATFORM}.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libarmmem-${PLATFORM}.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
Congratulations! Your new Hugo site is created in /home/pi/quickstart.
...
嗯,出现了错误消息。但是看起来hugo项目还是可以正常生成的样子。不太确定是否正常生成,让人感到担心啊……稍微查了一下,发现只有一条完美的POST。
- Install Hugo on Raspberry Pi 4
只是简单地将 /etc/ld.so.preload 中的 /usr/lib/arm-linux-gnueabihf/libarmmem-${PLATFORM}.so 用 # 进行了注释。(就是这样,没有改变。)
#/usr/lib/arm-linux-gnueabihf/libarmmem-${PLATFORM}.so
暂时看起来已经没有错误了,但这样真的可以吗…?
总之我想先进展到这一步。
2. 使用Hugo 创建项目
让我们重新振作起来,尝试创建Hugo的示例项目吧。
- Quick Start | Hugo
$ hugo new site quickstart
...
$ cd quickstart
$ git init
$ git submodule add https://github.com/budparr/gohugo-theme-ananke.git themes/ananke
我尝试添加了Ananke作为最初的主题。(照搬自教程…)
所以,让我们将ananke追加到设置文件中。
...
theme = "ananke"
我们将继续按照教程的指导,尝试添加博客文章。
$ hugo new posts/my-first-post.md
我們先在這裡嘗試啟動Hugo的開發伺服器。
$ hugo server -D
让我们在浏览器中打开localhost:1313。

好的,Hugo的准备工作已经完成了!
将Angular转换为Angular Element兼容的版本。
这次的主要事件是Angular Element,大致上可以这样说。
Angular Elements是一种将Angular组件封装为Web Components的方式。而Web Components是一种不依赖任何框架的Web标准技术,用于定义新的HTML元素。
无论如何,就是可以直接使用在Angular中定义的组件标签。
请详细阅读以下内容。
- angular-elements概要
我想参考之前介绍的关于如何将使用Angular Elements创建的应用程序嵌入Hugo的文章,在之前的文章中,将我们创建的Angular项目适配为Angular Elements。
使用 ng 命令添加 @angular/elements 插件。
$ ng add @angular/elements
...
其实,以上就是结束了!
我打算直接使用AppComponent,所以我会直接使用。Angular默认以app-root标签为起点,所以不需要进行任何配置更改。无需修改配置文件,只需进行JavaScript生成。
$ ng build --prod --output-hashing=none
...
所以
Angular8以后,已经被拆分为es5和es2015两个文件。因此,我们通过package.json的脚本将es5和es2015合并成单个的js文件,如下所示。
由于这个原因,我将分散输出的 js 文件合并成一个单一的 js 文件。由于这个 Angular 项目直接部署在 Node-RED 的静态网站上,所以有点复杂,但命令如下所示。
$ cat ~/node-red-static/DjRequestApp/{runtime-es5,polyfills-es5,scripts,main-es5}.js > ~/node-red-static/DjRequestApp/DjRequestApp-es5.js
$ cat ~/node-red-static/DjRequestApp/{runtime-es2015,polyfills-es2015,scripts,main-es2015}.js > ~/node-red-static/DjRequestApp/DjRequestApp-es2015.js
这里有两个JS文件,一个是DjRequestApp-es5.js,另一个是DjRequestApp-es2015.js,它们将被Hugo用作JS文件。
4. 将Hugo移植到中文平台
4-1. 将 js 和 css 进行复制
现在,按照将生成的 Angular js 文件和 style.css 文件复制到由 hugo 创建的“quickstart”项目中的步骤,我们需要遵循 hugo 中的嵌入过程。目录结构如下所示。
static
├── css
│ └── styles.css
└── js
├── DjRequestApp-es2015.js
└── DjRequestApp-es5.js
4-2. HTML文件的加载,第一部分
我想覆盖Hugo设置的主题模板,并尝试加载上述的js和css。
首先,将quickstart/themes/ananke/layouts/partials/site-header.html文件复制到quickstart/layouts/partials/site-scripts.html中。这将应用于每个页面。
风格 gé)
脚本 -
{{ $script := .Site.Data.webpack_assets.app }}
{{ with $script.js }}
<script src="{{ relURL (printf "%s%s" "dist/" .) }}"></script>
{{ end }}
<script type="module" src="{{ .Site.BaseURL }}/js/DjRequestApp-es2015.js"></script>
<script src="{{ .Site.BaseURL }}/js/DjRequestApp-es5.js" nomodule defer></script>
<link rel="stylesheet" href="{{ .Site.BaseURL }}/css/styles.css">
最初的三行在$script.js中进行循环的部分是原始代码。以下是我们添加的新代码。
4-3. HTML加载,第二部分
下一步终于要在主体的模板HTML中添加。像头部那样,我们将覆盖主题的index.html。
首先,将quickstart/themes/ananke/layouts/index.html复制到quickstart/layouts/index.html。
接下来,在index.html中添加以下代码:标签。
...
...
{{/* As above, Use $section_name to get the section title, and URL. Use "with" to only show it if it exists */}}
{{ with .Site.GetPage "section" $section_name }}
<a href="{{ .Permalink }}" class="link db f6 pa2 br3 bg-mid-gray white dim w4 tc">{{ i18n "allTitle" . }}</a>
{{ end }}
</section>
{{ end }}
</div>
{{ end }}
<div class="pa3 pa4-ns w-100 w-70-ns center">
<app-root></app-root>
</div>
{{ end }}
将一个具有类似样式的div添加到显示博客文章列表的块的后面,其中包含app-root标签。修复工作到此为止,但我不确定这样是否真的能让Angular组件=语音识别API正常工作…
4-4. 更改Hugo的输出目标
Hugo默认将生成的HTML文件等放置在public文件夹中。由于从Hugo生成后再从public复制很麻烦,因此我们尝试直接将其部署到node-red的static文件夹中。
在Hugo的toml文件中添加如下内容。
...
publishDir = "../node-red-static/DjReqChannel"
DjReqChannel可以任意选择,在不与Angular应用程序冲突的情况下即可。
4-5. 更改基地址并生成网站。
顺便说一下,我们还要指定Hugo网站的起始地址。我们要修改baseURL。
配置文件config.toml如下所示。
baseURL = "https://raspberrypi.local:1880/DjReqChannel"
languageCode = "en-us"
title = "My New Hugo Site"
theme = "ananke"
publishDir = "../node-red-static/DjReqChannel"
这次我尝试使用raspberrypi.local而不是localhost。
只需使用hugo命令来生成HTML,就可以完成了!
$ hugo -D
5. 动作确认
嗯,其实从这里开始才是很长的部分呢…
这个事与本文本质上无关,但是发生了很多事情,多亏了这些,我写了两篇文章,总共有12篇。哈哈
好吧,有了一些问题,我终于成功显示了以下的截图。

我刚刚对着麦克风低声说出了”新年快乐”。语音识别API也正常运行!
(因为主题简洁,所以原始的HTML没有太大的变化…)
而且,它也能够正确地显示在Node-RED的调试日志中。

咻…真好动起来了…(如果语音识别API不要求HTTPS,我就不会有这么多麻烦了…)
总结
Angular Elements的嵌入非常简单,但是这次我们直接使用了app-root,所以几乎什么都不用做,很方便。
然而,通常情况下,可能需要导出多个组件并嵌入到网站中。
虽然可以输出多个组件,但据说需要在app.module.ts中进行各种追加,所以目前来看,实际上并不太实用。
如果可以像这次一样真的只需简单地嵌入一个单独的动态小部件(如果可以在Angular项目中这样创建),我认为可以创造出有趣的服务。
【2020年1月】过年之后,我被告知要在Mac上使用Zsh! ↩
【2020年1月】我在Chrome上遇到了Raspberry Pi 4的SSL证书问题,导致无法访问,显示”ERR_CERT_REVOKED”。 ↩