헤드리스 Oracle Content Management로 다음.js에 블로그 구축
소개
Next.js는 서버측 렌더링, React 기반 웹 애플리케이션용 정적 웹 사이트 생성 등의 기능을 지원하는 오픈 소스 React 프론트 엔드 개발 웹 프레임워크입니다. CMS(Content Management System)에서 모든 컨텐츠를 제공해야 하는 경우 어떻게 됩니까? 다행히도 풍부한 헤드리스 CMS 기능을 갖춘 Oracle Content Management는 컨텐츠 관리 및 거버넌스 요구사항을 위한 최고의 솔루션을 제공합니다.
이 사용지침서에서는 Oracle Content Management를 헤드리스 CMS로, JavaScript에서 콘텐츠 전달을 위해 SDK(소프트웨어 개발 키트)를 활용하여 Next.js에서 간단한 블로그를 구축합니다. 이 Next.js 샘플은 GitHub에서 사용할 수 있습니다.
이 튜토리얼은 다음 세 가지 작업으로 구성됩니다.
필요 조건
이 튜토리얼을 계속하기 전에 먼저 다음 정보를 읽는 것이 좋습니다.
이 자습서를 따르려면 다음이 필요합니다.
- Oracle Content Management 가입
- 콘텐츠 관리자 롤이 있는 Oracle Content Management 계정
- 노드 버전이 10 이상인 Windows 또는 Mac 컴퓨터
우리가 구축하고 있는 것
이 블로그는 방문자들이 주제로 구성된 블로그 기사를 탐색할 수 있는 3페이지 분량의 사이트로 구성됩니다. 첫 번째 페이지인 홈 페이지는 브랜딩(회사 이름 및 로고), 일부 링크 및 블로그 항목 목록으로 구성됩니다.
빌드 중인 내용에 대해 살펴보기 위해 자습서의 최종 상태는 Oracle Content Management의 콘텐츠를 사용하는 기본 Next.js 블로그입니다.
https://headless.mycontentdemo.com/samples/oce-nextjs-blog-sample
다음은 이 자습서의 마지막 부분인 홈 페이지입니다.

두번째 페이지인 토픽 페이지는 해당 항목에 속하는 각 블로그 문서의 미리보기를 보여줍니다. 개별 항목 페이지가 표시되는 방법은 다음과 같습니다.

마지막으로 입자 페이지는 블로그 작성자에 대한 정보를 포함하여 최종 블로그 문서를 렌더링합니다. 개별 기사 페이지가 표시되는 방법은 다음과 같습니다.

계속하려면 Oracle Content Management에 대한 활성 구독이 있어야 하며 콘텐츠 관리자 역할로 로그인해야 합니다.
작업 1: Oracle Content Management 준비
Oracle Content Management 인스턴스가 아직 없는 경우 빠른 시작을 참조하여 Oracle Cloud에 등록하고, Oracle Content Management 인스턴스를 프로비전하고, 헤드리스 CMS로 Oracle Content Management를 구성하는 방법을 알아보십시오.
이 자습서에서는 두 가지 방법 중 하나로 콘텐츠 모델을 생성해야 합니다. 다운로드 가능한 자산 팩을 사용하여 빈 저장소를 콘텐츠 유형 및 연관된 콘텐츠로 채우거나 고유의 콘텐츠 모델과 콘텐츠를 생성할 수 있습니다.
Oracle Content Management를 준비하려면 다음을 수행합니다.
- 채널 및 자산 저장소 생성.
- 두 가지 방법 중 하나를 사용하여 콘텐츠 모델을 생성합니다.
- 방법 1: Oracle Content Management 샘플 자산 팩 임포트
- 방법 2: 고유한 콘텐츠 모델 생성
채널 및 자산 저장소 생성
먼저 콘텐츠를 게시할 수 있도록 Oracle Content Management에서 채널과 자산 저장소를 생성해야 합니다.
Oracle Content Management에서 채널 및 자산 저장소를 생성하려면 다음과 같이 하십시오.
Oracle Content Management 웹 인터페이스에 관리자로 로그인합니다.
왼쪽 탐색 메뉴에서 콘텐츠를 선택하고 페이지 헤더의 선택 목록에서 채널 게시를 선택합니다.

오른쪽 상단 모서리에서 생성을 눌러 새 채널을 생성합니다. 이 자습서의 목적을 위해 채널 이름을 'OCEGettingStartedChannel'로 지정하고 액세스를 공개로 유지합니다. 저장을 눌러 채널을 생성합니다.

왼쪽 탐색 메뉴에서 콘텐츠를 선택하고 페이지 헤더의 선택 목록에서 저장소를 선택합니다.
![이 이미지는 [콘텐츠] 페이지 헤더의 드롭다운 메뉴에서 선택된 [저장소] 옵션을 보여줍니다. 이 이미지는 [콘텐츠] 페이지 헤더의 드롭다운 메뉴에서 선택된 [저장소] 옵션을 보여줍니다.](./images/repositories.png)
오른쪽 상단 모서리에서 생성을 눌러 새 자산 저장소를 생성합니다. 이 자습서의 목적을 위해 자산 저장소 이름을 'OCEGettingStartedRepository'로 지정합니다.

채널 게시 필드에서 OCEGettingStartedRepository 저장소의 콘텐츠를 OCEGettingStartedChannel 채널에 게시할 수 있도록 Oracle Content Management에 표시할 OCEGettingStartedChannel 채널을 선택합니다. 완료되면 저장을 누릅니다.
![이 이미지는 [게시 채널] 필드에 'OCEGettingStartedChannel'이 있는 저장소 정의 패널을 보여줍니다. 이 이미지는 [게시 채널] 필드에 'OCEGettingStartedChannel'이 있는 저장소 정의 패널을 보여줍니다.](./images/create-repository-2.png)
컨텐트 모델 생성
다음 작업은 컨텐트 모델을 생성하는 것입니다. 다음 두 가지 방법 중 하나를 사용할 수 있습니다.
- 방법 1: Oracle Content Management 샘플 자산 팩 임포트
- 방법 2: 고유한 콘텐츠 모델 생성
Oracle Content Management 샘플 자산 팩 임포트
이 자습서에 필요한 모든 콘텐츠 유형 및 자산이 포함된 미리 구성된 Oracle Content Management 샘플 자산 팩을 다운로드할 수 있습니다. 원하는 경우 샘플 자산 팩을 다운로드하지 않고 고유 콘텐츠 모델을 생성할 수도 있습니다.
Oracle Content Management 샘플 자산 팩에서 이 자습서에서 사용 중인 콘텐츠의 복사본을 업로드할 수 있습니다. 이렇게 하면 콘텐츠 유형을 실험하고 콘텐츠를 수정할 수 있습니다. Oracle Content Management 샘플 자산 팩을 임포트하려면 자산 팩 아카이브 OCESamplesAssetPack.zip를 다운로드하여 선택한 디렉토리로 추출할 수 있습니다.
Oracle Content Management 다운로드 페이지에서 Oracle Content Management 샘플 자산 팩(OCESamplesAssetPack.zip)을 다운로드합니다. 다운로드한 zip 파일을 컴퓨터의 위치에 추출합니다. 압축을 푼 후 이 위치에 OCEGettingStarted_data.zip이라는 파일이 포함됩니다.
Oracle Content Management 웹 인터페이스에 관리자로 로그인합니다.
왼쪽 탐색 메뉴에서 콘텐츠를 선택하고 페이지 헤더의 선택 목록에서 저장소를 선택합니다. 이제 OCEGettingStartedRepository을 선택하고 위쪽 작업 표시줄에서 콘텐츠 임포트 단추를 누릅니다.
![이 이미지는 OCEGettingStartedRepository 항목이 선택된 [저장소] 페이지를 보여줍니다. 이 이미지는 OCEGettingStartedRepository 항목이 선택된 [저장소] 페이지를 보여줍니다.](./images/import-content-1.png)
로컬 컴퓨터에서 문서 폴더로 OCEGettingStarted_data.zip을 업로드합니다.

업로드되면 OCEGettingStarted_data.zip을 선택하고 확인을 눌러 콘텐츠를 자산 저장소로 임포트합니다.
![이 이미지는 [확인] 단추가 사용으로 설정된 상태에서 선택한 OCEGettingStarted_data.zip 파일을 보여줍니다. 이 이미지는 [확인] 단추가 사용으로 설정된 상태에서 선택한 OCEGettingStarted_data.zip 파일을 보여줍니다.](./images/import-content-3.png)
콘텐츠를 성공적으로 임포트한 후 자산 페이지로 이동하여 OCEGettingStartedRepository 저장소를 엽니다. 이제 모든 관련 이미지와 콘텐츠 항목이 자산 저장소에 추가되었음을 알 수 있습니다.

왼쪽 상단의 모두 선택, 게시를 차례로 눌러 임포트한 모든 자산을 이전에 생성한 게시 채널 OCEGettingStartedChannel에 추가합니다.

게시하기 전에 모든 자산을 검증해야 합니다. 먼저 OCEGettingStartedChannel을 선택한 채널로 추가하고 검증 단추를 누릅니다.
![이 이미지는 [검증 결과] 페이지를 보여줍니다. [채널] 필드에 OCEGettingStartedChannel 채널이 추가되고 검증할 모든 자산이 있고 [검증] 단추가 사용으로 설정되어 있습니다. 이 이미지는 [검증 결과] 페이지를 보여줍니다. [채널] 필드에 OCEGettingStartedChannel 채널이 추가되고 검증할 모든 자산이 있고 [검증] 단추가 사용으로 설정되어 있습니다.](./images/validate-assets-1.png)
자산이 검증되면 오른쪽 맨 위에 있는 게시 단추를 눌러 선택한 채널에 모든 자산을 게시할 수 있습니다.
![이 이미지는 [검증 결과] 페이지를 보여줍니다. [채널] 필드에 OCEGettingStartedChannel 채널이 추가되고 모든 자산이 검증되고 [게시] 단추가 사용으로 설정됩니다. 이 이미지는 [검증 결과] 페이지를 보여줍니다. [채널] 필드에 OCEGettingStartedChannel 채널이 추가되고 모든 자산이 검증되고 [게시] 단추가 사용으로 설정됩니다.](./images/validate-assets-2.png)
모든 자산이 게시된 자산 페이지에서 확인할 수 있습니다. 자산 이름 위의 아이콘으로 알 수 있습니다.
![이 이미지는 모든 자산이 포함된 [자산] 페이지를 보여줍니다. 이 이미지는 모든 자산이 포함된 [자산] 페이지를 보여줍니다.](./images/assets-page-with-published-assets.png)
Oracle Content Management 샘플 자산 팩을 가져온 후 Next.js에서 블로그 구축을 시작할 수 있습니다.
고유의 콘텐츠 모델 생성
Oracle Content Management 샘플 자산 팩 임포트 대신 고유한 콘텐츠 모델을 생성할 수도 있습니다.
이 자습서에서는 'OCEGettingStartedHomePage'이라는 콘텐츠 유형을 사용하여 블로그의 홈 페이지를 작성합니다. 이 홈 페이지는 브랜딩(회사 이름 및 로고), 링크에 대한 일부 URL 및 페이지에 포함되어야 하는 블로그 항목 목록으로 구성됩니다.

콘텐츠 모델에 대한 콘텐츠 유형을 생성하려면 다음을 수행합니다.
- Oracle Content Management 웹 인터페이스에 관리자로 로그인합니다.
- 왼쪽 탐색 메뉴에서 콘텐츠를 선택하고 페이지 헤더의 선택 목록에서 자산 유형을 선택합니다.
- 오른쪽 상단에서 생성을 누릅니다.
- 디지털 자산 유형이 아닌 콘텐츠 유형을 생성하도록 선택합니다. 필요한 모든 콘텐츠 유형에 대해 이 작업을 반복합니다.
![이 이미지는 Oracle Content Management 웹 인터페이스의 [자산 유형 생성] 대화상자를 보여줍니다. 이 이미지는 Oracle Content Management 웹 인터페이스의 [자산 유형 생성] 대화상자를 보여줍니다.](./images/create-content-type.png)
각각 고유한 필드 집합을 포함하는 네 가지 콘텐츠 유형을 생성합니다.
- OCEGettingStartedHomePage
- OCEGettingStartedTopic
- OCEGettingStartedAuthor
- OCEGettingStartedArticle
첫번째 콘텐츠 유형 OCEGettingStartedHomePage에는 다음 필드가 있어야 합니다.
| 표시 이름 | 필드 유형 | 필요 | 시스템 이름 |
|---|---|---|---|
| 회사 이름 | 단일 값 텍스트 필드 | X | company_name |
| 회사 로고 | 단일 값 텍스트 필드 | X | company_logo |
| 항목 | 다중 값 참조 필드 | X | 주제 |
| 연락처 URL | 단일 값 텍스트 필드 | X | contact_url |
| URL 정보 | 단일 값 텍스트 필드 | X | about_url |
OCEGettingStartedHomePage 콘텐츠 유형 정의는 다음과 같아야 합니다.

두번째 콘텐츠 유형 OCEGettingStartedTopic에는 다음 필드가 있어야 합니다.
| 표시 이름 | 필드 유형 | 필요 | 시스템 이름 |
|---|---|---|---|
| 작은 그림 | 단일 값 이미지 필드 | X | 작은 그림 |
OCEGettingStartedTopic 콘텐츠 유형은 다음과 같아야 합니다.

세번째 콘텐츠 유형 OCEGettingStartedAuthor에는 다음 필드가 있어야 합니다.
| 표시 이름 | 필드 유형 | 필요 | 시스템 이름 |
|---|---|---|---|
| 아바타 | 단일 값 이미지 필드 | X | 아바타 |
OCEGettingStartedAuthor 콘텐츠 유형은 다음과 같아야 합니다.

네번째 및 최종 콘텐츠 유형 OCEGettingStartedArticle에는 다음 필드가 있어야 합니다.
| 표시 이름 | 필드 유형 | 필요 | 시스템 이름 |
|---|---|---|---|
| 게시 일자 | 단일 값 날짜 필드 | X | published_name |
| 작성자 | 단일 값 참조 필드 | X | 작성자 |
| 이미지 | 단일 값 이미지 필드 | X | 이미지 |
| 이미지 캡션 | 단일 값 텍스트 필드 | X | image_caption |
| 기사 콘텐츠 | 단일 값 대형 텍스트 필드 | X | article_content |
| 주제 | 단일 값 참조 필드 | X | 항목 |
OCEGettingStartedArticle 콘텐츠 유형은 다음과 같아야 합니다.
![이 이미지는 콘텐츠 유형 'OCEGettingStartedArticlePage'에 대한 정의를 보여줍니다. 여기에는 [게시된 날짜], [작성자], [이미지], [이미지 캡션], [문서 콘텐츠] 및 [항목] 데이터 필드가 포함됩니다. 이 이미지는 콘텐츠 유형 'OCEGettingStartedArticlePage'에 대한 정의를 보여줍니다. 여기에는 [게시된 날짜], [작성자], [이미지], [이미지 캡션], [문서 콘텐츠] 및 [항목] 데이터 필드가 포함됩니다.](./images/content-type-4.png)
콘텐츠 유형을 생성한 후에는 해당 콘텐츠 유형을 이전에 생성한 저장소(OCEGettingStartedRepository)에 추가할 수 있습니다.
- Oracle Content Management 웹 인터페이스에 관리자로 로그인합니다.
- OCEGettingStartedRepository으로 이동합니다.
- 저장소를 편집하고 자산 유형에서 새로 생성된 네 가지 콘텐츠 유형을 모두 지정합니다. Save 버튼을 눌러 변경사항을 저장합니다.
![이 이미지는 Oracle Content Management의 [저장소 편집] 페이지에 OCEGettingStartedRepository 저장소와 연관된 4개의 새로 생성된 콘텐츠 유형을 보여 줍니다. 이 이미지는 Oracle Content Management의 [저장소 편집] 페이지에 OCEGettingStartedRepository 저장소와 연관된 4개의 새로 생성된 콘텐츠 유형을 보여 줍니다.](./images/repository-with-asset-types.png)
저장소에 콘텐츠 유형을 추가한 후 자산 페이지에서 OCEGettingStartedRepository 저장소를 열고 모든 콘텐츠 유형에 대한 콘텐츠 항목 생성을 시작할 수 있습니다.
![이 이미지는 Oracle Content Management 웹 인터페이스의 [자산] 페이지에 있는 콘텐츠 항목을 보여 줍니다. 모음, 채널, 언어, 유형, 콘텐츠 항목 선택 및 상태에 대한 왼쪽에 옵션이 있습니다. 이 이미지는 Oracle Content Management 웹 인터페이스의 [자산] 페이지에 있는 콘텐츠 항목을 보여 줍니다. 모음, 채널, 언어, 유형, 콘텐츠 항목 선택 및 상태에 대한 왼쪽에 옵션이 있습니다.](./images/assets-create-content-items.png)
작업 2: Next.js로 블로그 구축
서버측 렌더링된 Next.js 애플리케이션에서 Oracle Content Management 콘텐츠를 소비하기 위해 GitHub에서 오픈 소스 저장소로 제공되는 Next.js 블로그 샘플을 사용할 수 있습니다.
주: Next.js 샘플은 선택 사항이므로 이 자습서에서 사용하여 빠르게 시작할 수 있습니다. 고유의 Next.js 애플리케이션을 구축할 수도 있습니다.
Next.js에서 블로그를 구축하려면 다음과 같이 하십시오.
샘플 저장소 복제 및 설치 종속성
Next.js 블로그 샘플은 GitHub에서 오픈 소스 저장소로 제공됩니다.
먼저 GitHub의 샘플을 로컬 컴퓨터로 복제하고 디렉토리를 저장소 루트로 변경해야 합니다.
git clone https://github.com/oracle/oce-nextjs-blog-sample.git
cd oce-nextjs-blog-sample
이제 코드베이스가 있으므로 응용 프로그램에 대한 종속성을 다운로드해야 합니다. 루트 디렉토리에서 다음 명령을 실행합니다.
npm install
Next.js 애플리케이션 구성
이 Next.js 블로그 샘플에서는 Oracle Content Management Content SDK(및 기타 모든 요청)가 올바른 채널 토큰을 사용하여 올바른 인스턴스 URL 및 API 버전을 대상으로 지정할 수 있도록 몇 가지 정보를 구성해야 합니다. 이러한 값은 스크립트/server-config-utils.js에서 새 전달 클라이언트를 인스턴스화하는 데 사용됩니다.
이 응용 프로그램은 Next.js에서 읽고 process.env를 사용하여 응용 프로그램 내의 코드에 사용 가능한 .env.local 파일을 사용합니다.
텍스트 편집기에서 .env.local 파일을 엽니다. 다음 정보가 표시됩니다.
# The connection details for the Oracle Content Management server to be used for this application
SERVER_URL=https://samples.mycontentdemo.com
API_VERSION=v1.1
CHANNEL_TOKEN=47c9fb78774d4485bc7090bf7b955632
각 키-값 쌍을 변경하여 인스턴스 URL, 대상으로 지정할 API 버전 및 게시 채널과 연관된 채널 토큰을 반영합니다. 이 자습서의 채널은 OCEGettingStartedChannel입니다.
Oracle Content Management Content SDK 사용
Oracle Content Management는 애플리케이션에서 콘텐츠를 검색하고 사용하는 데 도움이 되는 SDK를 제공합니다. SDK는 NPM 모듈로 게시되며 프로젝트는 GitHub에 호스팅됩니다.
여기서 SDK에 대해 자세히 알아보십시오.
SDK가 package.json 파일에서 이 프로젝트의 런타임 종속성으로 등록되었습니다.
콘텐츠 SDK를 사용하여 콘텐츠 인출
이제 Content SDK를 활용하여 콘텐츠를 인출하여 Next.js 애플리케이션에서 렌더링할 수 있습니다.
스크립트 폴더에는 Content SDK를 사용하여 Oracle Content Management에서 데이터를 가져오는 코드가 포함되어 있습니다.
script/server-config-utils.js 파일은 Content SDK를 임포트한 다음 .env.local에 지정된 구성을 사용하여 전달 클라이언트를 생성합니다.
다음 명령은 SDK를 가져옵니다.
import { createDeliveryClient, createPreviewClient } from '@oracle/content-management-sdk';다음 명령은 전달 클라이언트를 생성합니다.
return createDeliveryClient(serverconfig);스크립트/services.js 파일에는 애플리케이션의 데이터를 가져오는 모든 코드가 포함되어 있습니다. 응용 프로그램의 각 페이지 구성 요소에는 해당 페이지의 모든 데이터를 가져오는 하나의 기본 함수가 있습니다.
이미지를 렌더링하기 위해 services.js는 자산의 변환에서 구성된 자산에 대한 소스 세트를 검색하는 도우미 메소드를 제공합니다.
function getSourceSet(asset) {
const urls = {};
urls.srcset = '';
urls.jpgSrcset = '';
if (asset.fields && asset.fields.renditions) {
asset.fields.renditions.forEach((rendition) => {
addRendition(urls, rendition, 'jpg');
addRendition(urls, rendition, 'webp');
});
}
// add the native rendition to the srcset as well
urls.srcset += `${asset.fields.native.links[0].href} ${asset.fields.metadata.width}w`;
urls.native = asset.fields.native.links[0].href;
urls.width = asset.fields.metadata.width;
urls.height = asset.fields.metadata.height;
return urls;
}홈 페이지 데이터
홈 페이지의 모든 데이터를 가져오려면 여러 개의 데이터 호출이 필요합니다.
- 먼저 .env.local에 지정된 채널에서 항목을 질의합니다.
- 각 항목 항목에 대해 세부 정보를 가져옵니다.
스크립트/services.js를 열고 홈 페이지에 대한 모든 데이터를 가져오는 getTopicsListPageData() 함수를 찾습니다.
export function getTopicsListPageData() {
const client = getDeliveryClient();
return fetchHomePage(client)
.then((data) => (
getRenditionURLs(client, data.logoID)
.then((renditionUrls) => {
data.companyThumbnailRenditionUrls = renditionUrls;
return data;
})
));
}getTopicsListPageData() 함수에서 호출하는 fetchHomePage() 함수는 채널의 모든 항목을 가져옵니다. 로고 ID, 회사 이름, 정보 및 연락처 URL, 항목 목록을 가져옵니다.
function fetchHomePage(client) {
return client.queryItems({
q: '(type eq "OCEGettingStartedHomePage" AND name eq "HomePage")',
}).then((data) => {
const logoID = data.items[0].fields.company_logo.id;
const title = data.items[0].fields.company_name;
const aboutUrl = data.items[0].fields.about_url;
const contactUrl = data.items[0].fields.contact_url;
const { topics } = data.items[0].fields;
const promises = [];
topics.forEach((origTopic) => {
// add a promise to the total list of promises to get the full topic details
promises.push(
fetchTopic(client, origTopic.id)
.then((topic) => topic),
);
});
// execute all the promises returning a single dimension array of all
// of the topics and the other home page data
return Promise.all(promises)
.then((allTopics) => (
{
logoID,
companyTitle: title,
aboutUrl,
contactUrl,
topics: flattenArray(allTopics),
}
)).catch((error) => logError('Fetching topics failed', error));
}).catch((error) => logError('Fetching home page data failed', error));
}그런 다음 각 항목 ID에 대해 fetchTopic() 함수를 호출하여 전체 항목 세부 정보를 가져옵니다.
function fetchTopic(client, topicId) {
return client.getItem({
id: topicId,
expand: 'fields.thumbnail',
}).then((topic) => {
topic.renditionUrls = getSourceSet(topic.fields.thumbnail);
return topic;
}).catch((error) => logError('Fetching topic failed', error));
}getTopicsListPageData()도 getRenditionURLs()를 호출하여 렌더링할 이미지의 URL을 가져옵니다.
function getRenditionURLs(client, identifier) {
return client.getItem({
id: identifier,
expand: 'fields.renditions',
}).then((asset) => getSourceSet(asset))
.catch((error) => logError('Fetching Rendition URLs failed', error));
}항목 페이지 데이터
Next.js는 정적 사이트 생성을 사용하여 애플리케이션의 각 페이지를 사전 렌더링합니다. 각 항목 페이지의 경로는 항목 ID를 포함합니다. 스크립트/services.js를 열고 모든 항목 ID를 가져오는 데 사용되는 fetchTopicIds() 함수를 찾습니다.
export function fetchTopicIds() {
const client = getDeliveryClient();
return client.queryItems({
q: '(type eq "OCEGettingStartedHomePage" AND name eq "HomePage")',
}).then((data) => {
const { topics } = data.items[0].fields;
const topicIds = topics.map(
(topic) => topic.id,
);
return topicIds;
}).catch((error) => logError('Fetching topic ids failed', error));
}항목 페이지는 항목 ID를 받고 해당 데이터를 모두 가져오려면 여러 개의 데이터 호출이 필요합니다.
- 주제 이름 가져오기
- 지정된 토픽에 대한 모든 기사를 가져옵니다.
- 각 문서에 대해 해당 변환 URL을 가져옵니다.
항목 이름을 가져오는 데 사용되는 fetchTopicName(topicId) 함수를 찾습니다.
export function fetchTopicName(topicId) {
const client = getDeliveryClient();
return client.getItem({
id: topicId,
}).then((topic) => topic.name)
.catch((error) => logError('Fetcvhing topic name failed', error));
}항목 페이지에 대한 문서 데이터를 가져오는 fetchTopicArticles(topicId) 함수를 찾습니다.
export function fetchTopicArticles(topicId) {
const client = getDeliveryClient();
return client.queryItems({
q: `(type eq "OCEGettingStartedArticle" AND fields.topic eq "${topicId}")`,
orderBy: 'fields.published_date:desc',
}).then((data) => {
const promises = [];
const articles = data.items;
articles.forEach((article) => {
// add a promise to the total list of promises to get the article url
promises.push(
getRenditionURLs(client, article.fields.image.id)
.then((renditionUrls) => {
article.renditionUrls = renditionUrls;
// Note: the spread operator is used here so that we return a top level
// object, rather than a value which contains the object
// i.e we return
// {
// field1: 'value', field2 : "value", etc
// },
// rather than
// {
// name: {
// field1: 'value', field2 : "value", etc
// }
// }
return {
...article,
};
}),
);
});
// execute all the promises and return all the data
return Promise.all(promises)
.then((allArticles) => ({
topicId,
articles: flattenArray(allArticles),
}));
}).catch((error) => logError('Fetching topic articles failed', error));
}또한 fetchTopicArticles() 메소드는 앞에서 살펴본 것처럼 getRenditionURLs()를 사용하여 문서의 이미지를 가져옵니다.
문서 페이지 데이터
각 문서 페이지의 경로는 문서 ID를 포함합니다. 스크립트/services.js를 열고 각 문서 페이지를 사전 렌더링할 때 사용되는 모든 문서 ID를 가져오는 데 사용되는 fetchAllArticlesSimple() 함수를 찾습니다.
export function fetchAllArticlesSimple() {
const client = getDeliveryClient();
return fetchTopicIds()
.then((topicIds) => {
const promises = [];
topicIds.forEach((topicId) => {
// add a promise to the total list of promises to get the article url
promises.push(
fetchTopicArticlesSimple(client, topicId)
.then((data) => {
const { items } = data;
const articles = items.map((item) => (
{
id: item.id,
name: item.name,
}
));
return articles;
}),
);
});
// execute all the promises and return all the data
return Promise.all(promises)
.then((allArticles) => flattenArray(allArticles));
}).catch((error) => logError('Fetching basic information for all articles failed', error));
}fetchAllArticlesSimple()는 fetchTopicArticlesSimple()을 호출하여 단순화된 문서 목록을 가져옵니다.
function fetchTopicArticlesSimple(client, topicId) {
return client.queryItems({
q: `(type eq "OCEGettingStartedArticle" AND fields.topic eq "${topicId}")`,
orderBy: 'fields.published_date:desc',
}).then((data) => data)
.catch((error) => logError('Fetching basic information for topic articles failed', error));
}문서 페이지는 문서 ID를 수신하며 모든 데이터를 가져오기 위해 여러 데이터 호출이 필요합니다.
- 지정된 문서에 대한 문서 세부정보를 가져옵니다.
- 각 문서에 대해 해당 변환 URL을 가져옵니다.
문서 페이지에 대한 데이터를 가져오는 fetchArticleDetails(articleId) 함수를 찾습니다. 이 메소드는 문서에 대한 이미지를 가져오고 getMediumRenditionURL() 함수를 사용하여 작성자의 이미지를 가져오는 getRenditionURL() 함수를 사용합니다.
export function fetchArticleDetails(articleId) {
const client = getDeliveryClient();
return client.getItem({
id: articleId,
expand: 'fields.author,fields.image',
}).then((article) => {
const { fields } = article;
const title = fields.author.name;
const date = fields.published_date;
const content = fields.article_content;
const imageCaption = fields.image_caption;
const { topic } = fields;
const { name } = article;
const renditionUrls = getSourceSet(article.fields.image);
const avatarID = article.fields.author.fields.avatar.id;
// Get the author's avatar image
return getRenditionURLs(client, avatarID)
.then((authorRenditionUrls) => (
// return an object with just the data needed
{
id: articleId,
name,
title,
date,
content,
imageCaption,
renditionUrls,
authorRenditionUrls,
topicId: topic.id,
topicName: topic.name,
}
));
}).catch((error) => logError('Fetching article details failed', error));
}또한 fetchArticleDetails() 메소드는 앞에서 살펴본 것처럼 getRenditionURLs()를 사용하여 아바타 이미지를 가져옵니다.
이제 데이터 쿼리를 실행했으므로 Next.js 구성 요소에서 응답을 렌더링할 수 있습니다.
Next.js 구성 요소
Next.js는 React를 기반으로 하며 React는 JavaScript에 대한 HTML과 같은 구문 확장인 JSX라는 기술을 사용하여 컨텐츠를 렌더링합니다. 순수한 JavaScript를 작성하여 Oracle Content Management에서 데이터를 렌더링할 수 있지만 JSX를 사용하는 것이 좋습니다.
블로그 응용 프로그램은 각 페이지를 여러 작은 구성 요소로 나눕니다.
다음 몇 섹션에서는 Next.js가 각 구성 요소에서 응용 프로그램을 렌더링하는 방법에 대한 개요를 제공합니다.
- 페이지 폴더
- 인덱스 구성요소
- 머리글 구성요소
- TopicsListItem 구성요소
- ArticleListPage 구성요소
- ArticesListItem 구성요소
- ArticleDetailsPage 구성요소
- 이동 경로 및 이동 경로 구성 요소
페이지 폴더
이 사이트에서는 다음 세 가지 경로를 제공하고자 합니다.
- 주제 목록으로 구성된 홈 페이지
- 선택한 항목에 대한 모든 문서를 표시하는 항목 페이지
- 선택된 문서를 표시하는 개별 문서 페이지
다음.js 페이지의 모든 페이지는 애플리케이션의 경로로 처리됩니다.
인덱스 구성요소
홈 페이지는 개별 항목으로 구성된 목록으로 구성됩니다. page/index.jsx에 있는 Index 구성 요소에 의해 렌더링됩니다.
구성요소는 API를 임포트하여 services.js 파일에서 데이터를 가져옵니다.
import { getTopicsListPageData } from '../scripts/services';getStaticProps()에서 구성 요소는 홈 페이지를 렌더링하는 데 필요한 모든 데이터를 가져옵니다.
export async function getStaticProps() {
const data = await getTopicsListPageData();
return { props: { data } };
}머리글 구성요소
인덱스 구성 요소는 머리글 구성 요소를 사용하여 회사 제목, 회사 로고 및 연락처/연락처 링크를 표시합니다.
src/구성 요소/Header.jsx에 있으며 모든 데이터를 속성으로 수신합니다. 서버에서 추가 데이터를 가져오지 않습니다.
TopicsListItem 구성요소
인덱스 구성 요소는 TopicsListItem 구성 요소를 사용하여 목록에 개별 항목을 표시합니다.
src/구성 요소/TopicsListItem.jsx에 있는 TopicsListItem 구성 요소는 모든 데이터를 속성으로 수신합니다. 서버에서 추가 데이터를 가져오지 않습니다.
ArticleListPage 구성요소
[항목] 페이지에는 URL의 구성요소에 ID가 전달되는 항목의 문서가 표시됩니다. page/articles/[id].jsx에 있는 ArticleListPage 구성 요소에 의해 렌더링됩니다.
구성요소는 API를 임포트하여 services.js 파일에서 데이터를 가져옵니다.
import { fetchTopicIds, fetchTopicName, fetchTopicArticles } from '../../scripts/services';주제 페이지의 URL은 토픽 ID를 경로로 포함하는 동적 URL입니다. URL 경로는 다음과 같습니다.
- /articles/topicId1
- /articles/topicId2
- /articles/topicId3
Next.js가 동적 URL이 있는 페이지에 대해 정적 사이트 생성을 사용하는 경우 getStaticPaths()을 호출하여 해당 페이지의 모든 경로를 가져옵니다.
export async function getStaticPaths() {
const topicIds = await fetchTopicIds();
// Generate the paths we want to pre-render based on posts
const paths = topicIds.map((topicId) => ({
params: { id: topicId },
}));
return {
paths,
fallback: false,
};
}getStaticProps() 함수는 [주제] 페이지의 단일 인스턴스에 대한 데이터를 가져오는 데 사용됩니다. 항목 ID는 메소드에 전달된 매개변수에서 가져옵니다. 그런 다음 이 페이지에 필요한 모든 데이터를 가져오는 데 항목 ID가 사용됩니다.
export async function getStaticProps(context) {
const { params } = context;
const { id } = params;
const [data, topicName] = await Promise.all([fetchTopicArticles(id), fetchTopicName(id)]);
return {
props: {
topicId: id,
topicName,
data,
},
};
}ArticesListItem 구성요소
ArticleListPage 구성 요소는 ArticlesListItem 구성 요소를 사용하여 목록에 개별 문서를 표시합니다.
ArticlesListItem 구성 요소는 src/구성 요소/ArticlesListItem.jsx에 있으며 모든 데이터를 속성으로 수신합니다. 서버에서 추가 데이터를 가져오지 않습니다.
ArticleDetailsPage 구성요소
[문서] 페이지에는 ID가 URL에 전달된 문서의 세부 정보가 표시됩니다. page/article/[id].jsx에 있는 ArticleDetailsPage 구성 요소에 의해 렌더링됩니다.
구성요소는 API를 임포트하여 services.js 파일에서 데이터를 가져옵니다.
import { fetchAllArticlesSimple, fetchArticleDetails } from '../../scripts/services';기사 페이지의 URL은 문서 ID를 경로로 포함하는 동적 URL입니다. 예: URL 경로는 다음과 같습니다.
- /article/articleId1
- /article/articleId2
- /article/articleId3
Next.js가 동적 URL이 있는 페이지에 대해 정적 사이트 생성을 사용하는 경우 getStaticPaths()을 호출하여 해당 페이지의 모든 경로를 가져옵니다.
export async function getStaticPaths() {
const articles = await fetchAllArticlesSimple();
// Generate the paths we want to pre-render based on posts
return {
paths: articles.map((article) => ({
params: { id: article.id },
})),
fallback: true,
};
}getStaticProps() 함수는 [문서] 페이지의 단일 인스턴스에 대한 데이터를 가져오는 데 사용됩니다. 메소드로 전달된 파라미터에서 문서 ID를 가져옵니다. 그런 다음 이 페이지에 필요한 모든 데이터를 가져오는 데 문서 ID가 사용됩니다.
export async function getStaticProps(context) {
const { params } = context;
const { id } = params;
const data = await fetchArticleDetails(id);
return {
props: {
data,
},
};
}이동 경로 및 이동 경로 구성 요소
인덱스 및 ArticleDetailsPage 구성 요소는 모두 이동 경로 및 이동 경로 구성 요소를 사용하여 페이지 상단에 이동 경로를 표시하므로 사용자가 [항목] 페이지 또는 [홈] 페이지로 돌아갈 수 있습니다. 두 구성 요소는 모든 데이터를 속성으로 수신하므로 서버에서 추가 데이터를 가져오지 않습니다.
작업 3: 배치를 위한 응용 프로그램 준비
이제 Next.js 블로그 사이트를 구축했으므로 이제 로컬 개발 서버에서 이 사이트를 확인해야만 문제를 디버그하고 애플리케이션을 미리 볼 수 있습니다.
다음 두 단계로 응용 프로그램을 배치하도록 준비합니다.
로컬 개발 서버 가동
다음 명령을 실행하여 개발 서버를 로컬로 시작할 수 있습니다.
npm run dev
그런 다음 http://localhost:3000에 브라우저를 열어 사용 중인 사이트를 확인합니다.
주: 페이지를 미리 렌더링하지 않습니다. 페이지를 미리 렌더링하려면 다음 섹션을 참조하십시오.
스크립트를 사용하여 개발 및 프로덕션에서 응용 프로그램 작성 및 실행
운용의 경우 빌드 스크립트를 사용하여 사이트를 정적으로 생성합니다.
npm run build
시작 스크립트는 정적으로 생성된 페이지를 제공하는 Node.js 서버를 시작하는 데 사용됩니다.
npm run start
헤드리스 Oracle Content Management로 다음.js에 블로그 구축
F49316-01
2021년 10월
Copyright © 2021, Oracle and/or its affiliates.
주 저자: Oracle Corporation