열린 도면 이미지 자동 작성

21216 단어 puppeteerjavascript

Originally posted on my personal website https://www.zubach.com/blog/automate-open-graph-image-creation


만약 개발자라면 유행하는 개발 관련 사이트에서 생성된 오픈 그래픽 이미지(Open Graph Protocol의 일부분), 예를 들어 VercelOpen Graph Image as a Service을 본 적이 있을 것이다.이 두 가지 예는 모두 내용과 관련된 이미지를 보여주는 방법을 사용하기 때문에 표준 레이아웃 배경, 내용과 관련된 이미지(vercel의 로고나 작가의 이미지), 글의 제목이나 제목, 설명을 포함한다.
다음은 제가 DEV.to에 발표한 "CSS의 10개 핸드폰 케이스"글의 Open Graph 이미지입니다.

이 두 가지 모두 매우 좋은 방법으로 모든 사이트를 위해 준비를 해서 이 사진들이 유일무이하게 만들어야 한다.나는 이 아이디어를 요약하고 싶다. 마치 빠른 해결 방안이나 첫 번째 단계처럼 og:image초를 빨리 추가해야 하고 시간 원가가 거의 없을 때를 대비한다.

문제.


나는 이러한 방법이 사실상 이상적인 방법이고 반드시 이렇게 해야 한다고 생각하지만 개선을 고려할 수 있는 일은 매우 적다.
  • 은 필요한
  • 처럼 보이도록 설계+개발 방법이 추가로 필요합니다.
  • 은 블로그 게시물
  • 뿐만 아니라 모든 유형의 페이지에 대해 자동으로 OG 이미지를 생성합니다.
    더욱 통용되는 방법으로 이 문제들을 해결하고 모든 수요를 만족시키는 것이 어떻습니까?

    공통 솔루션


    내 아내가 가장 좋아하는 속담은 Arthur Ashe의'네가 지금 있는 곳부터 네가 가진 것을 이용해서 네가 할 수 있는 일을 해라'는 것이다.따라서 개방된 도형 이미지를 생성하고자 하는 모든 페이지의 기존 내용부터 시작하여 불러올 수 있는 페이지를 설계하고 실현합니다.
    이 페이지가 있는 이상, 특정한 크기의 화면 캡처를 되돌려 주는 API를 만듭니다.물론 가장 중요한 정보는 첫 번째 볼 수 있는 화면에 나와야 한다.Puppeteer은 이러한 작업에 필수적인 도구입니다.

    Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol. Puppeteer runs headless by default, but can be configured to run full (non-headless) Chrome or Chromium.


    따라서 다음과 같은 API를 생성하려고 합니다.
  • 에서 제공된 URL 가져오기
  • 은 Puppeter를 통해 URL을 로드하고 이미지를 반환합니다.
  • 아래의 예시에서, 나는 Vercel에 적용되는 방법을 사용했지만, 당신은 그것을 모든 종류의 노드에 사용할 수 있어야 합니다.js 백엔드나 Vercel을 사용하여 이 방법을 마이크로 서비스로 배치하고 백엔드에서 프록시합니다.
    간단함(Vercel에 서버 함수 API가 없는 크기를 제한하는 경우)을 위해 OG 이미지 생성을 처리하기 위한 별도의 프로젝트/마이크로 서비스를 만듭니다.기본 항목은 URL로 표시되지만 HTML 대신 이미지로 반환되는 하위 도메인일 뿐입니다.따라서 만약에 저희 https://example.com/<URL> 사이트 URL이 있다면 오픈 그래픽 이미지 URL은 https://og-image.example.com/<URL>(같은 URL이지만 og-image 하위 도메인에서)

    첫걸음


    Vercel의 Serverless Functions 가이드에 따라 api/index.js을 만들겠습니다.
    const puppeteer = require('puppeteer-core');
    // a chrome we need for Serverless Function API to use by puppeteer
    const chrome = require('chrome-aws-lambda');
    const {
      NODE_ENV = 'production', // needed to be able to run local chromium to test how everything works locally
      WEBSITE // This is your main website URL
    } = process.env;
    // helper function just in case to give a page some time to render things after loading
    const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
    module.exports = async (req, res) => {
      const websiteURL = req.url; // FYI, it starts with `/`
      const fullUrl = `${WEBSITE}${websiteURL}`;
      const config =
        NODE_ENV === 'production'
          ? {
              args: chrome.args,
              executablePath: await chrome.executablePath,
              headless: chrome.headless
            }
          : {
              executablePath: '/opt/homebrew/bin/chromium' // based on `which chromium` command, I installed mine via homebrew
            };
      const browser = await puppeteer.launch(config);
      const page = await browser.newPage();
      await page.setViewport({
        width: 1000,
        height: 800
      });
      await page.goto(fullUrl, { waitUntil: 'networkidle0' });
      // A bit of delay to make sure page is fully settled
      await delay(50);
      const file = await page.screenshot({
        type: 'jpeg',
        quality: 81,
        fullPage: false
      });
      await browser.close();
      res.statusCode = 200;
      res.setHeader('Cache-Control', 's-maxage=300, stale-while-revalidate');
      res.setHeader('Content-Type', `image/jpeg`);
      res.end(file);
    };
    
    Vercel API이므로 vercel.json 구성을 통해 마이크로서비스의 모든 요청을 라우팅해야 합니다.
    {
      "version": 2,
      "routes": [{ "src": "/.*", "dest": "/api/index.js" }]
    }
    
    이렇게이 API는 모든 요청이 완료될 때까지 ({ waitUntil: 'networkidle0' }의 Puppeter 명령에 따라) 페이지를 불러오고, 우리가 필요로 하는 크기와 품질의 화면 캡처를 응답으로 전달합니다.
    이 단계를 완료하면 자동으로 생성된 열린 도면 이미지를 다음과 같이 사용할 수 있습니다.
    <meta
      property="og:image"
      content="https://og-image.example.com/whatever/url/you-wanna?pass=here"
    />
    

    2단계(옵션)


    우리는 이 API의 성능을 향상시키기 위해 몇 가지 일을 할 수 있다.Google은 Google이 어떤 서비스를 사용하고 있는지 알고 있습니다. 이 서비스들은 네트워크 호출을 할 수 있지만 결과는 중요하지 않습니다.
  • 일부 분석
  • 추적 픽셀
  • 소셜 버튼
  • 리뷰 서비스
  • 페이지의 맨 아래쪽에 모든 내용을 로드할 수 있는 경우
  • ❗️가장 중요한 것은 현재 페이지의 열린 도형 이미지에 대한 인용 (이렇게 하면 우리는 무한 순환이 없을 것이다)
  • 따라서 이론적으로 우리는 이러한 요청을 막고 마운트 속도를 좀 높일 수 있다. 왜냐하면 우리가 필요로 하는 것은 단지 이미지일 뿐이지 기능이 완비된 사이트가 아니기 때문이다.페이지 await page.goto(fullUrl, { waitUntil: 'networkidle0' }); 행을 열기 전에 요청을 차단하고 Puppeter에 대한 지침을 제공하는 코드를 추가합니다.
    // to be able to intercept the requests:
    await page.setRequestInterception(true);
    page.on('request', (req) => {
      // 1. Ignore requests for resources that don't produce DOM
      // (images, stylesheets, media).
      const resourceType = req.resourceType();
      const whitelist = [
        'document',
        'script',
        'xhr',
        'fetch',
        'image',
        'stylesheet',
        'font'
      ];
      if (!whitelist.includes(resourceType)) {
        return req.abort();
      }
      // 2. Don't load your analytics lib of choise requests so pageviews aren't 2x.
      const blacklist = [
        'www.google-analytics.com',
        '/gtag/js',
        'ga.js',
        'analytics.js',
        'disqus.com',
        `og-image${websiteURL}` // self-reference I mentioned above
        // add more domains to ignore here
      ];
      if (blacklist.find((regex) => reqUrl.match(regex))) {
        return req.abort();
      }
      // 3. Pass through all other requests.
      req.continue();
    });
    

    3단계(옵션)


    OG 이미지에 동일한 도메인을 사용하기 위해 vercel.json의 구성을 사용하여 https://example.com/og-image/<any-url>과 같은 내부 라우팅을 og-image 마이크로서비스로 라우팅했습니다.
    {
      "version": 2,
      "routes": [
        { "handle": "filesystem" },
        // This one
        {
          "src": "/og-image/(?<path>.*)",
          "dest": "https://og-image.example.com/$path"
        }
        // ... other routes config goes here
      ]
    }
    

    { "handle": "filesystem" } config is specifically at the top, to handle the case where og images can be provided as files right away. If that's not your case - feel free to move the config for og-image route to the top


    it 개선 / 확장 방법


    틀림없이 그것을 개선하고 확장할 방법이 있을 것이다.내가 생각한 극소수는 다음과 같다.

    공통 및 사설 OG 이미지 조합


    블로그 게시물에 대해 DEV.to의 OG 이미지는 매우 좋아 보인다.그래서 우리는 이런 통용적인 방법을 사용하고 간단한 페이지를 만들 수 있으며 셔츠를 캡처해야 한다.https://example.com/blog/url과 비슷한 블로그 게시물 URL이 있다고 가정해 보십시오.마이크로 서비스를 통해 화면을 캡처하는 일반적인 URL은 https://example.com/og-image/blog/url이지만 https://example.com/preview/blog/url과 같은 글을 위해 특정한 작은 페이지를 만들 수 있습니다. 이 페이지들은 OG 이미지에서 볼 수 있는 내용을 정확하게 출력하지만 작은 페이지로 만들 수 있습니다.
    이런 방법은 블로그 게시물, 평론 페이지, 페이지 등에 사용될 수 있다.비슷한 URL 위치(예를 들어 https://example.com/preview/<any-url-here>)에서 점차적으로 작은 미리보기를 위해 이 페이지를 만든 다음에 이 URL에 /og-image/ 접두사를 추가하여 우리의 마이크로 서비스를 사용하여 이 미리보기에서 이미지를 생성하는 것이 주된 생각이다.

    구성 적용


    하나의 큰 개선은 URL에서 일부 env 변수가 아닌 GET 파라미터를 통해 설정을 제공하는 것이다.예를 들어 ?_w=1000&_h=800&_q=81&_t=jpeg(_w은 너비, _h은 높이, _q은 품질, _t은 유형을 표시한다).URL의 일부 실제 GET 매개 변수와 중첩될 수 있기 때문에 _을 사용해서 더욱 독특하고 자바스크립트의 의미에서'사유적'이다.
    이것은 페이지에 여러 개의 OG 이미지 <meta /> 라벨이 있을 수 있기 때문에 크기에 따라 다른 목적에 사용할 수 있습니다.서로 다른 소셜네트워크서비스가 이러한 기능을 사용하고 있기 때문에 그들은 자신의 수요에 따라 서로 다른 크기를 사용할 수 있다.

    데모


    다음은 제 사이트에 있는 이 블로그 포스터의 오픈 사진의 모습입니다.

    and the fact that this image is loaded, means that self-reference fix we did in "Step 2" works


    유용한 서비스 및 도구에 링크

  • Open Graph Protocol
  • Vercel
  • Vercel Open Graph Image as a Service

  • Puppeteer
  • Facebook Sharing Debugger
  • 좋은 웹페이지 즐겨찾기