概述
用于组织Qiita股票的" Mindexer"服务的前端
我重建了用Vue.js构建的SPA应用程序,以使用Nuxt.js进行SSR。
我正在Lambda和Nuxt.js上运行Express服务器。
在本文中,我想解释与该开发中获得的Nuxt.js相关的技巧和基础结构配置。
另外,不包括有关从Vue.js进行迁移的说明。
关于服务
在本文中解释了" Mindexer"。
它还说明了后端使用的技术,因此希望您能一起看到它。
AWS Laravel Vue.js创建了一项服务来组织Qiita股票! [个人发展]
从EC2到Fargate取代了个人开发的基础架构!
源代码
所有源代码都在这里可用。
Nuxt.js:https://github.com/nekochans/qiita-stocker-frontend
地形:https://github.com/nekochans/qiita-stocker-terraform
迁移到Nuxt.js
的原因
原因如下。
- 因为我想通过SSR提高页面显示速度
- 因为我想介绍BFF层(在服务器端执行身份验证部分更安全)
- 因为我想使用Nuxt的布局功能
选择架构
的原因
我担心选择运行Nuxt.js的体系结构。
选项包括AWS Fargate和GAE(Google App Engine)。
起初,我以为GAE(Google App Engine)会很容易,但是我停下来了,因为在这里的合作似乎很复杂,因为我使用Route53作为域注册商,并使用ACM作为证书。
最后,我选择在AWS Lambda上运行Nuxt.js。
原因如下。
- 除非访问次数大大增加,否则运行成本很低
- 只能使用AWS上的服务来完成
在AWS Lambda上运行Nuxt.js的设置变得有些复杂,因此我将在下一部分中对此进行说明。
技术元素
- Nuxt.js v2.10.0
- Vue.js Vuex
- typescript
- 无服务器框架
基础架构配置
AWS配置图
前端
我正在Lambda和Nuxt.js上运行Express服务器。
首先,使用CloudFront分发对S3和API网关的访问。
静态资源(例如图像和JavaScript文件)是从S3分发的,对SSR和BFF的访问是通过API网关从Lambda分发的。
后端
后端API由ECS Fargate分发。
本文介绍了ECS Fargate,因此,如果您愿意,请在这里看看。
从EC2到Fargate取代了个人开发的基础架构!
基础设施建设
AWS基础结构配置图中显示的资源构造有些复杂,但是它是由两个
-
无服务器框架
- API网关
- 拉姆达
-
地貌
- CloudFront
- S3
首先,在解释AWS资源之前,我想解释在Lambda上运行的Express服务器,然后看一下AWS资源。
快递服务器
选择
Nuxt.js的
Nuxt.js用作Express服务器的中间件。
除此之外,Express服务器还充当BFF的角色。
Nuxt.js渲染(SSR)
通过调用
API:nuxt.render(req,res)--NuxtJS
BFF(前端后端)
主要扮演以下角色。
- 将对多个Web API的请求处理组合为一个
- 执行SSR(服务器端渲染)(这是通过Nuxt的机制完成的)
由于您可以正常编写服务器端代码(Express等代码可以正常工作),因此在此处编写围绕身份验证的处理会更简单。
另外,访问外部API时使用的凭据(API Secret等)也可以隐藏为服务器端环境变量,从而提高了安全性。
这次,使用Qiita帐户登录的部分已被修改为可以在此BFF上完成。
作为补充,使用
API:serverMiddleware属性--NuxtJS
无服务器
到目前为止,我已经解释了Nuxt.js在Express的服务器上运行,但是我想看看Express如何在Lambda上运行。
无服务器框架
无服务器框架是用于配置管理和部署无服务器应用程序的CLI工具。您可以使用无服务器框架轻松地部署到AWS Lmabda。
以下文章对有关无服务器框架的说明很有帮助,因此我将其发布。
如何使用无服务器框架
的摘要
在这种情况下,我们将执行以下操作:
- 创建Lambda和API网关
- 部署到Lamnda
为了通过Lambda交付Nuxt.js,您需要一个API网关作为调用Lambda的网关。
准备API网关并将HTTP请求发送到Lambda。
有关API网关设置,请检查以下内容。
无服务器框架--AWS Lambda事件--API网关
另外,以下库用于在Lambda上分发Nuxt.js。
- AWS无服务器表达
- 无服务器插件预热
aws-serverless-express
您可以使用AWS Labs提供的aws-serverless-express在Lambda上运行Express服务器。
无服务器插件warmup
用于Lambda的冷启动措施。
在下面的文章中详细描述了详细信息,因此我将其发布。
通过无服务器框架
采取措施防止Lambda冷启动
S3,CloudFront
Terraform管理由无服务器框架创建的AWS资源以外的所有资源。
即使SPA是随Vue.js一起交付的,其基础结构仍由Terraform(包括后端)管理。
在这里,我将不接触Terraform来解释S3和CloudFront的设置。
假定Lambda和API Gateway是由Serverless Framework创建的。
S3
准备一个S3存储桶以传递静态资源,例如图像和JavaScript文件。
访问策略设置如下,并且仅允许从CloudFront(GetObject)访问。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | { "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <CloudFrontのID>" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::<S3バケット>/*" } ] } |
另外,S3存储桶中的对象具有以下目录结构。 (我将省略有关如何部署到S3的说明。)
1 2 | ├── _nuxt # Nuxt.jsのクライアントのリソース └── assets # 画像などの静的リソース |
运行
该客户端的源代码将是一个JavaScript文件,可以将其上传到您的CDN。
CDN设置由
API:构建属性--NuxtJS
CloudFront
在
基础结构配置部分中,我提到了
起源 h5>
S3和Api网关均已注册。
S3
<表格>
tr>
header>
<身体>
tr>
tr>
tr>
tr>
tr>
tbody>
table>
我将
ApiGateway
<表格>
tr>
header>
<身体>
tr>
tr>
tr>
tr>
tr>
tr>
tr>
tr>
tr>
tr>
tbody>
table>
如果未设置舞台,则默认值为
行为 h5>
按路径设置原点分布。
<表格>
tr>
header>
<身体>
tr>
tr>
tr>
tbody>
table>
为了解释
设置,Nuxt.js客户端代码将访问
另外,静态文件(图标等)也被设置为分发到S3存储桶。
其他请求将分发到API网关。
适用的源代码在这里。
https://github.com/nekochans/qiita-stocker-terraform/blob/master/modules/aws/frontend/cloudfront.tf
Nuxt.js提示
目录结构
1 2 3 4 | ├── app # Nuxt.jsのコード ├── server # Expressのコード ├── nuxt.config.ts └── serverless.yml |
-
我将Nuxt.js代码放在
app 中,将Express代码放在server 中,并将其设置为在构建时的结果如下。-
/.nuxt :Nuxt.js代码 -
/dist :快递代码
-
-
静态资源(例如
图像)位于
app/static/assets 上。
CloudFront将请求分发到S3和API网关,但是通过这样设置,可以轻松设置CloudFront。
Nuxt.js TypeScript支持
Nuxt.js v2.10正式支持TypeScript。
请检查以下设置。
Nuxt TypeScript
我根据上述文档进行了设置,但是我想描述一下它,因为在某些地方会发生错误。
-
将
@nuxt/typescript-build 移至dependencies
在
CodeBuild上构建时,如果将
- 避免在开发模式下生成错误
在
开发人员模式下,它是由
对于
开发模式,将
服务器/核心/nuxt.ts
1 2 3 4 5 6 7 8 9 10 11 12 | import config from '../../nuxt.config' const { Nuxt } = require('nuxt') config.dev = !(process.env.NODE_ENV === 'production') if (config.dev) { config.extensions = ['ts'] // 追加 } export const nuxt = new Nuxt(config) export default config |
如果未添加,则
.nu??xt / store.js
1 2 3 4 | function resolveStoreModules (moduleData, filename) { moduleData = moduleData.default || moduleData // Remove store src + extension (./foo/index.js -> foo/index) const namespace = filename.replace(/\.(js|mjs)$/, '') //tsが含まれない |
-
添加了
nuxt.ready()
在Lambda上运行Nuxt.js时,出现错误,因为我没有添加以下设置。
原因是从Nuxt.js 2.5.x开始,在执行new Nuxt() 之后,除非我调用nuxt.ready() ,否则服务器不会渲染。通过采取以下措施解决了该问题。
服务器/app.ts
1 2 3 4 5 6 7 8 | // 変更前 app.use(nuxt.render) // 変更後 app.use(async (req, res, next) => { await nuxt.ready() nuxt.render(req, res, next) }) |
错误页
有两种显示错误页面的方法。
使用Nuxt.js的Layout属性
视图--NuxtJS(错误页面)
从API返回错误时显示。
发生错误时,通过调用
API:上下文--NuxtJS(错误(功能))
页面组件
应用程式/页面/股票/ all.vue
1 2 3 4 5 6 7 8 9 10 11 | async fetch({ store, error }: Context) { try { await store.dispatch('qiita/fetchUncategorizedStocks') await store.dispatch('qiita/saveDisplayCategoryId', 0) } catch (e) { error({ statusCode: e.code, message: e.message }) } } |
除页面组件之外的
应用程序/组件/页面/库存/ All.vue
1 2 3 4 5 6 7 8 9 10 | async onClickDestroyCategory(categoryId: number) { try { await this.destroyCategory(categoryId) } catch (error) { return this.$nuxt.error({ statusCode: error.code, message: error.message }) } } |
扩展由Nuxt.js创建的路由,并转换到错误页面
API:路由器属性--NuxtJS(extendRoutes)
如果
BFF中发生错误,它将转换为
扩展由Nuxt.js创建的路由,以创建错误页面。
如果BFF中发生错误,它将重定向到
将
nuxt.config.ts
1 2 3 4 5 6 7 8 9 10 11 | router: { middleware: ['authCookieMiddleware', 'redirectMiddleware'], extendRoutes(routes: any, resolve) { routes.push({ name: 'original_error', path: '/error', props: true, component: resolve(__dirname, 'app/pages/error.vue') }) } }, |
Middllwere
Middllwere用于执行与身份验证相关的处理。
API:中间件属性--NuxtJS
- authCookieMiddleware.ts:将存储在cookie中的凭据保存在Vuex商店中
- redirectMiddleware.ts:根据需要从用户的身份验证状态重定向
Middll仅通过将以下内容添加到
Middll按照此处描述的顺序工作。 (