ناوبری فوری و انتقال بدون درز صفحه را به یک برنامه وب اضافه کنید

۱. قبل از شروع

این آزمایشگاه کد به شما آموزش می‌دهد که چگونه با جدیدترین APIهایی که گوگل کروم به صورت پیش‌فرض پشتیبانی می‌کند، ناوبری فوری و انتقال یکپارچه صفحات را به یک برنامه وب نمونه اضافه کنید.

این برنامه وب نمونه، ارزش غذایی میوه‌ها و سبزیجات محبوب را بررسی می‌کند. صفحات فهرست میوه‌ها و جزئیات میوه‌ها به صورت یک برنامه تک صفحه‌ای (SPA) و صفحات فهرست سبزیجات و جزئیات سبزیجات به صورت یک برنامه چند صفحه‌ای سنتی (MPA) ساخته شده‌اند.

نمونه اسکرین شات برنامه در موبایلنمونه اسکرین شات برنامه در موبایل

به طور خاص، شما پیش‌رندرینگ ، حافظه پنهان عقب/جلو (bfcache) و پروکسی پیش‌واکشی خصوصی را برای ناوبری فوری و انتقال عناصر ریشه/مشترک را برای انتقال‌های یکپارچه صفحه پیاده‌سازی می‌کنید. شما پیش‌رندرینگ و bfcache را برای صفحات MPA و انتقال عناصر مشترک را برای صفحات SPA پیاده‌سازی می‌کنید.

سرعت سایت همیشه جنبه مهمی از تجربه کاربری است، به همین دلیل گوگل Core Web Vitals را معرفی کرد، مجموعه‌ای از معیارها که عملکرد بارگذاری، تعامل و پایداری بصری صفحات وب را برای سنجش تجربه کاربری در دنیای واقعی اندازه‌گیری می‌کنند. جدیدترین APIها به شما کمک می‌کنند تا امتیاز Core Web Vitals وب‌سایت خود را در این زمینه، به ویژه برای عملکرد بارگذاری، بهبود بخشید.

تصویر نمایشی چگونه bfcache زمان بارگذاری را بهبود می‌بخشد

نسخه نمایشی از Mindvalley

کاربران همچنین به استفاده از انتقال‌ها برای ایجاد ناوبری و تغییرات وضعیت بسیار شهودی در برنامه‌های بومی موبایل عادت کرده‌اند. متأسفانه، تکرار چنین تجربیات کاربری در وب ساده نیست. در حالی که ممکن است بتوانید با APIهای فعلی پلتفرم وب به جلوه‌های مشابهی دست یابید، توسعه ممکن است بسیار دشوار یا پیچیده باشد، به خصوص در مقایسه با همتایان ویژگی در برنامه‌های اندروید یا iOS. APIهای یکپارچه برای پر کردن این شکاف تجربه کاربر و توسعه‌دهنده بین برنامه و وب طراحی شده‌اند.

نسخه آزمایشی API انتقال عناصر مشترک از pixivنسخه ی نمایشی API Shared Element Transitions از Tokopedia

نسخه‌های نمایشی از pixiv و Tokopedia

پیش‌نیازها

آگاهی از:

آنچه یاد خواهید گرفت:

نحوه پیاده سازی:

  • پیش‌رندرینگ
  • بی اف کش
  • پروکسی خصوصی Prefetch
  • انتقال عناصر ریشه/مشترک

آنچه خواهید ساخت

یک برنامه وب نمونه ساخته شده با Next.js که با جدیدترین قابلیت‌های مرورگر فوری و یکپارچه غنی شده است:

  • ناوبری تقریباً آنی با پیش‌رندرینگ
  • bfcache برای بارگذاری فوری با دکمه‌های عقب و جلو مرورگر
  • برداشت‌های اولیه عالی از ناوبری بین مبدا با پروکسی خصوصی پیش واکشی یا تبادل امضا شده (SXG)
  • انتقال یکپارچه بین صفحات با انتقال عناصر ریشه/مشترک

آنچه نیاز دارید

  • نسخه کروم ۱۰۱ یا بالاتر

۲. شروع کنید

فعال کردن پرچم‌های کروم

  1. به about://flags بروید و سپس پرچم‌های زمان اجرای Prerender2 و documentTransition API را فعال کنید.
  2. مرورگر خود را مجدداً راه اندازی کنید.

کد را دریافت کنید

  1. کد را از این مخزن گیت‌هاب در محیط توسعه مورد علاقه خود باز کنید:
git clone -b codelab git@github.com:googlechromelabs/instant-seamless-demo.git
  1. وابستگی‌های مورد نیاز برای اجرای سرور را نصب کنید:
npm install
  1. سرور را روی پورت ۳۰۰۰ شروع کنید:
npm run dev
  1. در مرورگر خود به آدرس http://localhost:3000 بروید.

حالا می‌توانید برنامه خود را ویرایش و بهبود دهید. هر زمان که تغییراتی ایجاد کنید، برنامه دوباره بارگذاری می‌شود و تغییرات شما مستقیماً قابل مشاهده هستند.

۳. ادغام پیش‌رندرینگ

برای این دمو، زمان بارگذاری صفحه جزئیات سبزیجات در برنامه نمونه به دلیل تأخیر دلخواه در سمت سرور بسیار کند است. شما می‌توانید این زمان انتظار را با پیش‌رندرینگ از بین ببرید.

برای افزودن دکمه‌های پیش‌رندر به صفحه فهرست سبزیجات و فعال کردن پیش‌رندر پس از کلیک کاربر:

  1. یک کامپوننت دکمه ایجاد کنید که تگ اسکریپت «specution-rules» را به صورت پویا وارد کند:

کامپوننت‌ها/prerender-button.js

import { useContext } from 'react'
import ResourceContext from './resource-context'

// You use resource context to manage global states.
// In the PrerenderButton component, you update the prerenderURL parameter when the button is clicked.
export default function PrerenderButton() {
  const { dispatch } = useContext(ResourceContext)
  const handleClick = (e) => {
    e.preventDefault()
    e.stopPropagation()
    const parent = e.target.closest('a')
    if (!parent) {
      return
    }
    const href = parent.getAttribute('href')
    dispatch({ type: 'update', prerenderURL: href })
  }

  return (
    <button className='ml-auto bg-gray-200 hover:bg-gray-300 px-4 rounded' onClick={handleClick}>
      Prerender
    </button>
  )
}
  1. کامپوننت PrerenderButton را در فایل list-item.js وارد کنید.

کامپوننت‌ها/لیست-آیتم.js

// Codelab: Add a PrerenderButton component.
import PrerenderButton from './prerender-button'

...
function ListItemForMPA({ item, href }) {
  return (
    <a href={href} className='block flex items-center'>
      <Icon src={item.image} />
      <div className='text-xl'>{item.name}</div>
      {/* Codelab: Add PrerenderButton component. */}
      <PrerenderButton />
    </a>
  )
}
  1. یک کامپوننت برای افزودن API قوانین حدس و گمان ایجاد کنید.

کامپوننت SpeculationRules به صورت پویا یک تگ اسکریپت را در صفحه وارد می‌کند، زمانی که برنامه وضعیت prerenderURL را به‌روزرسانی می‌کند.

کامپوننت‌ها/speculationrules.js

import Script from 'next/script'
import { useContext, useMemo } from 'react'
import ResourceContext from './resource-context'

export default function SpeculationRules() {
  const { state } = useContext(ResourceContext)
  const { prerenderURL } = state

  return useMemo(() => {
    return (
      <>
        {prerenderURL && (
          <Script id='speculationrules' type='speculationrules'>
            {`
            {
              "prerender":[
                {
                  "source": "list",
                  "urls": ["${prerenderURL}"]
                }
              ]
            }
          `}
          </Script>
        )}
      </>
    )
  }, [prerenderURL])
}
  1. کامپوننت‌ها را با برنامه ادغام کنید.

صفحات/_app.js

// Codelab: Add the SpeculationRules component.
import SpeculationRules from '../components/speculationrules'

function MyApp({ Component, pageProps }) {
  useAnalyticsForSPA()

  return (
    <ResourceContextProvider>
      <Layout>
        <Component {...pageProps} />
      </Layout>
      {/* Codelab: Add SpeculationRules component */}
      <SpeculationRules />
      <Script id='analytics-for-mpa' strategy='beforeInteractive' src='/analytics.js' />
    </ResourceContextProvider>
  )
}

export default MyApp
  1. روی پیش‌رندر کلیک کنید.

حالا می‌توانید بهبود قابل توجه بارگذاری را مشاهده کنید. در حالت واقعی، پیش‌رندرینگ برای صفحه‌ای که کاربر احتمالاً در مرحله بعد از آن بازدید خواهد کرد، طبق برخی از روش‌های اکتشافی، فعال می‌شود.

ویدیوی نمونه‌ی دموی برنامه برای پیش‌رندرینگ

تجزیه و تحلیل

به طور پیش‌فرض، فایل analytics.js در برنامه وب نمونه، هنگامی که رویداد DOMContentLoaded رخ می‌دهد، یک رویداد page-view ارسال می‌کند. متأسفانه، این کار عاقلانه نیست زیرا این رویداد در مرحله پیش رندرینگ اجرا می‌شود.

برای رفع این مشکل ، رویدادهای document.prerendering و prerenderingchange را معرفی کنید:

  • فایل analytics.js را بازنویسی کنید:

عمومی/تحلیلی.js

  const sendEvent = (type = 'pageview') => {
    // Codelab: Make analytics prerendering compatible.
    // The pageshow event could happen in the prerendered page before activation.
    // The prerendered page should be handled by the prerenderingchange event.
    if (document.prerendering) {
      return
    }
    console.log(`Send ${type} event for MPA navigation.`)
    fetch(`/api/analytics?from=${encodeURIComponent(location.pathname)}&type=${type}`)
  }
  ...

  // Codelab: Make analytics prerendering compatible.
  // The prerenderingchange event is triggered when the page is activated.
  document.addEventListener('prerenderingchange', () => {
    console.log('The prerendered page was activated.')
    sendEvent()
  })
  ...

عالی شد، شما با موفقیت تجزیه و تحلیل‌های خود را طوری تغییر دادید که با پیش‌رندر سازگار باشند. حالا می‌توانید گزارش‌های بازدید از صفحه را با زمان‌بندی صحیح در کنسول مرورگر مشاهده کنید.

۴. مسدودکننده‌های bfcache را حذف کنید

کنترل کننده رویداد unload را حذف کنید

داشتن یک رویداد unload غیرضروری یک اشتباه بسیار رایج است که دیگر توصیه نمی‌شود. این کار نه تنها مانع از کار bfcache می‌شود، بلکه غیرقابل اعتماد نیز هست. برای مثال، همیشه روی موبایل و سافاری اجرا نمی‌شود.

به جای رویداد unload ، از رویداد pagehide استفاده می‌کنید که در تمام مواردی که رویداد unload اجرا می‌شود و زمانی که صفحه‌ای در bfcache قرار می‌گیرد، فعال می‌شود.

برای حذف کنترل کننده رویداد unload :

  • در فایل analytics.js ، کد مربوط به رویداد unload را با کد مربوط به رویداد pagehide جایگزین کنید:

عمومی/تحلیلی.js

// Codelab: Remove the unload event handler for bfcache.
// The unload event handler prevents the content from being stored in bfcache. Use the pagehide event instead.
window.addEventListener('pagehide', () => {
  sendEvent('leave')
})

به‌روزرسانی هدر کنترل حافظه پنهان

صفحاتی که با هدر HTTP از نوع Cache-control: no-store ارائه می‌شوند، از ویژگی bfcache مرورگر بهره‌مند نمی‌شوند، بنابراین بهتر است در استفاده از این هدر صرفه‌جویی کنید. به طور خاص، اگر صفحه حاوی اطلاعات شخصی‌سازی شده یا حیاتی مانند وضعیت ورود به سیستم نباشد، احتمالاً نیازی به ارائه آن با هدر HTTP از نوع Cache-control: no-store ندارید.

برای به‌روزرسانی هدر cache-control برنامه نمونه:

  • کد getServerSideProps را تغییر دهید:

صفحات/سبزیجات/index.js

export const getServerSideProps = middleware(async (ctx) => {
  const { req, res } = ctx
  // Codelab: Modify the cache-control header.
  res.setHeader('Cache-Control', 'public, s-maxage=10, stale-while-revalidate=59')
  ...

صفحات/سبزیجات/[نام].js

export const getServerSideProps = middleware(async (ctx) => {
  const { req, res, query } = ctx
  // Codelab: Modify the cache-control header.
  res.setHeader('Cache-Control', 'public, s-maxage=10, stale-while-revalidate=59')
  ...

تعیین اینکه آیا یک صفحه از bfcache بازیابی شده است یا خیر

رویداد pageshow درست پس از رویداد load ، زمانی که صفحه برای اولین بار بارگذاری می‌شود و هر زمان که صفحه از bfcache بازیابی شود، اجرا می‌شود. رویداد pageshow دارای یک ویژگی persisted است که اگر صفحه از bfcache بازیابی شده باشد، مقدار آن true و در غیر این صورت false است. می‌توانید از ویژگی persisted برای تشخیص بارگذاری‌های منظم صفحه از بازیابی‌های bfcache استفاده کنید. سرویس‌های تحلیلی بزرگ باید از bfcache آگاه باشند، اما می‌توانید بررسی کنید که آیا صفحه از bfcache بازیابی شده است یا خیر و رویدادها را به صورت دستی ارسال کنید.

برای تعیین اینکه آیا یک صفحه از bfcache بازیابی شده است یا خیر:

  • این کد را به فایل analytics.js اضافه کنید.

عمومی/تحلیلی.js

  // Codelab: Use the pageshow event handler for bfcache.
  window.addEventListener('pageshow', (e) => {
    // If the persisted flag exists, the page was restored from bfcache.
    if (e.persisted) {
      console.log('The page was restored from bfcache.')
      sendEvent()
    }
  })

اشکال‌زدایی یک صفحه وب

ابزارهای توسعه‌دهنده کروم می‌توانند به شما کمک کنند صفحات خود را آزمایش کنید تا از بهینه‌سازی آنها برای bfcache اطمینان حاصل کنید و هرگونه مشکلی را که ممکن است آنها را غیرقابل قبول کند، شناسایی کنید.

برای آزمایش یک صفحه خاص:

  1. در کروم به صفحه مورد نظر بروید.
  2. در ابزارهای توسعه‌دهنده کروم، روی برنامه > حافظه پنهان رو به جلو > اجرای تست کلیک کنید.

ابزارهای توسعه‌دهنده کروم تلاش می‌کنند تا به صفحه دیگری بروند و سپس برگردند تا مشخص کنند که آیا صفحه می‌تواند از طریق bfcache بازیابی شود یا خیر.

49bf965af35d5324.png

در صورت موفقیت، پنل به شما می‌گوید که صفحه از حافظه پنهان back-forward بازیابی شده است:

۴۷۰۱۵a۰de۴۵f۰b۰f.png

اگر ناموفق بود، پنل به شما می‌گوید که صفحه بازیابی نشده و دلیل آن را نیز توضیح می‌دهد. اگر دلیل چیزی باشد که شما به عنوان یک توسعه‌دهنده می‌توانید آن را برطرف کنید، پنل این موضوع را نیز به شما می‌گوید.

dcf0312c3fc378ce.png

۵. فعال کردن پیش‌واکشی بین سایتی

پیش‌واکشی (Prefetching) شروع به واکشی (fetch) زودتر می‌کند تا بایت‌ها هنگام پیمایش کاربر در مرورگر باشند، که این امر پیمایش را تسریع می‌کند. این یک راه آسان برای بهبود Core Web Vitals و جبران برخی از فعالیت‌های شبکه قبل از پیمایش است. این امر مستقیماً Largest Contentful Paint (LCP) را تسریع می‌کند و فضای بیشتری برای First Input Delay (FID) و Cumulative Layout Shift (CLS) هنگام پیمایش فراهم می‌کند.

پراکسی پیش‌واکشی خصوصی، پیش‌واکشی بین سایتی را فعال می‌کند، اما اطلاعات خصوصی کاربر را برای سرور مقصد فاش نمی‌کند.

نحوه کار پروکسی خصوصی Prefetch

فعال کردن پیش‌واکشی بین سایتی با استفاده از پراکسی پیش‌واکشی خصوصی

صاحبان وب‌سایت کنترل پیش‌واکشی را از طریق یک منبع توصیه ترافیک شناخته‌شده، مشابه /robots.txt برای خزنده‌های وب، حفظ می‌کنند که به یک سرور HTTP اجازه می‌دهد اعلام کند که عوامل پیاده‌سازی باید توصیه‌های مربوطه را اعمال کنند. در حال حاضر، صاحبان وب‌سایت می‌توانند به عامل توصیه کنند که اتصالات شبکه را مجاز نداند یا محدود کند. در آینده، ممکن است توصیه‌های دیگری نیز اضافه شود.

برای میزبانی یک منبع مشاوره ترافیکی:

  1. این فایل شبیه به JSON را اضافه کنید:

public/.well-known/traffic-advice

[
  {
    "user_agent": "prefetch-proxy",
    "google_prefetch_proxy_eap": {
      "fraction": 1
    }
  }
]

فیلد google_prefetch_proxy_eap یک فیلد ویژه برای برنامه دسترسی زودهنگام است و فیلد fraction فیلدی برای کنترل کسری از prefetch های درخواستی است که Private Prefetch Proxy ارسال می‌کند.

توصیه‌های ترافیکی باید با نوع MIME application/trafficadvice+json برگردانده شوند.

  1. در فایل next.config.js ، هدر پاسخ را پیکربندی کنید:

فایل پیکربندی بعدی (next.config.js)

const nextConfig = {
  // Codelab: Modify content-type for traffic advice file.
  async headers() {
    return [
      {
        source: '/.well-known/traffic-advice',
        headers: [
          {
            key: 'Content-Type',
            value: 'application/trafficadvice+json',
          },
        ],
      },
    ]
  },
}

module.exports = nextConfig

۶. ادغام API انتقال عناصر مشترک

وقتی کاربری در وب از یک صفحه به صفحه دیگر می‌رود، محتوایی که می‌بیند به طور ناگهانی و غیرمنتظره تغییر می‌کند، صفحه اول ناپدید می‌شود و صفحه جدید ظاهر می‌شود. این تجربه کاربری متوالی و منقطع، گیج‌کننده است و منجر به بار شناختی بالاتری می‌شود، زیرا کاربر مجبور می‌شود چگونگی رسیدن به جایی که هست را کنار هم بگذارد. علاوه بر این، این تجربه، میزان درک کاربران از بارگذاری صفحه را در حین انتظار برای بارگذاری مقصد مورد نظر، افزایش می‌دهد.

انیمیشن‌های بارگذاری روان، بار شناختی را کاهش می‌دهند زیرا کاربران هنگام پیمایش بین صفحات، در متن باقی می‌مانند و تأخیر ادراک‌شده هنگام بارگذاری را کاهش می‌دهند زیرا کاربران در این بین چیزی جذاب و لذت‌بخش می‌بینند. به همین دلایل، اکثر پلتفرم‌ها، مانند اندروید، iOS، MacOS و ویندوز، ابتدایی‌های آسان برای استفاده را ارائه می‌دهند که به توسعه‌دهندگان اجازه می‌دهد انتقال‌های یکپارچه‌ای ایجاد کنند.

API مربوط به انتقال عناصر مشترک، صرف نظر از اینکه انتقال‌ها بین سندی (MPA) یا درون سندی (SPA) باشند، همین قابلیت را در وب در اختیار توسعه‌دهندگان قرار می‌دهد.

نسخه آزمایشی API انتقال عناصر مشترک از pixivنسخه ی نمایشی API Shared Element Transitions از Tokopedia

نسخه‌های نمایشی از pixiv و Tokopedia

برای ادغام API انتقال عناصر مشترک برای بخش SPA برنامه نمونه:

  1. یک قلاب سفارشی برای مدیریت انتقال در فایل use-page-transition.js ایجاد کنید:

utils/use-page-transition.js

import { useEffect, useContext, useRef, useCallback } from 'react'
import ResourceContext from '../components/resource-context'

// Call this hook on this first page before you start the page transition. For Shared Element Transitions, you need to call the transition.start() method before the next page begins to render, and you need to do the Document Object Model (DOM) modification or setting of new shared elements inside the callback so that this hook returns the promise and defers to the callback resolve.
export const usePageTransitionPrep = () => {
  const { dispatch } = useContext(ResourceContext)

  return (elm) => {
    const sharedElements = elm.querySelectorAll('.shared-element')
    // Feature detection
    if (!document.createDocumentTransition) {
      return null
    }

    return new Promise((resolve) => {
      const transition = document.createDocumentTransition()
      Array.from(sharedElements).forEach((elm, idx) => {
        transition.setElement(elm, `target-${idx}`)
      })
      transition.start(async () => {
        resolve()
        await new Promise((resolver) => {
          dispatch({ type: 'update', transition: { transition, resolver } })
        })
      })
    })
  }
}

// Call this hook on the second page. Inside the useEffect hook, you can refer to the actual DOM element and set them as shared elements with the transition.setElement() method. When the resolver function is called, the transition is initiated between the captured images and newly set shared elements.
export const usePageTransition = () => {
  const { state, dispatch } = useContext(ResourceContext)
  const ref = useRef(null)
  const setRef = useCallback((node) => {
    ref.current = node
  }, [])

  useEffect(() => {
    if (!state.transition || !ref.current) {
      return
    }
    const { transition, resolver } = state.transition
    const sharedElements = ref.current.querySelectorAll('.shared-element')
    Array.from(sharedElements).forEach((elm, idx) => {
      transition.setElement(elm, `target-${idx}`)
    })
    resolver()
    return () => {
      dispatch({ type: 'update', transition: null })
    }
  })

  return setRef
}
  1. هوک سفارشی usePageTransitionPrep() را در صفحه لیست فراخوانی کنید و سپس تابع async را برای اجرای متد transition.start() درون رویداد click فراخوانی کنید.

درون تابع، عناصر کلاس shared-element جمع‌آوری و به عنوان عناصر مشترک ثبت می‌شوند.

کامپوننت‌ها/لیست-آیتم.js

// Codelab: Add the Shared Element Transitions API.
import { usePageTransitionPrep } from '../utils/use-page-transition'
...

function ListItemForSPA({ item, href }) {
  // Codelab: Add Shared Element Transitions.
  const transitionNextState = usePageTransitionPrep()
  const handleClick = async (e) => {
    const elm = e.target.closest('a')
    await transitionNextState(elm)
  }
  return (
    <Link href={href}>
      <a className='block flex items-center' onClick={handleClick}>
        <Icon src={item.image} name={item.name} className='shared-element' />
        <div className='text-xl'>{item.name}</div>
      </a>
    </Link>
  )
}
  1. در صفحه جزئیات، هوک usePageTransition() را فراخوانی کنید تا تابع فراخوانی transition.start() به پایان برسد.

در این فراخوانی مجدد، عناصر مشترک در صفحه جزئیات نیز ثبت می‌شوند.

صفحات/میوه‌ها/[نام].js

// Codelab: Add the Shared Element Transitions API.
import { usePageTransition } from '../../utils/use-page-transition'

const Item = ({ data }) => {
  const { name, image, amountPer, nutrition } = data
  // Codelab: Add the Shared Element Transitions API.
  const ref = usePageTransition()

  return (
    <div className={'flex flex-col items-center justify-center py-4 px-4 sm:flex-row'} ref={ref}>
      <div className='flex flex-col items-center sm:w-2/4'>
        <Image
          className='object-cover border-gray-100 border-2 rounded-full shared-element'
          src={image}
          width='240'
          height='240'
          alt={`picture of ${name}`}
        />
        <h1 className='text-4xl font-bold mt-4'>{name}</h1>
      </div>

      <div className='sm:w-2/4 w-full'>
        <Nutrition amountPer={amountPer} nutrition={nutrition} />
      </div>
    </div>
  )
...
}

حالا می‌توانید ببینید که عناصر تصویر در صفحات فهرست و جزئیات به اشتراک گذاشته شده‌اند و در انتقال صفحه به طور یکپارچه به هم متصل شده‌اند. شما حتی می‌توانید انیمیشن را با استفاده از شبه عناصر CSS سفارشی کنید تا زیباتر شود.

ویدیوی نمونه‌ی دموی اپلیکیشن بدون انتقال المان مشترکویدیوی نمونه‌ی دموی اپلیکیشن با Shared Element Transition

۷. تبریک

تبریک می‌گویم! شما یک برنامه وب فوری و یکپارچه با یک تجربه کاربری کم‌دردسر، جذاب و شهودی ایجاد کردید.

بیشتر بدانید

پیش‌رندرینگ

بی اف کش

پیش‌واکشی بین‌سایتی

مبادلات امضا شده

انتقال عناصر ریشه/مشترک

این APIها هنوز در مراحل اولیه توسعه هستند، بنابراین لطفاً نظرات خود را در crbug.com یا به عنوان مشکل در مخزن Github APIهای مربوطه به اشتراک بگذارید.