Habanero Bee에서 Google 스프레드시트를 사용하는 컨텐츠 관리 전략

며칠 전에 제가 직접 만든 하바나로베라는 오픈소스의 도구를 소개해 드렸습니다.
https://zenn.dev/shinshin86/articles/e199ce2a9baba6
이번 번에도 이 형식을 이어가고 싶은데 해반레로 베의 기술적인 부분에 대해 조금 써볼게요.

Google 스프레드시트를 이용한 컨텐츠 관리 전략


Habanero Bee는 링크된 사서함에 적힌 대로 웹 사이트의 기본 정보, 메타 정보, 컨텐츠 정보를 하나의 Google 스프레드시트 파일로 관리합니다.
이러한 점에 대해 웹 사이트 제작자는 하나의 파일만으로 모든 웹 사이트 정보를 관리하고 간단하게 관리할 수 있으며, 게다가 익숙한 Google 스프레드시트를 사용하면 새로운 지식을 배울 필요성을 잃게 된다. (예를 들어 학습 대시보드 사용 방법 등)
이상과 같은 이용자 측의 관리 원가 삭감은 말할 것도 없고 그 다음으로 실사자 측의 부담 삭감에도 큰 기여를 했다.
WordPress의 관리 화면을 상상해 보면 쉽게 연상될 수 있지만, 대시보드 설치는 로그인 관리와 권한 관리를 필두로 설치량과 주의력을 사용하는 곳도 많아 개인 개발 수준의 자원을 속도감 있게 설치하기 어렵다.
이번에는 콘텐츠 관리를 위한 도구로 Google 스프레드시트를 사용한 결과 권한 주위와 로그인 주위가 모두 Google 측에 떠밀려 그 구현을 모두 생략할 수 있습니다.

Google 스프레드시트 API화


다음은 실제 Google 스프레드시트에 작성된 웹 사이트 정보를 Habanero Bee에 전달하는 방법입니다.이 경우 API에서 Google 스프레드시트 활용을 간단히 결정합니다.
API를 실제로 수행하는 방법에 대한 요약은 다음 문서에 나와 있습니다.
Habanero Bee Google Apps Script | 웹 애플리케이션으로 게시 단계
위의 절차에 따라 Google 스프레드시트의 내용을 다음과 같은 API로 디자인할 수 있습니다.
이 링크를 방문하면 Habanero Bee의 에뮬레이션 웹 사이트에서 만든 컨텐츠 정보가 JSON으로 반환됩니다.
Habanero Bee Demo site data(Google Sheets API)
위의 API 는 다음 정보가 Google 스프레드시트에 기재되어 있습니다.
Habanero Bee Demo site 데이터(Google 스프레드시트)
다음 Google Apps Script는 이 기술을 API로 사용하기 위해 사용됩니다.
(현재 모든 코드를 표시합니다. 이 원본 코드는 창고habanero-bee-google-apps-script에서 관리합니다)
const getSheetData = sheetName => {
  const sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
  const rows = sheet.getDataRange().getValues();

  // Get keys(rows[0]) and Delete rows[0]
  const keys = rows.splice(0,1)[0];

  return rows.map((row) => {
    const obj = {};
    row.map((item, index) => {
      obj[String(keys[index])] = String(item);
    });
    return obj;
  });
}

const doGet = () => {
  const general = getSheetData('general')[0];
  const meta = getSheetData('meta')[0];
  const content = getSheetData('content');

  const data = { general, meta, content };

  return ContentService.createTextOutput(JSON.stringify(data))
    .setMimeType(ContentService.MimeType.JSON);
}
이 함수doGet를 사용하면 지정된 URL에서 GET 요청을 할 때 지정된 처리를 할 수 있습니다.doGet Google Electronic 피드에 기재된 내용을 JSON화하여 되돌려 주는 간단한 프로세스

doGet 함수의 일상적인 사용은 성능에 있어서 매우 엄격하다


참고로 이렇게 doGet 함수를 사용하여 API화하는 방법은 반응 속도가 매우 느리다.
웹 사이트에서 이 함수를 직접 사용하는 API처럼 실시간으로 사용하는 것은 권장되지 않는다는 것이다.
다만, 해반로베의 경우 이 API는 웹사이트 구축 때와 사용doGet 명령의 개발 때 좌우되는 것으로 불린다.
개발할 때 방문할 때마다 이 API를 두드리기 때문에 동작이 느슨하지만 구축할 때 반응 속도가 그리 중요하지 않다.
사이트가 만들어지면 필요한 모든 데이터가 이미 얻은 상태가 되기 때문에 빠르게 이동한다.
위에서 말한 바와 같이yarn dev 함수의 단점 부분에 대해 Habanero Bee는 규격상의 관점에서 무시할 수 있다.

Next.js의 GetStaticPaths와 getStatic Propos에서 처리


그러면 JSON으로 되돌아오는 이 데이터는 해반로베 측 웹사이트 생성 시 활용된다.
지난번에 쓴 바와 같이 해반로베는 Next.js를 기반으로 한다.
웹 사이트 구축 시doGetgetStaticPaths 내 처리에서 구글 전자시드에서 얻은 정보getStaticProps에 따라 부여된 라벨一覧ページ・詳細ページの作成 등에 따라 각각 진행한다는 것이다.
구체적인 처리는 다음과 같다.
이것은 Habanero Bee의 원본 코드에서 발췌한 부분으로 상세한 페이지를 생성할 때의 원본 코드タグページの作成입니다.
일본어 해설을 추가했다.
export const getStaticPaths: GetStaticPaths = async () => {
  if (!process.env.SHEET_URL) {
    throw new Error('BUILD ERROR: Setting the SHEET_URL is required.');
  }

  const { SHEET_URL } = process.env;

  // Google スプレッドシートにアクセスしてJSON化されているサイト情報を取得している
  const response = await fetch(SHEET_URL).then((r) => r.json());
  // 各ページのパスを設定
  const paths = response.content.map((c: Content) => `/${getSlugText(c.slug)}`);

  return { paths, fallback: false };
};

type Params = {
  params: {
    slug: string;
  };
};

export const getStaticProps: GetStaticProps = async ({ params }: Params) => {
  if (!process.env.SHEET_URL) {
    throw new Error('BUILD ERROR: Setting the SHEET_URL is required.');
  }

  const { SHEET_URL } = process.env;

  // Google スプレッドシートにアクセスしてJSON化されているサイト情報を取得している
  const response = await fetch(SHEET_URL).then((r) => r.json());
  const { general, meta, content } = response;
  
  // URLパスに応じたコンテンツを取得している
  const contentData = content.find(
    (c: Content) => getSlugText(c.slug) === params.slug
  );

  // サイトの本文をHTMLにレンダリング
  // (サイトの本文はmarkdownに対応しているため、markdown -> amp htmlへの変換処理を挟んでいます)
  contentData.renderedHTML = await renderAmpHTML(contentData.text);

  // 後述しますが、サイトで利用している画像を一度ダウンロードしています。
  contentData.downloadedImagePath =
    contentData.imagePath &&
    (await getDownloadedImagePath(contentData.imagePath));

  // 前のページ・次のページに関するリンクの作成
  const slugList = content.map((c: Content) => getSlugText(c.slug));
  const targetPageIndex = slugList.indexOf(params.slug);
  contentData.prevPageUrl =
    targetPageIndex && `/${slugList[targetPageIndex - 1]}`;
  contentData.nextPageUrl =
    slugList.length > targetPageIndex + 1 &&
    `/${slugList[targetPageIndex + 1]}`;

  if (!isValidData(general, meta, new Array(contentData))) {
    throw new Error('BUILD ERROR: Invalid sheet data');
  }

  return {
    props: {
      general,
      meta,
      contentData: contentData,
    },
  };
};
상기 처리를 사용하여 페이지를 생성합니다.

amp-태그 생성 정보


위의 소스 코드에 대한 논평에서 후술한 이미지의 다운로드에 대해 다른 프레임워크로 다시 쓰고 싶지만 간단한 개요만 여기에 썼으면 좋겠다고 생각합니다.
Habanero Bee는 AMP에 대응하는 웹 사이트를 만들기 위해 콘텐츠 메모리가 이미지에 있는 경우 이미지habanero-bee/src/pages/[slug].tsx 레이블로 변환해야 합니다.
https://amp.dev/ja/documentation/components/amp-img/ amp-img 레이블은 이미지 크기를 지정해야 하기 때문에 구축 단계 동안 사용된 이미지의 크기를 다운로드하고 검사하며 이미지에 각각 레이블amp-img을 생성합니다.
아직 최적화할 여지가 많지만, 이 처리를 통해 부여받은 이미지를 해반레로 베가 생성한 사이트에 함께 저장하기로 했다.
분야별 방문을 최소화하고 사이트 성능을 높이기 위해서다.
(참고로 구현 전후로 성능을 측정했는데 그 정도로 성능이 향상되지 못했습니다. 측정 사이트가 커지면 개선률이 더 높아질 수 있지만 실제 상황은 어떻습니까? 아래에 참고 이미지를 붙여 주십시오.)
https://github.com/shinshin86/habanero-bee/pull/40#issuecomment-804931623

탭에서amp 탭으로 전환하는 도구


참고로 amp-img 라벨에서 라벨로의 전환 처리는 이쪽 npm포장을 사용합니다.
https://www.npmjs.com/package/img2amp-img
해반로베로 전환이 필요해 급하게 npm 포장을 했다.
만약 img 탭에서 탭amp-img으로 전환하고 싶은 도구가 있다면 시도해 보십시오.
창고는 여기 있습니다.홍보 m()도 기대하고 있고요.m
https://github.com/shinshin86/img2amp-img
글이 길어졌으니 오늘은 여기까지 쓰자.
개인 개발에 관한 글을 쓸 때 어떻게든 자기가 만든 아이디어 있는 부분에 대해 얘기하고 싶어 문장이 좀 긴 경향이 있어요.😅
Habanero Bee는 AMP 대응 사이트를 쉽게 만들 수 있어서 상당히 편리한 도구라고 생각합니다. 가능하면 한번 시도해 보세요.
아이슈·PR 등도 기대하고 있다.
창고는 여기 있습니다.
https://github.com/shinshin86/habanero-bee

좋은 웹페이지 즐겨찾기