<script type="speculationrules">

Експериментальне

Це експериментальна технологія.
Перед її використанням у промисловій розробці уважно перевірте Таблицю сумісності з браузерами.

Значення speculationrules (правила спекуляції) атрибута type елемента <script> вказує на те, що тіло цього елемента містить правила спекуляції.

Правила спекуляції приймають форму структури JSON, що визначає те, які браузеру слід отримати наперед або візуалізувати наперед. Це частина API правил спекуляції.

[!NOTE] Правила спекуляції можна визначати в зовнішніх текстових файлах, на які посилається заголовок HTTP Speculation-Rules, за допомогою такого ж представлення JSON, як показано нижче. Задавати заголовок HTTP корисно у тих випадках, коли розробники не можуть безпосередньо змінювати сам документ.

Синтаксис

<script type="speculationrules">
  // Об'єкт JSON, що визначає правила
</script>

[!NOTE] Атрибути src, async, nomodule, defer, crossorigin, integrity і referrerpolicy повинні не бути задані.

Винятки

TypeError

Визначення правил спекуляції не є дійсним об'єктом JSON.

Опис

Елемент <script type="speculationrules"> повинен містити дійсну структуру JSON, що визначає правила спекуляції. Наступні приклади показують окремі правила спекуляції для попереднього отримання та попередньої візуалізації:

<script type="speculationrules">
  {
    "prefetch": [
      {
        "source": "list",
        "urls": ["next.html", "next2.html"],
        "requires": ["anonymous-client-ip-when-cross-origin"],
        "referrer_policy": "no-referrer"
      }
    ]
  }
</script>
<script type="speculationrules">
  {
    "prerender": [
      {
        "where": { "href_matches": "/next" },
        "eagerness": "eager"
      }
    ]
  }
</script>

Представлення правил спекуляції в JSON

Ця структура JSON вміщає одне або більше полів на вищому рівні, кожне з яких представляє одну дію, для якої визначено правила спекуляції. Наразі підтримуються такі дії:

"prefetch" Необов'язкове

Правила для потенційних майбутніх переходів, тіла відповідей відповідних документів яких повинні бути завантажені, що призводить до суттєвого покращення ефективності, коли до таких документів відбувається перехід. Зверніть увагу, що жоден з підресурсів, на які посилається сторінка, не завантажується.

"prerender" Необов'язкове

Правила для потенційних майбутніх переходів, відповідні документи яких повинні бути повністю завантажені, візуалізовані та завантажені в невидиму вкладку. Це включає завантаження всіх підресурсів, виконання всього JavaScript, і навіть завантаження підресурсів і виконання отримання даних, запущених JavaScript. Коли до такого документа відбувається перехід, він є миттєвим, що призводить до значного покращення ефективності.

[!NOTE] Ознайомтеся з основною сторінкою API правил спекуляції для отримання повної інформації про те, як ефективно використовувати попереднє отримання та попередню візуалізацію.

Кожне поле дії вміщає масив, котре, своєю чергою, містить один або більше об'єктів. Кожний об'єкт містить одне правило, що визначає набір URL і споріднені параметри.

Кожний об'єкт може містити наступні властивості:

"source"

Рядок, що позначає джерело URL, до яких застосовується правило. Це необов'язково, оскільки таке значення завжди можна вивести з інших властивостей.

Можливі значення:

"document"

Задає те, що URL зіставлятимуться з посиланнями переходу в пов'язаному документі (у вигляді, визначеному в елементах <a> та <area>), на основі умов, описаних ключем "where". Зауважте, що наявність ключа "where" вказує на "source": "document", явне задання "document" – необов'язкове.

"list"

Задає те, що URL повинні бути взяті зі списку, визначеного в ключі "urls". Зауважте, що наявність ключа "urls" вказує на "source": "list", явне задання "list" – необов'язкове.

"urls"

Масив рядків, що представляє список URL, до яких застосовуватиметься правило. Це можуть бути абсолютні чи відносні URL. Відносні URL тлумачаться відносно базового URL документа (якщо опис правил вбудований у документ) або відносно URL зовнішнього ресурсу (якщо вони отримані зовні). В одному правилі не можна задати водночас як "urls", так і "where".

"where"

Об'єкт, що представляє умови, за яких правило спрацьовує щодо URL, що містяться в пов'язаному документі. Фактично, об'єкт "where" представляє перевірку, яка виконується для кожного посилання на сторінці, щоб визначити, чи застосовувати до нього правило спекуляції. В одному правилі не можна задати водночас як і "where", так і "urls".

Такий об'єкт може містити лише одну й тільки одну з наступних властивостей:

"href_matches"

Рядок, що містить патерн URL, або масив, що містить кілька рядків з патернами URL, що відповідають стандартному синтаксису API патернів URL. До посилань у документі, URL яких відповідають патерну (чи патернам), застосовується правило.

"relative_to"

У випадку умови "href_matches", це може вказувати, стосовно чого повинна бути відносною умова. Це працює так само, як ключ "relative_to" на рівні правила, за винятком того, що воно впливає лише на одну умову "href_matches" всередині ключа "where".

"selector_matches"

Рядок, що містить селектор CSS, або масив, що містить кілька селекторів CSS. До посилань у документі, які відповідають цим селекторам, застосовується правило.

"and"

Масив, що містить один або більше об'єктів, що містять умови ("href_matches", "selector_matches", "and", "not" або "or"), всі з яких повинні давати збіг, щоб правило застосувалося.

"not"

Об'єкт, що містить одну умову ("href_matches", "selector_matches", "and", "not" або "or"), і якщо з цією умовою є збіг, то правило не застосовується. До всіх посилань, що не мають збігу з цією умовою, буде застосовано правило.

"or"

Масив, що містить один або більше об'єктів, що містять умови ("href_matches", "selector_matches", "and", "not" або "or"), і якщо будь-яка з умов дає збіг, то правило застосовується.

Умови "where" можуть бути вкладені на кілька рівнів для створення складних умов, а ще можна розділяти їх на кілька окремих правил, щоб умови лишалися простими. Дивіться розгорнуте пояснення в прикладах where, а також кілька прикладів застосування.

"eagerness"

Рядок, що дає браузеру підказку щодо того, наскільки швидко він має попередньо завантажувати або візуалізувати цільову сторінку посилання, щоб збалансувати виграш щодо продуктивності відносно витрат ресурсів. Можливі значення:

"immediate"

Розробник вважає, що за посиланням перейдуть з дуже високою ймовірністю, чи документ може завантажуватися суттєвий час. Попереднє отримання або попередня візуалізація має початися якомога швидше, за винятком випадків, коли цьому заважають налаштування користувача або обмеження щодо ресурсів.

"eager"

Розробник бажає попередньо завантажити чи візуалізувати велику кількість переходів, якомога раніше. Попереднє отримання або попередня візуалізація має початися при найменшому натяку на те, що за посиланням можуть перейти. Наприклад, користувач може порухати курсор миші в бік посилання, навести на неї чи передати їй фокус на якусь мить, або зупинити прокручення, коли посилання перебуває на видноті.

"moderate"

Розробник прагне золотої середини між eager і conservative. Попереднє отримання або візуалізація має початися, коли є резонна вказівка на те, що користувач перейде за посиланням у найближчому майбутньому. Наприклад, він може прокрутити сторінку так, що посилання потрапить в область перегляду, або торкнутися його на якусь мить.

"conservative"

Розробник бажає отримати певні переваги від спекулятивного завантаження, витрачаючи доволі невеликі ресурси. Попереднє отримання або візуалізація має початися лише тоді, коли користувач починає клацати по посиланню, наприклад, при події mousedown або pointerdown.

Якщо "eagerness" не задано явно, то правила списку ("urls") усталено отримують значення immediate, а правила документу ("where") — conservative. Браузер бере цю підказку до уваги вкупі зі власними евристиками, тож він може обрати посилання, яке розробник задав як менш термінове за інше, якщо менш терміновий кандидат вважається кращим вибором.

Рядок, що дає браузеру підказку щодо того, яке значення заголовка No-Vary-Search буде задано на відповідях щодо документів, які він отримує на запити попереднього отримання та візуалізації. Браузер може користуватися цією підказкою, щоб наперед з'ясувати, чи варто чекати завершення поточного попереднього отримання чи візуалізації, чи краще почати новий запит отримання, коли є збіг з правилом спекуляції. Дивіться більш детальне пояснення того, як цим можна користуватися, у прикладі "expects_no_vary_search".

"referrer_policy"

Рядок, що представляє рядок конкретної політики посилача для використання при запитуванні URL, заданих у правилі – дивіться можливі значення в Referrer-Policy. Такий рядок потрібен, щоб дати змогу сторінці-посилачу задавати для спекуляційних запитів суворішу політику, ніж та, що вже задана для всієї сторінки (або усталено, або за допомогою Referrer-Policy).

[!NOTE] Міжсайтове попереднє отримання вимагає, щоб політика посилача була щонайменше так само сувора, як усталене значення "strict-origin-when-cross-origin" — отже, це може бути "strict-origin-when-cross-origin", "same-origin", "strict-origin" або "no-referrer". Поблажливіша політика, задана в правилах спекуляції, пересилює суворішу політику, задану на сторінці-посилачу, якщо вона все ще є достатньо суворою для міжсайтових запитів.

[!NOTE] У випадку правил документа буде використана задана політика посилача для посилання, що дало збіг (наприклад, за допомогою атрибута referrerpolicy), якщо правило не задає політику, що її пересилює.

"relative_to"

Рядок, що задає те, відносно чого посилання, що зіставляються за URL, є відносними. Можливі значення:

document

URL повинні зіставлятися відносно документу, на якому задані правила спекуляції.

ruleset

URL повинні зіставлятися відносно файлу, в якому задані правила. Це усталене значення.

Це ключове налаштування має значення лише для правил, заданих у зовнішньому правилі (заданому за допомогою заголовку Speculation-Rules). Коли правила визначаються всередині того ж документу, для якого вони задаються (тобто в елементі <script>, вбудованому в документ), воно ні на що не впливає.

"requires"

Масив рядків, що представляють можливості браузера, що розбирає правило, які повинні бути доступні, щоб правило було застосовано до заданих URL.

[!WARNING] Попереднє отримання автоматично зазнає невдачі в браузерах, що не можуть виконати одну з вимог, навіть якщо вони підтримують API правил спекуляції.

Можливі значення:

"anonymous-client-ip-when-cross-origin"

(Лише для "prefetch".) Задає те, що правило має збіг лише тоді, коли користувацький агент може не дати серверу походження побачити клієнтську IP-адресу, якщо відбувається запит попереднього отримання з іншого походження. Те, як саме це працює, залежить від конкретики браузерної реалізації. Наприклад:

  • Реалізація Chrome приховує IP-адресу за допомогою проксі, що належить Google, таким чином, усталено це працює лише для посилачів, які контролює Google (оскільки в такому випадку надсилання цільових URL до Google не є додатковим витоком приватності). Коли це використовується на сайті, що не належить Google, правила, що включають це значення, матимуть збіг лише для користувачів, що ввімкнули "Покращене попереднє завантаження" у chrome://settings/preloading.
  • Іншим браузерам на основі Chromium доведеться надати власні рішення. Рекомендується ретельне тестування в усіх цільових браузерах.
  • Майбутня реалізація Safari, можливо, використовуватиме щось на зразок iCloud Private Relay.
  • Майбутня реалізація Firefox, можливо, використовуватиме щось на основі продукту Mozilla VPN.

[!NOTE] Оскільки правила спекуляції використовують елемент <script>, їх потрібно явно дозволити в директиві script-src Content-Security-Policy, якщо вона є на сайті. Це робиться шляхом додавання значення "inline-speculation-rules" вкупі з хешем або числом-одноразом джерела.

Приклади

Попереднє отримання та попередня візуалізація в одному наборі правил

Базові приклади, показані в розділі опису, містять окремі правила спекуляції, визначені для попереднього отримання та попередньої візуалізації. Можна визначати як перше, так і друге в одному наборі правил:

<script type="speculationrules">
  {
    "prefetch": [
      {
        "urls": ["next.html", "next2.html"],
        "requires": ["anonymous-client-ip-when-cross-origin"],
        "referrer_policy": "no-referrer"
      }
    ],
    "prerender": [
      {
        "where": { "selector_matches": ".product-link" },
        "eagerness": "eager"
      }
    ]
  }
</script>

[!NOTE] Цей уривок коду містить приклад правила списку ("urls") та правила документу ("where").

Кілька наборів правил

Також дозволено включати кілька наборів правил в один файл HTML:

<script type="speculationrules">
  {
    "prefetch": [
      {
        "urls": ["next.html", "next2.html"],
        "requires": ["anonymous-client-ip-when-cross-origin"],
        "referrer_policy": "no-referrer"
      }
    ]
  }
</script>
<script type="speculationrules">
  {
    "prerender": [
      {
        "where": { "selector_matches": ".product-link" },
        "eagerness": "eager"
      }
    ]
  }
</script>

І кілька правил в одному наборі результатів:

<script type="speculationrules">
{
  "prerender": [
    {
      "urls": ["one.html"]
    },
    {
      "urls": ["two.html"]
    }
  ]
}
</script>

Динамічне додання правил

Нижче – приклад, який з'ясовує факт підтримки правил спекуляції, і якщо вони підтримуються, то додає правило спекуляції попередньої візуалізації за допомогою JavaScript:

if (
  HTMLScriptElement.supports &&
  HTMLScriptElement.supports("speculationrules")
) {
  const specScript = document.createElement("script");
  specScript.type = "speculationrules";
  const specRules = {
    prerender: [
      {
        urls: ["/next.html"],
      },
    ],
  };
  specScript.textContent = JSON.stringify(specRules);
  console.log("додано правило спекуляції до: next.html");
  document.body.append(specScript);
}

Це можна побачити в дії на цій сторінці демонстрацій попередньої візуалізації.

Приклади синтаксису where

Правило від документа містить властивість "where", яка є об'єктом, що містить критерії, які визначають, яким посиланням у документі відповідає правило. Фактично, об'єкт "where" представляє перевірку, яка виконується щодо кожного посилання на сторінці, аби визначити, чи застосовувати до нього правило спекуляції.

Найбазовіша версія шукатиме збіг з одним патерном URL або селектором CSS:

{ "where": { "href_matches": "/next" } }
{ "where": { "selector_matches": ".important-link" } }

Властивостям "href_matches" і "selector_matches" також можна задати масив значень, щоб одночасно давали збіг кілька патернів URL або селекторів CSS:

{ "where": { "href_matches": ["/next", "/profile"] } }
{ "where": { "selector_matches": [".important-link", "#unique-link"] } }

Патерни URL і селектори також можуть вміщати символи джокера (*), який дає змогу одному значенню давати збіг з кількома URL. Наприклад, об'єкт нижче може дати збіг з user/, user/settings, user/stats і т.д..

{ "where": { "href_matches": "/user/*" } }

На параметри пошуку (чи рядки запиту) також можна націлюватися в href_matches. Наприклад, об'єкт нижче може давати збіг з усіма URL за тим самим походженням, що мають параметр пошуку category (як перший або подальший параметр):

{ "where": { "href_matches": "/*\\?*(^|&)category=*" } }

Будь-яку умову можна обернути, якщо поставити її всередину умови "not" – це означає, що коли така вкладена умова дає збіг, до посилання не буде застосовуватися правило спекуляції, а коли не дає – то буде. Наступний приклад призведе до того, що до всіх посилань, які не відповідають патерну URL /logout, буде застосовано правило, але не до посилань, що відповідають /logout:

{ "where": { "not": { "href_matches": "/logout" } } }

Поєднання кількох умов "where" за допомогою "and" або "or"

Кілька умов можна поєднати всередині умов "and" або "or" — такі умови приймають за значення масиви, що містять кілька умов, серед яких усі або будь-яка (відповідно) повинні давати збіг, щоб до посилання застосовувалися правила спекуляції. За допомогою "and" або "or" можна утворювати умови з багатьма рівнями вкладеності: немає обмежень щодо глибини вкладеності умов.

Доречно уявляти об'єкт "where" як такий, що рівносильний операції if. Тож

{ and: [A, B, { or: [C, { not: D }] }] }

рівносильно щодо

if (A && B && (C || !D)) {
  застосувати правило спекуляції
}

У наступному довершеному прикладі правила спекуляції всі сторінки з того самого походження позначаються для попереднього отримання, за винятком тих, які відомо, що є проблематичними — сторінка /logout та будь-які посилання, позначені класом .no-prerender:

<script type="speculationrules">
  {
    "prefetch": [
      {
        "where": {
          "and": [
            { "href_matches": "/*" },
            { "not": { "href_matches": "/logout" } },
            { "not": { "selector_matches": ".no-prerender" } }
          ]
        }
      }
    ]
  }
</script>

[!NOTE] Патерн where вище не включає міжсайтові посилання, які підтримуються для попереднього отримання (за умови що користувач не має заданих реп'яшків для цільового сайту, щоб захистити від відстеження), але не для попередньої візуалізації.

Приклад "relative_to"

Що до наборів правил, які отримані зовні (наприклад, за допомогою заголовка відповіді Speculation-Rules), URL у правилах списку та патернах URL у правилах документа усталено розбираються відносно URL зовнішнього текстового файлу, що їх вміщає. Щоб URL у правилі списку розбиралися відносно базового URL поточного документа, отак використовується "relative_to":

{
  "urls": ["/home", "/about"],
  "relative_to": "document"
}

Що до правил документа, то "relative_to" можна безпосередньо поєднати з "href_matches", і базовий URL документа буде використовуватися лише для патернів у цій конкретній умові:

{
  "where": {
    "or": [
      { "href_matches": "/home", "relative_to": "document" },
      { "href_matches": "/about" }
    ]
  }
}

У прикладі вище лише перший "href_matches" буде зіставлений відносно базового URL документа.

Властивість relative_to перш за все доцільна, якщо файл JSON правил спекуляції перебуває за іншим походженням відносно документа, до якого ці правила необхідно застосувати:

  1. Якщо документ розташований за адресою https://example.com/some/subpage.html, а правила — за адресою https://example.com/resources/rules.json, то /home завжди відповідає https://example.com/home, незалежно від того, чи задано relative_to як document, чи як ruleset.

  2. Проте якщо документ розташований за адресою https://example.com/some/subpage.html, а правила — за адресою https://other.example/resources/rules.json (наприклад, на сторонньому ресурсі чи ресурсі без реп'яшків), то:

    • "relative_to": "document" змусить /home відповідати https://example.com/home.
    • "relative_to": "ruleset" змусить /home відповідати https://other.example/home.

    Це типовий випадок використання "relative_to".

  3. Інший потенційний (хоч і рідкісніший) випадок використання трапляється, коли URL задані у вигляді home, а не /home. Якщо документ розташований за адресою https://example.com/some/subpage.html, а правила — за адресою https://example.com/resources/rules.json, то:

    • "relative_to": "document" змусить home відповідати https://example.com/some/home.
    • "relative_to": "ruleset" змусить home відповідати https://example.com/resources/home.

Уявімо випадок, коли є цільова сторінка зі списком користувачів, /users, до якої можна додати параметр id, щоб відобразити інформацію про конкретного користувача, наприклад, /users?id=345. Чи ці URL мають вважатися однаковими для потреб кешування, залежить від поведінки застосунку:

  1. Якщо цей параметр призводить до завантаження геть інакшої сторінки, що містить інформацію про вказаного користувача, то такий URL слід кешувати окремо.
  2. Якщо цей параметр виділяє заданого користувача на тій самій сторінці, і можливо, відкриває панель, що відображає його дані, то такий URL слід вважати тотожним для потреб кешування. Це може призвести до покращення продуктивності щодо завантаження сторінок користувачів і може бути досягнуто за допомогою No-Vary-Search зі значенням params=("id").

Як це стосується правил спекуляції? Для прикладу – наступний код:

<script type="speculationrules">
  {
    "prefetch": [
      {
        "urls": ["/users"]
      }
    ]
  }
</script>
<a href="/users?id=345">Користувач Василь</a>

Що сталось би в такому випадку, якби користувач почав перехід до /users?id=345, коли заголовки для попереднього отримання /users ще не були отримані? На такому етапі браузер не знає, яким буде значення No-Vary-Search, якщо воно взагалі буде. Якщо значення No-Vary-Search не задано, і поведінка застосунку більше схожа на варіант 1 вище, то попереднє отримання буде втрачено, і браузеру доведеться знову завантажувати окрему сторінку /users?id=345 з нуля.

Щоб це вирішити, можна надати підказку щодо того, яке значення No-Vary-Search автор сторінки очікує. Правило спекуляції може містити поле "expects_no_vary_search", що містить рядок, який представляє очікуване значення заголовка:

<script type="speculationrules">
  {
    "prefetch": [
      {
        "urls": ["/users"],
        "expects_no_vary_search": "params=(\"id\")"
      }
    ]
  }
</script>
<a href="/users?id=345">Користувач Василь</a>

Це вказує на те, що варіант 2, описаний вище, – саме те, що очікується від сервера. Якщо перехід починається, поки триває попереднє отримання /users, expects_no_vary_search повідомляє браузеру, що він повинен зачекати на попереднє отримання, а не негайно розпочинати ще одне отримання /users?id=345.

Правила документу також можна використовувати в поєднанні з "expects_no_vary_search", залежно від використаного патерну. Наприклад, у випадку:

<script type="speculationrules">
  {
    "prefetch": [
      {
        { "where": { "href_matches": "/users?id=*" } },
        "expects_no_vary_search": "params=(\"id\")"
      }
    ]
  }
</script>
<a href="/users?id=012">Користувач Володимир</a>
<a href="/users?id=345">Користувач Василь</a>
<a href="/users?id=678">Користувач Петро</a>

Якщо користувач наводить курсор на посилання, браузер починає попереднє отримання цього конкретного посилання.

Якщо користувач наводить ще на одне посилання, коли попереднє завантаження попереднього посилання ще не завершено, патерн expects_no_vary_search повідомляє браузеру, що немає потреби скасовувати поточне попереднє завантаження, оскільки всі URL /users з параметром URL id фактично вказують на ту саму сторінку для цього контексту (і для цілей кешування).

Приклад eagerness

Наступний набір правил документа показує, як eagerness можна скористатися, аби підказати браузеру, наскільки терміново він повинен попередньо візуалізувати кожний набір посилань, що дає збіг.

<script type="speculationrules">
  {
    "prerender": [
      {
        "where": { "href_matches": "/*" },
        "eagerness": "conservative"
      },
      {
        "where": { "selector_matches": ".product-link" },
        "eagerness": "eager"
      }
    ]
  }
</script>

Тут робиться підказка про те, що:

  • Всі посилання на той же сайт, що містяться в документі, повинні бути попередньо візуалізовані консервативним чином (тобто лише тоді, коли користувач починає активувати їх).
  • Будь-які посилання на продукти (у цьому випадку це ті посилання, що мають class .product-link) у документі повинні бути попередньо візуалізовані терміново (тобто якщо користувач робить будь-який крок у бік переходу за ними).

[!NOTE] Дія налаштувань терміновості має меншу корисність для правил списку. Усталено URL правил списку попередньо отримуються чи візуалізуються негайно, щойно правила розібрані, і це те, що очікується – такі правила призначені для явного перелічення високопріоритетних URL, які повинні бути доступними якомога швидше. Через це eager у нинішніх реалізаціях діє так само, як immediate. Налаштування нижчої терміновості призначені для попереднього отримання чи візуалізації при взаємодії з посиланнями, і для цього, ймовірно, ви скористаєтесь правилами документа для їх пошуку на сторінці.

Специфікації

Якщо ви це бачите — значить, щось трапилося з цією сторінкою.

Сумісність із браузерами

Якщо ви це бачите — значить, щось трапилося з цією сторінкою.

Дивіться також