日本語版
最新ニュース
企業

headless oでコンテンツを公開した後、next.jsでページを再検証する

ヘッドレスのCMS実装はますます人気が高まっています。このアプローチでは、CMSとフロントエンドアプリケーションが分離されており、異なるテクノロジースタックを使用できます。ただし、そのようなWebサイトを構築するときは、CMSとフロントエンドの間のシームレスな接続を確保して、スムーズな編集体験を維持することが不可欠です。 ヘッドレスCMSにヘッドアプリケーションを実装する最も人気のあるフレームワークの1つは、次の.JSです。これは、クライアントまたはサーバーサイドレンダリング、静的サイトの生成、およびインクリメンタルな静的再生のさまざまなレンダリング手法を提供します。もっと情報が必要な場合は、ここですべてをカバーするわけではありません この記事。このブログでは、CMSを扱う際に大多数のケースのために行く方法です。 ISRは、新しいコンテンツが公開されるたびにフロントエンドアプリケーション全体を再構築する必要なく、静的サイト生成からのHTMLファイルへのプレレンダリングコンテンツの能力と、単一ページの再生の柔軟性を組み合わせます。 next.jsにアプリを実装する方法は2つあります。 ページルーター そして新しい アプリルーター、両方で、ISRは次のAPIのいくつかの違いと同様に機能します。ベース実装コンテンツでは、たとえば60秒ごとに、特定の期間にキャッシュが無効になります。 CMSエディターにとって、このアプローチは迷惑な原因である可能性があります。この問題に対処するために、オンデマンドの再検証を実装して、コンテンツがOptMizely CMSで公開されるたびに実行できます。 next.jsの再検証はキャッシュを無効にすることに留意してください。実際の再生は、Pageに初めてアクセスしたときに発生することに留意してください。 まず、コンテンツ公開イベントを実装する必要があります。 Optimizely PAAS CMSの場合、イベントに接続する次のコードを使用できます。コンテンツが変更されたページを見つけて、次のように呼び出します。JSAPIがセキュリティシークレットを渡し、ページを変更しました。 [InitializableModule] [ModuleDependency(typeof(EPiServer.Web.InitializationModule))] public class EventsInitialization : IInitializableModule { private IContentEvents _contentEvents; private IContentRepository _contentRepository; private IContentLoader _contentLoader; private ISiteDefinitionResolver _sideDefinitionResolver; private IConfiguration _configuration;…

1743054555
2025-03-25 10:24:00

ヘッドレスのCMS実装はますます人気が高まっています。このアプローチでは、CMSとフロントエンドアプリケーションが分離されており、異なるテクノロジースタックを使用できます。ただし、そのようなWebサイトを構築するときは、CMSとフロントエンドの間のシームレスな接続を確保して、スムーズな編集体験を維持することが不可欠です。

ヘッドレスCMSにヘッドアプリケーションを実装する最も人気のあるフレームワークの1つは、次の.JSです。これは、クライアントまたはサーバーサイドレンダリング、静的サイトの生成、およびインクリメンタルな静的再生のさまざまなレンダリング手法を提供します。もっと情報が必要な場合は、ここですべてをカバーするわけではありません この記事。このブログでは、CMSを扱う際に大多数のケースのために行く方法です。 ISRは、新しいコンテンツが公開されるたびにフロントエンドアプリケーション全体を再構築する必要なく、静的サイト生成からのHTMLファイルへのプレレンダリングコンテンツの能力と、単一ページの再生の柔軟性を組み合わせます。

next.jsにアプリを実装する方法は2つあります。 ページルーター そして新しい アプリルーター、両方で、ISRは次のAPIのいくつかの違いと同様に機能します。ベース実装コンテンツでは、たとえば60秒ごとに、特定の期間にキャッシュが無効になります。 CMSエディターにとって、このアプローチは迷惑な原因である可能性があります。この問題に対処するために、オンデマンドの再検証を実装して、コンテンツがOptMizely CMSで公開されるたびに実行できます。 next.jsの再検証はキャッシュを無効にすることに留意してください。実際の再生は、Pageに初めてアクセスしたときに発生することに留意してください。

まず、コンテンツ公開イベントを実装する必要があります。 Optimizely PAAS CMSの場合、イベントに接続する次のコードを使用できます。コンテンツが変更されたページを見つけて、次のように呼び出します。JSAPIがセキュリティシークレットを渡し、ページを変更しました。



[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class EventsInitialization : IInitializableModule
{
    private IContentEvents _contentEvents;
    private IContentRepository _contentRepository;
    private IContentLoader _contentLoader;
    private ISiteDefinitionResolver _sideDefinitionResolver;
    private IConfiguration _configuration;
    private IHttpClientFactory _httpClientFactory;

    public void Initialize(InitializationEngine context)
    {
        _contentEvents ??= ServiceLocator.Current.GetInstance();
        _contentRepository ??= ServiceLocator.Current.GetInstance();
        _contentLoader ??= ServiceLocator.Current.GetInstance();
        _sideDefinitionResolver ??= ServiceLocator.Current.GetInstance();
        _configuration ??= ServiceLocator.Current.GetInstance();
        _httpClientFactory ??= ServiceLocator.Current.GetService();
        _contentEvents.PublishedContent += ContentEvents_PublishedContent;
    }

    public void Uninitialize(InitializationEngine context)
    {
        _contentEvents ??= ServiceLocator.Current.GetInstance();
        _contentEvents.PublishedContent -= ContentEvents_PublishedContent;
    }

    private void ContentEvents_PublishedContent(object sender, ContentEventArgs e)
    {
        if (sender == null || e == null) return;

        var pages = PagesToRevalidate(e.Content);
        foreach (var page in pages)
        {
            RevalidatePages(page);
        }
    }

    protected List PagesToRevalidate(IContent content)
    {
        // TODO this is simplified method to find pages referenced by the modified content. There may be more cases like deleting page, change page url and updating references, updating settings items, etc.
        if (content is BasePageData page)
        {
            return new List { page };
        }

        return GetRefPages(content);
    }

    protected List GetRefPages(IContent content)
    {
        var pages = new List();
        if (content is BaseBlockData)
        {
            var references = _contentRepository.GetReferencesToContent(content.ContentLink, true).ToList();
            foreach (var reference in references)
            {
                var refContent = _contentLoader.Get(reference.OwnerID);
                if (refContent != null && refContent is BasePageData pageRef)
                {
                    if (!pages.Any(p => p.ContentLink.ID == refContent.ContentLink.ID))
                    {
                        pages.Add(pageRef);
                    }
                }
                else if (refContent is BaseBlockData)
                {
                    var refPages = GetRefPages(refContent);
                    foreach (var page in refPages)
                    {
                        if (!pages.Any(p => p.ContentLink.ID == page.ContentLink.ID))
                        {
                            pages.Add(page);
                        }
                    }
                }
            }
        }
        return pages;
    }

    protected void RevalidatePages(BasePageData page)
    {
        var langUrls = new List();
        //TODO We take all languages, assuming pages have language fallback and changed content may be culture invariant. 
        foreach(var language in page.ExistingLanguages)
        {
            var url = UrlResolver.Current.GetUrl(page.ContentLink, language.Name);
            if (url != null)
            {
                langUrls.Add(url);
            }
        }

        var site = _sideDefinitionResolver.GetByContent(page.ContentLink, true);
        if (site == null || langUrls.Count == 0)
        {
            return;
        }

        var secretKey = _configuration["NextRevalidate:Secret"];
        var frontUrl = $"https://my-front-end-app.com/api/revalidate?secret={secretKey}";
        GetWebResponseAsync(frontUrl, langUrls);
    }

    protected async void GetWebResponseAsync(string apiUrl, List urls)
    {
        HttpClient httpClient = _httpClientFactory.CreateClient();
        HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, apiUrl);
        httpRequestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        httpRequestMessage.Content = new StringContent(JsonConvert.SerializeObject(urls), Encoding.UTF8, "application/json");

        using (var reader = new StreamReader(await (await httpClient.SendAsync(httpRequestMessage).ConfigureAwait(continueOnCapturedContext: false)).Content.ReadAsStreamAsync(), Encoding.UTF8))
        {
            var resultText = await reader.ReadToEndAsync();
            Log.Information("Revalidate API result:", resultText);
        }
    }
}


これで、next.jsアプリケーションに「Revalidate」APIルートを実装できます。この例では、APPルーターにAPI機能を調整し、使用するためにページルーターを使用しています revalidatePath('/path') の代わりに res.revalidate('/path') 実装は、クエリパラメーターから秘密(およびenv変数からの値と比較)とISRを再検証するパスを読み取ります。


import type { NextApiRequest, NextApiResponse } from 'next';
 
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse,
) { 
  try {
    if (req.query.secret !== process.env.NEXTAUTH_SECRET) {
        return res.status(401).json({ message: 'Invalid token' });
    }

    if (!req.body){
      return;
    }

    var results: string[] = await Promise.all(req.body.map(async (url: string): Promise => {
      await res.revalidate(url);
      return url;
    }));

    return res.json({ revalidated: results });
  } catch (err) {
    console.error(err);
    return res.status(500).send('Error revalidating');
  }
}

次のアプリケーションを実行します next build そして next start コマンドとCMSを起動し、いくつかのコンテンツを公開すると、ページを更新した直後に変更が表示される必要があります。

2025年3月25日

#headless #oでコンテンツを公開した後next.jsでページを再検証する

執筆者について: nipponese

Nipponese News編集部は、国内外のニュースを日本語で分かりやすくお届けします。