React应用程序 react-app
[AEM Headlessas a Cloud Service]{class="badge informative"}
示例应用程序是探索Adobe Experience Manager (AEM)的Headless功能的绝佳方法。 此React应用程序演示了如何通过AEM的GraphQL API,使用持久化查询来查询内容。 适用于JavaScript的AEM Headless客户端用于执行为应用程序提供支持的GraphQL持久查询。
使用AEM Headless的
在GitHub🔗上查看源代码
提供了完整的分步教程,其中介绍了如何生成此React应用程序。
先决条件 prerequisites
应在本地安装以下工具:
AEM要求
React应用程序可与以下AEM部署选项配合使用。 所有部署都需要安装WKND站点v3.0.0+。
React应用程序设计用于连接到 AEM Publish 环境,但是,如果在React应用程序的配置中提供身份验证,则该应用程序可以从AEM Author获取内容。
使用方法
-
克隆
adobe/aem-guides-wknd-graphql
存储库:code language-shell $ git clone git@github.com:adobe/aem-guides-wknd-graphql.git
-
编辑
aem-guides-wknd-graphql/react-app/.env.development
文件并将REACT_APP_HOST_URI
设置为指向您的目标AEM。如果连接到作者实例,请更新身份验证方法。
code language-plain # Server namespace REACT_APP_HOST_URI=https://publish-p123-e456.adobeaemcloud.com #AUTH (Choose one method) # Authentication methods: 'service-token', 'dev-token', 'basic' or leave blank to use no authentication REACT_APP_AUTH_METHOD=basic # For Bearer auth, use DEV token (dev-token) from Cloud console REACT_APP_DEV_TOKEN=dev-token # For Service toke auth, provide path to service token file (download file from Cloud console) REACT_APP_SERVICE_TOKEN=auth/service-token.json # For Basic auth, use AEM ['user','pass'] pair (eg for Local AEM Author instance) REACT_APP_BASIC_AUTH_USER=admin REACT_APP_BASIC_AUTH_PASS=admin
-
打开终端并运行以下命令:
code language-shell $ cd aem-guides-wknd-graphql/react-app $ npm install $ npm start
-
新的浏览器窗口应在http://localhost:3000上加载
-
应用程序上应显示WKND引用站点中的冒险列表。
代码
以下摘要介绍了React应用程序的构建方式、它如何连接到AEM Headless以使用GraphQL持久查询检索内容,以及这些数据的呈现方式。 可在GitHub上找到完整代码。
持久查询
遵循AEM Headless最佳实践,React应用程序使用AEM GraphQL持久查询来查询冒险数据。 该应用程序使用两个持久查询:
wknd/adventures-all
持久查询,该查询返回AEM中的所有冒险,其中具有一组删节的属性。 此持久查询驱动初始视图的冒险列表。
# Retrieves a list of all Adventures
#
# Optional query variables:
# - { "offset": 10 }
# - { "limit": 5 }
# - {
# "imageFormat": "JPG",
# "imageWidth": 1600,
# "imageQuality": 90
# }
query ($offset: Int, $limit: Int, $sort: String, $imageFormat: AssetTransformFormat=JPG, $imageWidth: Int=1200, $imageQuality: Int=80) {
adventureList(
offset: $offset
limit: $limit
sort: $sort
_assetTransform: {
format: $imageFormat
width: $imageWidth
quality: $imageQuality
preferWebp: true
}) {
items {
_path
slug
title
activity
price
tripLength
primaryImage {
... on ImageRef {
_path
_dynamicUrl
}
}
}
}
}
wknd/adventure-by-slug
持久查询,该查询返回由slug
(唯一标识冒险的自定义属性)通过一组完整属性进行的单次冒险。 此持久查询为冒险详细信息视图提供支持。
# Retrieves an Adventure Fragment based on it's unique slug.
#
# Required query variables:
# - {"slug": "bali-surf-camp"}
#
# Optional query variables:
# - {
# "imageFormat": "JPG",
# "imageSeoName": "my-adventure",
# "imageWidth": 1600,
# "imageQuality": 90
# }
#
# This query returns an adventure list but since the the slug property is set to be unique in the Content Fragment Model, only a single Content Fragment is expected.
query ($slug: String!, $imageFormat:AssetTransformFormat=JPG, $imageSeoName: String, $imageWidth: Int=1200, $imageQuality: Int=80) {
adventureList(
filter: {slug: {_expressions: [{value: $slug}]}}
_assetTransform: {
format: $imageFormat
seoName: $imageSeoName
width: $imageWidth
quality: $imageQuality
preferWebp: true
}) {
items {
_path
title
slug
activity
adventureType
price
tripLength
groupSize
difficulty
price
primaryImage {
... on ImageRef {
_path
_dynamicUrl
}
}
description {
json
plaintext
html
}
itinerary {
json
plaintext
html
}
}
_references {
... on AdventureModel {
_path
slug
title
price
__typename
}
}
}
}
执行GraphQL持久查询
AEM的持久查询通过HTTPGET执行,因此,JavaScript的AEM Headless客户端用于对AEM执行持久的GraphQL查询并将冒险内容加载到应用程序中。
每个持久查询在src/api/usePersistedQueries.js
中具有相应的React useEffect挂接,该挂接异步调用AEM HTTPGET持久查询终结点,并返回冒险数据。
每个函数依次调用aemHeadlessClient.runPersistedQuery(...)
,执行持久的GraphQL查询。
// src/api/usePersistedQueries.js
/**
* React custom hook that returns a list of adevntures by activity. If no activity is provided, all adventures are returned.
*
* Custom hook that calls the 'wknd-shared/adventures-all' or 'wknd-shared/adventures-by-activity' persisted query.
*
* @returns an array of Adventure JSON objects, and array of errors
*/
export function useAdventuresByActivity(adventureActivity, params = {}) {
...
let queryVariables = params;
// If an activity is provided (i.e "Camping", "Hiking"...) call wknd-shared/adventures-by-activity query
if (adventureActivity) {
// The key is 'activity' as defined in the persisted query
queryVariables = { ...queryVariables, activity: adventureActivity };
// Call the AEM GraphQL persisted query named "wknd-shared/adventures-by-activity" with parameters
response = await fetchPersistedQuery("wknd-shared/adventures-by-activity", queryVariables);
} else {
// Else call the AEM GraphQL persisted query named "wknd-shared/adventures-all" to get all adventures
response = await fetchPersistedQuery("wknd-shared/adventures-all", queryVariables);
}
...
}
...
/**
* Private function that invokes the AEM Headless client.
*
* @param {String} persistedQueryName the fully qualified name of the persisted query
* @param {*} queryParameters an optional JavaScript object containing query parameters
* @returns the GraphQL data or an error message
*/
async function fetchPersistedQuery(persistedQueryName, queryParameters) {
let data;
let err;
try {
// AEM GraphQL queries are asynchronous, either await their return or use Promise-based .then(..) { ... } syntax
const response = await aemHeadlessClient.runPersistedQuery(
persistedQueryName,
queryParameters
);
// The GraphQL data is stored on the response's data field
data = response?.data;
} catch (e) {
// An error occurred, return the error messages
err = e
.toJSON()
?.map((error) => error.message)
?.join(", ");
console.error(e.toJSON());
}
return { data, err };
}
视图
React应用程序使用两个视图在Web体验中展示冒险数据。
-
src/components/Adventures.js
从
src/api/usePersistedQueries.js
中调用getAdventuresByActivity(..)
并在列表中显示返回的冒险。 -
src/components/AdventureDetail.js
使用通过
Adventures
组件上的冒险选择传入的slug
参数调用getAdventureBySlug(..)
,并显示单个冒险的详细信息。
环境变量
多个环境变量用于连接到AEM环境。 默认连接到http://localhost:4503
上运行的AEM Publish。 更新.env.development
文件以更改AEM连接:
-
REACT_APP_HOST_URI=https://publish-p123-e456.adobeaemcloud.com
:设置为AEM目标主机 -
REACT_APP_GRAPHQL_ENDPOINT=/content/graphql/global/endpoint.json
:设置GraphQL终结点路径。 此React应用程序不使用此选项,因为此应用程序仅使用持久化查询。 -
REACT_APP_AUTH_METHOD=
:首选的身份验证方法。 可选,根据默认情况,不使用身份验证。service-token
:使用服务凭据获取AEM as a Cloud Service上的访问令牌dev-token
:在AEM as a Cloud Service上使用开发令牌进行本地开发basic
:使用用户/通行证进行本地AEM创作程序的本地开发- 留空以在不进行身份验证的情况下连接到AEM
-
REACT_APP_AUTHORIZATION=admin:admin
:设置连接到AEM Author环境时要使用的基本身份验证凭据(仅用于开发)。 如果连接到Publish环境,则不需要此设置。 -
REACT_APP_DEV_TOKEN
:开发令牌字符串。 要连接到远程实例,在基本身份验证(user:pass)旁边,您可以从云控制台将持有者身份验证与开发令牌结合使用 -
REACT_APP_SERVICE_TOKEN
:服务凭据文件的路径。 要连接到远程实例,还可以使用服务令牌进行身份验证(从Developer Console下载文件)。
代理AEM请求
使用webpack开发服务器(npm start
)时,项目依赖于使用http-proxy-middleware
的代理设置。 该文件在src/setupProxy.js中配置,并且依赖在.env
和.env.development
设置的多个自定义环境变量。
如果连接到AEM创作环境,则需要配置相应的身份验证方法。
跨源资源共享(CORS)
此React应用程序依赖于在目标AEM环境中运行的基于AEM的CORS配置,并假定React应用程序在开发模式下在http://localhost:3000
上运行。 查看AEM Headless部署文档以了解有关如何设置和配置CORS的详细信息。