Skip to main content

Server Side Rendering

warning

이 기능은 현재 사전 협의된 매체에만 제공됩니다.

지속적으로 개발되고 있는 기능으로, API가 예고 없이 변경될 수 있습니다.

info

Server Side Rendering은 Native Advanced 광고 형식에 대해서만 지원됩니다. 그 이외의 광고 형식은 광고 요청에 대한 Preloading은 지원되지만, 광고 마크업이 서버의 렌더 결과물에 포함되지 않으며, Client Side에서만 렌더링이 진행됩니다.

Initial Setup

GFP Web SDK를 로드하고, GladSdkProvider 컴포넌트로 React SDK를 사용할 준비를 합니다.

React SDK Initial Setup 가이드를 참고하세요.

Preloading Ad in Server

Preload Client를 생성하고, 매체마다 부여된 Service Code와 클라이언트의 IP 주소를 설정합니다. 그 후, preloadClient.preloadAd 메소드를 호출하여 광고를 Preload합니다.

info

Service Code와 Client Address는 필수로 설정되어야 합니다. 자세한 내용은 WIKI 문서를 참고하세요.

pages/sample.tsx
import {
AdHydrationBoundary,
} from '@gfpsdk/display-sdk-react';
import {
dehydrate,
PreloadClient,
} from '@gfpsdk/display-sdk-react/server';

const adRequestOptions = {
adUnitId: 'ad-unit-id',
adSlotElementId: 'ad-slot-element-id',
};

export async function getServerSideProps(context) {
const preloadClient = new PreloadClient({
headers: context.req.headers,
serviceCode: SERVICE_CODE,
clientAddress: getClientAddress(),
});
await preloadClient.preloadAd(adRequestOptions);
return {
props: {
dehydratedAdState: dehydrate(preloadClient),
},
};
}

function Sample() {
// ...
}

export default function SampleRoute({ dehydratedAdState }) {
return (
<AdHydrationBoundary state={dehydratedAdState}>
<Sample />
</AdHydrationBoundary>
);
}

Custom Ad Server URL

Production 환경 외의 운영 환경으로 광고를 요청하려는 경우, preloadClient.setAdCallUrl 메소드를 호출하여 광고 서버의 URL을 변경할 수 있습니다. Service URL 목록은 WIKI 문서 에서 확인하실 수 있습니다.

const preloadClient = new PreloadClient({
headers: headers,
serviceCode: SERVICE_CODE,
clientAddress: getClientAddress(),
})
.setAdCallUrl('http://test-gfp.veta.naver.com');

Hydrating/Displaying preloaded Ad

Preload된 광고는 AdHydrationBoundary 컴포넌트를 통해 Hydration 됩니다. AdHydrationBoundary 내부에서 렌더링되는 광고들은 Preload된 광고를 별도 요청 없이 즉시 노출할 수 있습니다.

pages/sample.tsx
import {
AdHydrationBoundary,
} from '@gfpsdk/display-sdk-react';
import {
dehydrate,
PreloadClient,
} from '@gfpsdk/display-sdk-react/server';

const adRequestOptions = {
adUnitId: 'ad-unit-id',
adSlotElementId: 'ad-slot-element-id',
};

export async function getServerSideProps(context) {
const preloadClient = new PreloadClient({
headers: context.req.headers,
serviceCode: SERVICE_CODE,
clientAddress: getClientAddress(),
});
await preloadClient.preloadAd(adRequestOptions);
return {
props: {
dehydratedAdState: dehydrate(preloadClient),
},
};
}

function Sample() {
return <AdSlotElement adSlotOptions={adRequestOptions} />;
}

export default function SampleRoute({ dehydratedAdState }) {
return (
<AdHydrationBoundary state={dehydratedAdState}>
<Sample />
</AdHydrationBoundary>
);
}

Ad Deduplication (중복제어)

Deduplicating Preload Requests

여러 개의 광고 슬롯을 Preload할 때 중복제어를 적용하려는 경우 PreloadDeduplicationManager를 이용할 수 있습니다. PreloadDeduplicationManager 인스턴스를 초기화한 후, deduplicationManager.execute 메소드에 preload를 실행할 callback 함수를 전달합니다.

전달된 callback의 callstack 내부에서 실행되는 preload 요청은 모두 중복제어가 적용되어 로드됩니다.

전달된 callback은 즉시 동기적으로 실행되며, 전달된 callback이 Promise를 반환할 경우 deduplicationManager.execute는 반환된 Promise를 그대로 반환합니다.

pages/sample.tsx
import {
AdHydrationBoundary,
} from '@gfpsdk/display-sdk-react';
import {
dehydrate,
PreloadClient,
PreloadDeduplicationManager,
} from '@gfpsdk/display-sdk-react/server';

const adRequestOptions = {
adUnitId: 'ad-unit-id',
adSlotElementId: 'ad-slot-element-id',
};

const adRequestOptions2 = {
adUnitId: 'ad-unit-id-2',
adSlotElementId: 'ad-slot-element-id-2',
};

export async function getServerSideProps(context) {
const deduplicationManager = new PreloadDeduplicationManager();
const preloadClient = new PreloadClient({
headers: context.req.headers,
serviceCode: SERVICE_CODE,
clientAddress: getClientAddress(),
})

await deduplicationManager.execute(async () => {
await preloadClient.preloadAd(adRequestOptions);
await preloadClient.preloadAd(adRequestOptions2);
});

return {
props: {
dehydratedAdState: dehydrate(preloadClient),
},
};
}

function Sample() {
return (
<>
<AdSlotElement adSlotOptions={adRequestOptions} />
<AdSlotElement adSlotOptions={adRequestOptions2} />
</>
);
}

export default function SampleRoute({ dehydratedAdState }) {
return (
<AdHydrationBoundary state={dehydratedAdState}>
<Sample />
</AdHydrationBoundary>
);
}

Deduplicating Preloaded Request and Client Side Requests

Server에서 Preload하려는 AdSlot과 Client에서 별도로 요청하려는 AdSlot 대해 서로 다른 광고를 표시하기 위해 중복제어를 적용하려는 경우, 동일한 AdDeduplicationBoundary 내부에 렌더링하거나 AdSlotElement의 props에 동일한 dedupReqId를 전달하면 됩니다.

pages/sample.tsx
import {
AdDeduplicationBoundary,
AdHydrationBoundary,
} from '@gfpsdk/display-sdk-react';
import {
dehydrate,
PreloadClient,
} from '@gfpsdk/display-sdk-react/server';

const adRequestOptions = {
adUnitId: 'ad-unit-id',
adSlotElementId: 'ad-slot-element-id',
};

const clientLoadedadRequestOptions = {
adUnitId: 'client-loaded-ad-unit-id',
adSlotElementId: 'client-loaded-ad-slot-element-id',
};

export async function getServerSideProps(context) {
const preloadClient = new PreloadClient({
headers: context.req.headers,
serviceCode: SERVICE_CODE,
clientAddress: getClientAddress(),
});
await preloadClient.preloadAd(adRequestOptions);
return {
props: {
dehydratedAdState: dehydrate(preloadClient),
},
};
}

const dedupReqId = 'sample-dedup-id';

function Sample() {
return (
<AdDeduplicationBoundary>
<AdSlotElement adSlotOptions={adRequestOptions} />
<AdSlotElement adSlotOptions={clientLoadedadRequestOptions} />
</AdDeduplicationBoundary>
);
// or
return (
<>
<AdSlotElement adSlotOptions={adRequestOptions} dedupReqId={dedupReqId} />
<AdSlotElement adSlotOptions={clientLoadedadRequestOptions} dedupReqId={dedupReqId} />
</>
);
}

export default function SampleRoute({ dehydratedAdState }) {
return (
<AdHydrationBoundary state={dehydratedAdState}>
<Sample />
</AdHydrationBoundary>
);
}

Streaming with Suspense(Advanced)

Remix(React Router), Next.js App Router, React Server Component 등 일부 환경에서는 non-critical data에 대한 Streaming을 통해 UI Blocking을 최소화할 수 있는 방식을 제공합니다.

GladSdk의 Preload 광고에 대해서도 Streaming 방식을 적용할 수 있습니다. 이 방식을 적용하면 광고의 Preload가 완료되지 않아도 페이지 응답을 render할 수 있으며, Preload가 진행 중인 경우에는 Suspense를 이용해 광고에 대한 fallback 컴포넌트를 render하고, Preload 응답이 준비되면 광고를 표시하도록 할 수 있습니다.

app/routes/sample.tsx
import {
AdHydrationBoundary,
} from '@gfpsdk/display-sdk-react';
import {
dehydrate,
PreloadClient,
} from '@gfpsdk/display-sdk-react/server';
import { useLoaderData } from "react-router";

const adRequestOptions = {
adUnitId: 'ad-unit-id',
adSlotElementId: 'ad-slot-element-id',
};

export async function loader({ request }) {
const preloadClient = new PreloadClient({
headers: request.headers,
serviceCode: SERVICE_CODE,
clientAddress: getClientAddress(),
});
// Do not await for Promise returned by preloadClient.preloadAd
preloadClient.preloadAd(adRequestOptions);
return {
dehydratedAdState: dehydrate(preloadClient),
};
}

function Sample() {
return (
// Wrap Ad Component with Suspense
<Suspense fallback={'Loading Ad...'}>
<NativeAd.Root adSlotOptions={adRequestOptions}>
{/* ... */}
</NativeAd.Root>
</Suspense>
);
}

export default function SampleRoute() {
const { dehydratedAdState } = useLoaderData<typeof loader>();
return (
<AdHydrationBoundary state={dehydratedAdState}>
<Sample />
</AdHydrationBoundary>
);
}