11 tyブログにおけるウェブメンテーションの実装


私たちはwhat are Webmentionsに導入しました、これを使用して、このブログでそれらを実装しましょう.

Note: I used Max Böck's article and his code to implement them on my blog.


次のようになります.

ステップ1。ウェブ言及のサインアップio


Aaron Pareckiは、この素晴らしい無料ツールwebmention.ioと呼ばれました.これは、Webを受信するホストのソリューションです.
サインアップはindie-authを使用していますので、以下のように我々のウェブサイトにリンクしなければなりません.
<a href="https://twitter.com/DailyDevTips1" rel="me">Twitter</a>
あなたのウェブサイトのドメインをTwitterのプロファイルに含まれていることを確認します.

手順2。ウェブリンクコレクションの追加


一度、我々は我々のドメインに我々の2つの関連を加える必要があります
<link rel="webmention" href="https://webmention.io/{username}/webmention" />
<link rel="pingback" href="https://webmention.io/{username}/xmlrpc" />
{username}などの実際のドメインに置き換えます.

ステップ3。接続としてつぶやきを接続する


それで、今、我々はウェブ言及を受けることができます、しかし、すべての正直で、WHOはWebReferenceを我々に送りますか?
人々のウェブサイトに私たちのURLをつぶやき変換しましょう!
我々は、bridgyのようなホストサービスを使用することができます.
ちょうどTwitterのアイコンをクリックしてログインします.
その後、あなたのウェブサイトや世論調査のTwitterをクロールすることができます.

Bridgy only gets the most recent Tweets, but you can add a Tweet URL in the Resend for the post button.


実際のウェブサイトでの応答は以下のようになります.

ステップ4。すべてのウェブページを取得する関数


すべての設定を持っているので、WebReadingのためのすべてのウェブメンテーションズを集めます.入出力API.
では、カスタムデータファイルをdaily-dev-tips.comフォルダに追加できます.
それを_dataと呼びましょう
const fs = require('fs');
const fetch = require('node-fetch');
const unionBy = require('lodash/unionBy');
const domain = 'daily-dev-tips.com';

// Load .env variables with dotenv
require('dotenv').config();

// Define Cache Location and API Endpoint
const CACHE_DIR = '_cache';
const API = 'https://webmention.io/api';
const TOKEN = process.env.WEBMENTION_IO_TOKEN;

async function fetchWebmentions(since, perPage = 10000) {
    if (!domain) {
        // If we dont have a domain name, abort
        console.warn('>>> unable to fetch webmentions: no domain name specified in site.json');
        return false;
    }

    if (!TOKEN) {
        // If we dont have a domain access token, abort
        console.warn('>>> unable to fetch webmentions: no access token specified in environment.');
        return false;
    }

    let url = `${API}/mentions.jf2?domain=${domain}&token=${TOKEN}&per-page=${perPage}`;
    if (since) url += `&since=${since}`;

    const response = await fetch(url);
    if (response.ok) {
        const feed = await response.json();
        console.log(`>>> ${feed.children.length} new webmentions fetched from ${API}`);
        return feed;
    }

    return null;
}

// Merge fresh webmentions with cached entries, unique per id
function mergeWebmentions(a, b) {
    return unionBy(a.children, b.children, 'wm-id');
}

// save combined webmentions in cache file
function writeToCache(data) {
    const filePath = `${CACHE_DIR}/webmentions.json`;
    const fileContent = JSON.stringify(data, null, 2);
    // create cache folder if it doesnt exist already
    if (!fs.existsSync(CACHE_DIR)) {
        fs.mkdirSync(CACHE_DIR);
    }
    // write data to cache json file
    fs.writeFile(filePath, fileContent, err => {
        if (err) throw err;
        console.log(`>>> webmentions cached to ${filePath}`);
    })
}

// get cache contents from json file
function readFromCache() {
    const filePath = `${CACHE_DIR}/webmentions.json`;

    if (fs.existsSync(filePath)) {
        const cacheFile = fs.readFileSync(filePath);
        const cachedWebmentions = JSON.parse(cacheFile);

        // merge cache with wms for legacy domain
        return {
            lastFetched: cachedWebmentions.lastFetched,
            children: cachedWebmentions.children
        };
    }

    // no cache found.
    return {
        lastFetched: null,
        children: {}
    };
}

module.exports = async function () {
    const cache = readFromCache();

    if (cache.children.length) {
        console.log(`>>> ${cache.children.length} webmentions loaded from cache`);
    }

    // Only fetch new mentions in production
    if (process.env.NODE_ENV === 'production') {
        const feed = await fetchWebmentions(cache.lastFetched);
        if (feed) {
            const webmentions = {
                lastFetched: new Date().toISOString(),
                children: mergeWebmentions(cache, feed)
            }
            writeToCache(webmentions);
            return webmentions;
        }
    }
    return cache;
}
大規模なファイルですが、基本的には、エンドポイント用のWebを読みます.
https://webmention.io/api/mentions.jf2?domain=${domain}&token=${TOKEN}
その後、キャッシュファイルでマージします.
この関数は、私たちの11回目のブログを構築したら実行されます.

To make it realtime, we can leverage other endpoints, but I won't go into that. Find more on Shawn's blog


このデータファイルを作成することで、webmentions.jsという変数にアクセスできます.

ステップ5。ブログの表示の表示


前述のように、我々は現在{{ webmentions }}変数を持ちます.
そして、私の場合は、次の要素をウェブサイトから分割します.
  • は、
  • が好きです
  • リポスト/retweets
  • は、
  • に言及して、答えます
    ブログページのレイアウトで次のように追加します.
    // layouts/post.njk
    {% include "partials/components/webmentions.njk" %}
    
    このwebファイルでは、すべての言及をロードします.
    まず、現在のページの完全なURLを取得する必要があります.
    {% set currentUrl %}{{ site.url + page.url | uniUrlFilter }}{% endset %}
    
    私はUniurlFilterを作成しました、私は私のURLの
    module.exports = function uniUrlFilter(value) {
        return encodeURI(value);
    };
    
    次に、この特定のURLのWebページを取得する必要があります.
    {%- set mentions = webmentions.children | getWebmentionsForUrl(currentUrl) -%}
    
    そして、このフィルタはそれらをきちんとした配列にソートします.
    const sanitizeHTML = require('sanitize-html');
    
    module.exports = function getWebmentionsForUrl(webmentions, url) {
        const likes = ['like-of'];
        const retweet = ['repost-of'];
        const messages = ['mention-of', 'in-reply-to'];
    
        const hasRequiredFields = entry => {
            const { author, published, content } = entry;
            return author.name && published && content;
        };
        const sanitize = entry => {
            const { content } = entry;
            if (content['content-type'] === 'text/html') {
                content.value = sanitizeHTML(content.value);
            }
            return entry;
        };
    
        return {
            'likes': webmentions
                .filter(entry => entry['wm-target'] === url)
                .filter(entry => likes.includes(entry['wm-property'])),
            'retweet': webmentions
                .filter(entry => entry['wm-target'] === url)
                .filter(entry => retweet.includes(entry['wm-property']))
                .filter(hasRequiredFields)
                .map(sanitize),
            'messages': webmentions
                .filter(entry => entry['wm-target'] === url)
                .filter(entry => messages.includes(entry['wm-property']))
                .filter(hasRequiredFields)
                .map(sanitize)
        };
    }
    
    見ることができるように、私はピースごとにソートするWebCountriesの3つの異なる要素をフィルタリングします.
    我々は、それから部分的に我々の{{ webmentions }}部分で彼らをループさせることができます.
    <ol>
    {% for webmention in mentions.likes %}
        <li class="webmentions__item">
            <a {% if webmention.url %}href="{{ webmention.url }}"{% endif %} target="_blank" rel="noopener noreferrer" title="{{ webmention.author.name }}">
                {% if webmention.author.photo %}
                    <img src="{{ webmention.author.photo }}" alt="{{ webmention.author.name }}" width="48" height="48" loading="lazy">
                {% else %}
                    <img src="{{ '/assets/images/avatar-default.jpg' | url }}" alt="" width="48" height="48">
                {% endif %}
            </a>
        </li>
    {% endfor %}
    </ol>
    
    <ol>
    {% for webmention in mentions.retweets %}
        <li class="webmentions__item">
            <a {% if webmention.url %}href="{{ webmention.url }}"{% endif %} target="_blank" rel="noopener noreferrer" title="{{ webmention.author.name }}">
                {% if webmention.author.photo %}
                    <img src="{{ webmention.author.photo }}" alt="{{ webmention.author.name }}" width="48" height="48" loading="lazy">
                {% else %}
                    <img src="{{ '/assets/images/avatar-default.jpg' | url }}" alt="" width="48" height="48">
                {% endif %}
            </a>
        </li>
    {% endfor %}
    </ol>
    
    <ol>
    {% for webmention in mentions.messages %}
        <li class="webmentions__item">
            <a {% if webmention.url %}href="{{ webmention.url }}"{% endif %} target="_blank" rel="noopener noreferrer" title="{{ webmention.author.name }}">
                {% if webmention.author.photo %}
                    <img src="{{ webmention.author.photo }}" alt="{{ webmention.author.name }}" width="48" height="48" loading="lazy">
                {% else %}
                    <img src="{{ '/assets/images/avatar-default.jpg' | url }}" alt="" width="48" height="48">
                {% endif %}
            </a>
            <strong>{{ webmention.author.name }}</strong>
            <time class="dt-published" datetime="{{ webmention.published | w3DateFilter }}">
                {{ webmention.published | dateFilter }}
            </time>
            {{ webmention.content.html | safe }}
        </li>
    {% endfor %}
    </ol>
    
    彼らは私たちは、ちょうどいくつかのスタイリングを追加し、あなたのEustenmentブログのショーケースのウェブサイトにあなたの準備ができています.

    読んでいただきありがとうございます、接続しましょう!


    私のブログを読んでくれてありがとう.私の電子メール会報を購読して、Facebook