feat: Configurable normalizeHref

オープン
#4,584 コメント 2 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
35/100
issue の種類
機能追加
明瞭さ
おおむね明確
活発さ
停滞
技術スタック
typescript
領域
build-system

調査の方向性

まず crawlAnchorsForNextUrls と standardNormalizeHref を見つけ、次に prerenderConfig のオプションがどのように定義され、使用されているかを調べます。設定可能な normalizeHref hook が既存の末尾スラッシュの動作とどのように連携すべきかを確認し、設定した動作が適用される一方でデフォルトの動作は変更されないことを示すテストを追加します。

索引モデルが issue の本文から書いたものです。

説明

Feature: Want this? Upvote it!
Prerequisites
Describe the Feature Request

In order to prerender pages it would be great to configure the behaviour of normalizing the href.

Describe the Use Case

I have hrefs with and without trailing slash. The only thing which can be configured is using trailing slash or not. If setting trailing slash to true all href will have a trailing slash in the end, if set to false all href won`t have a trailing slash. I would suggest to add the possibility make this configurable. Either by adding a the possibility to do something like trailingSlash: 'source' in the config or by adding the possibility to overwrite the standardNormalizeHref function.

Describe Preferred Solution

option number 1

const standardNormalizeHref = (prerenderConfig, diagnostics, url) => {
  try {
    if (url != null && typeof url.href === 'string') {
      let href = url.href.trim();
      if (prerenderConfig.trailingSlash === true) {
        // url should have a trailing slash
        if (!href.endsWith('/')) {
          const parts = url.pathname.split('/');
          const lastPart = parts[parts.length - 1];
          if (!lastPart.includes('.')) {
            // does not end with a slash and last part does not have a dot
            href += '/';
          }
        }
      }
      else if (prerenderConfig.trailingSlash === false ){
        // url should NOT have a trailing slash
        if (href.endsWith('/') && url.pathname !== '/') {
          // this has a trailing slash and it's not the root path
          href = href.slice(0, -1);
        }
      }
      return href;
    }
  }
  catch (e) {
    catchError(diagnostics, e);
  }
  return null;
};

option number 2

const crawlAnchorsForNextUrls = (prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors) => {
  if (!Array.isArray(parsedAnchors) || parsedAnchors.length === 0) {
    return [];
  }
  const basePathParts = baseUrl.pathname.split('/');
  // filterAnchor(): filter which anchors to actually crawl
  // normalizeUrl(): normalize href strings into URL objects
  // filterUrl(): filter which urls to actually crawl
  // normalizeHref(): normalize URL objects into href strings
  return parsedAnchors
    .filter((anchor) => {
    // filter which anchors to actually crawl
    if (typeof prerenderConfig.filterAnchor === 'function') {
      // user filterAnchor()
      try {
        const userFilterAnchor = prerenderConfig.filterAnchor(anchor, currentUrl);
        if (userFilterAnchor === false) {
          return false;
        }
      }
      catch (e) {
        // user filterAnchor() error
        catchError(diagnostics, e);
        return false;
      }
    }
    // standard filterAnchor()
    return standardFilterAnchor(diagnostics, anchor);
  })
    .map((anchor) => {
    // normalize href strings into URL objects
    if (typeof prerenderConfig.normalizeUrl === 'function') {
      try {
        // user normalizeUrl()
        const userNormalizedUrl = prerenderConfig.normalizeUrl(anchor.href, currentUrl);
        // standard normalizeUrl(), after user normalized
        return standardNormalizeUrl(diagnostics, userNormalizedUrl.href, currentUrl);
      }
      catch (e) {
        // user normalizeUrl() error
        catchError(diagnostics, e);
      }
    }
    // standard normalizeUrl(), no user normalized
    return standardNormalizeUrl(diagnostics, anchor.href, currentUrl);
  })
    .filter((url) => {
    // filter which urls to actually crawl
    if (typeof prerenderConfig.filterUrl === 'function') {
      // user filterUrl()
      try {
        const userFilterUrl = prerenderConfig.filterUrl(url, currentUrl);
        if (userFilterUrl === false) {
          return false;
        }
      }
      catch (e) {
        // user filterUrl() error
        catchError(diagnostics, e);
        return false;
      }
    }
    // standard filterUrl()
    return standardFilterUrl(diagnostics, url, currentUrl, basePathParts);
  })
    .map((url) => {
    

if (typeof prerenderConfig.normalizeHref === 'function') {
      try {
        // user normalizeHref()
        return  prerenderConfig.normalizeHref(prerenderConfig, diagnostics, url);
      }
      catch (e) {
        // user normalizeUrl() error
        catchError(diagnostics, e);
      }
    }
// standard normalize href
    // normalize URL objects into href strings
    return standardNormalizeHref(prerenderConfig, diagnostics, url);
  })
    .reduce((hrefs, href) => {
    // remove any duplicate hrefs from the array
    if (!hrefs.includes(href)) {
      hrefs.push(href);
    }
    return hrefs;
  }, [])
    .sort((a, b) => {
    // sort the hrefs so the urls with the least amount
    // of directories are first, then by alphabetical
    const partsA = a.split('/').length;
    const partsB = b.split('/').length;
    if (partsA < partsB)
      return -1;
    if (partsA > partsB)
      return 1;
    if (a < b)
      return -1;
    if (a > b)
      return 1;
    return 0;
  });
};
Describe Alternatives

No response

Related Code

No response

Additional Information

No response

主要言語
TypeScript
スター
13.2k
フォーク
865
平均マージ
2日 16時間
マージ済み PR(30日)
29

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

stenciljs/core のほかの issue

stenciljs/core の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。