React應用程式
- 主題:
- 內容片段
建立對象:
- 初學者
- 開發人員
AEM Headless as a Cloud Service
範例應用程式是探索Adobe Experience Manager (AEM)無頭式功能的絕佳方式。 此React應用程式示範了如何使用AEM的GraphQL API透過持續性查詢來查詢內容。 適用於JavaScript的AEM Headless Client是用來執行GraphQL持續性查詢,以支援此應用程式。
使用AEM Headless
在GitHub🔗上檢視原始程式碼
提供完整的逐步教學課程,說明此React應用程式的建置方式。
先決條件
下列工具應在本機安裝:
AEM需求
React應用程式可與下列AEM部署選項搭配使用。 所有部署都需要安裝WKND網站v3.0.0+。
React應用程式的設計是要連線至 AEM Publish 環境,不過,如果React應用程式的設定中有提供驗證,則它可以從AEM Author取得內容。
使用方式
-
複製
adobe/aem-guides-wknd-graphql
存放庫:$ git clone git@github.com:adobe/aem-guides-wknd-graphql.git
-
編輯
aem-guides-wknd-graphql/react-app/.env.development
檔案並將REACT_APP_HOST_URI
設定為指向您的目標AEM。如果連線到作者執行個體,請更新驗證方法。
# 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
-
開啟終端機並執行命令:
$ 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的持久查詢會透過HTTP GET執行,因此,JavaScript的AEM Headless使用者端是用來對AEM 執行持久的GraphQL查詢,並將冒險內容載入應用程式。
每個持續查詢在src/api/usePersistedQueries.js
中具有對應的React useEffect勾點,該勾點會非同步呼叫AEM HTTP GET持續查詢端點,並傳回冒險資料。
每個函式又會叫用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應用程式使用兩個檢視,在網頁體驗中呈現冒險資料。
-
src/components/Adventures.js
從
src/api/usePersistedQueries.js
叫用getAdventuresByActivity(..)
並在清單中顯示傳回的冒險。 -
src/components/AdventureDetail.js
使用透過
Adventures
元件上的冒險選項傳入的slug
引數叫用getAdventureBySlug(..)
,並顯示單一冒險的詳細資料。
環境變數
有數個環境變數可用來連線至AEM環境。 預設會連線到在http://localhost:4503
執行的AEM發佈。 更新.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上使用開發Token進行本機開發basic
:透過本機AEM Author將使用者/通行證用於本機開發- 留空可連線至AEM而不進行驗證
-
REACT_APP_AUTHORIZATION=admin:admin
:設定在連線至AEM Author環境時要使用的基本驗證認證(僅供開發)。 如果連線到發佈環境,就不需要此設定。 -
REACT_APP_DEV_TOKEN
:開發權杖字串。 若要連線到遠端執行個體,您可以在基本驗證(user:pass)旁邊,透過雲端主控台的DEV權杖使用持有者驗證 -
REACT_APP_SERVICE_TOKEN
:服務認證檔案的路徑。 若要連線到遠端執行個體,也可使用服務權杖完成驗證(從Developer Console下載檔案)。
Proxy AEM請求
使用webpack開發伺服器(npm start
)時,專案依賴使用http-proxy-middleware
的Proxy安裝程式。 檔案設定於src/setupProxy.js,且依賴於.env
和.env.development
上設定的數個自訂環境變數。
如果連線到AEM作者環境,則需要設定對應的驗證方法。
跨原始資源共用(CORS)
此React應用程式仰賴在目標AEM環境上執行的AEM型CORS設定,並假設React應用程式以開發模式在http://localhost:3000
上執行。 請檢閱AEM Headless部署檔案,以取得如何設定和設定CORS的詳細資訊。