1
2

サイトを埋め込み表示するGROWIプラグインの紹介

Posted at

オープンソースのWikiであるGROWIにはプラグイン機能が用意されています。自社のデータを表示したり、表示をカスタマイズするのに利用できます。

今回は、GROWIプラグインとして作ったWebサイト埋め込み表示プラグインを紹介します。非同期でデータを取得する際の注意点も合わせて紹介します。

FireShot Capture 545 - API Test - GROWI - localhost 545.jpg

コードについて

コードはgoofmint/growi-plugin-embed-site: GROWI Web site embed plugin
にあります。見るべきファイルとしては、以下の2つになります。

プラグインを追加する

利用する際には、GROWIの管理画面の プラグイン にて追加してください。URLは https://github.com/goofmint/growi-plugin-embed-site です。

FireShot Capture 359 - プラグイン - GROWI - localhost 359.jpg

使い方

利用する際には、Markdown記法のリンクを使います。その際にリンクのタイトルを OGP としてください。以下はその例です。

[OGP](https://example.com)

これでサイトの埋め込み表示になります。

実装について

プラグインの登録部分 client-entry.tsx のコードです。 optionsGenerators.customGenerateViewOptions の中でデフォルトの a タグの動作を変更しています。 EmbedOGP でラップすることで、動作を変更できます。

import { useEffect, useState } from 'react';

import config from './package.json';
import { EmbedOGP } from './src/EmbedOGP';
import { Options, Func, ViewOptions } from './types/utils';

declare const growiFacade : {
  markdownRenderer?: {
    optionsGenerators: {
      customGenerateViewOptions: (path: string, options: Options, toc: Func) => ViewOptions,
      generateViewOptions: (path: string, options: Options, toc: Func) => ViewOptions,
    },
  },
};

const activate = (): void => {
  if (growiFacade == null || growiFacade.markdownRenderer == null) {
    return;
  }
  const { optionsGenerators } = growiFacade.markdownRenderer;
  optionsGenerators.customGenerateViewOptions = (...args) => {
    const options = optionsGenerators.generateViewOptions(...args);
    const A = options.components.a;
    // replace
    options.components.a = EmbedOGP(A);
    return options;
  };
};

const deactivate = (): void => {
};

// register activate
if ((window as any).pluginActivators == null) {
  (window as any).pluginActivators = {};
}
(window as any).pluginActivators[config.name] = {
  activate,
  deactivate,
};

OGPの取得・表示

今回のプラグインでの肝になるのが、データの非同期での取得になります。GROWI全体がReactで構築されているため、単純に useEffectuseState は利用できません。その解決策として利用するのが react-async です。

import Async from 'react-async';

このコンポーネントで全体を囲みます。そして、利用時には promiseFn にて非同期関数、そして関数に渡す引数を指定します。戻り値で data にデータ、 error にエラー、 isPending にローディング状態が入ります。

return (
	<Async promiseFn={getOGP} href={href}>
		{({ data, error, isPending }) => {
			if (isPending) return 'Loading...';
			if (error) return `Something went wrong: ${error.message}`;
			if (data) {
				return (
					<div className='row ogp'>
						<div className='col-3'>
							<a href={href} target='_blank' rel='noopener noreferrer'>
								<img
									src={data.ogp['og:image'] || PLACEHOLDER_IMAGE}
									alt={data.html.title}
								/>
							</a>
						</div>
						<div className='col-9'>
							<a href={href} target='_blank' rel='noopener noreferrer'>
								<strong>{data.html.title}</strong>
							</a>
							<p>
								{ data.html.description || data.ogp['og:description'].join('') }
							</p>
							{ data.ogp['og:site_name'] && (
								<div
									style={{
										color: '#777',
									}}
								>
									{data.ogp['og:site_name']}
								</div>
							)}
						</div>
					</div>
				);
			}
			return null;
		}}
	</Async>
);

非同期関数は以下のように定義します。今回はウェブサイトのOGP情報を取得できるAPIをリリースしました! | たくろぐ。をお借りしています。同様の仕組みとして ogp-parser をExpressから利用する方法もあります。デフォルトの画像はplacehold.jp | ダミー画像生成 モック用画像作成を利用しています。

const OGP_API = 'https://ogp-scanner.kunon.jp/v1/ogp_info';
const PLACEHOLDER_IMAGE = 'https://placehold.jp/24/5C9A29/ffffff/480x360.png';

const getOGP = async({ href }: any) => {
  const res = await fetch(`${OGP_API}?url=${encodeURIComponent(href)}`);
  const json = await res.json();
  return json;
};

注意点

ウェブサイトのOGP情報を取得できるAPIをリリースしました! | たくろぐ。にある禁止事項を守った上でご利用ください。

まとめ

GROWIプラグインを使うと、表示を自由に拡張できます。足りない機能があれば、どんどん追加できます。ぜひ、自分のWikiをカスタマイズしましょう。

OSS開発wikiツールのGROWI | 快適な情報共有を、全ての人へ

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2