react-static-plugin-markdownの使い方

react-staticに関して
react-staticに関して

react-static-plugin-markdownを使ってみようとしてつまづいたのでメモとして。

[追記:2019.8.1]
react-static-plugin-mdxというマークダウン用プラグイン(中身はmdx-js)がreact-Staticから出ましたので、react-static-plugin-markdownは不要かもしれません。
react-static-plugin-markdownはあまり更新されていないようなので…。

react-static-plugin-markdown

このプラグインは2019年1月にリリースされた非常に新しいプラグインです。それを踏まえての印象は以下の通り。

  • 導入や設定やページの追加は非常に簡単
  • マークダウンと通常のJSファイルの併用が可能
  • 現状では機能が不足(マークダウン記法の全てが使えるわけではないなど)

導入

基本的にはGitLabのページに書いている通りなのですが、その通りが実際どうなのか悩む部分があったので以下に記載します。

1:ContentPageフォルダとファイルの作成

// src/containers/ContentPage
import React from 'react'
import { withRouteData } from 'react-static';
import { ContentPage } from 'react-static-plugin-markdown';

export default withRouteData(ContentPage);

上記のコードのコメントにあるsrc/containers/ContentPageのパスの構成どうりにフォルダを作成。
ContentPageの中にindex.jsを作成し、上記のコードをそのまま記述する。

2:static.config.jsに記述を追加

export default {
  plugins: [
    [
      'react-static-plugin-markdown',
      { renderComponent: 'src/containers/ContentPage' },
    ],
  ]
};

static.config.jsに上記のコードを追加。場所は特に気にする必要はないが、入れ子の状態はちゃんと確認してgetRoutesなどと同じ階層に書く。

3:Contentフォルダを作ってマークダウンファイルを入れる

Finally, write your Markdown files in the /content directory. For example, /content/some-page.md will be visible on your website at the path /some-page/.

上記に書かれているとおり、最後はcontentフォルダを作ってそこにマークダウンファイル(.md)を入れる。
contentフォルダの場所はsrcの中ではなくstatic.config.jssrcフォルダと同階層。

正常に完了した場合

正常に準備を終えられれば、以下のような感じでマークダウンファイルがそのままページのアドレスとして書き出される。

  • example.com/some-page (contentフォルダ内にsome-page.mdを設置した場合)
  • example.com/sub/some-page(contentフォルダ内にsubフォルダを作ってsome-page.mdを設置した場合)

メモ

ページの追加
  • マークダウンファイルはcontentに入れる
  • JSファイルはPageフォルダに入れる(react Staticのbasicテンプレートの通常の形)

なおマークダウンファイルを追加してページを増やす場合、buildした時に初めて認識されて構築反映される模様。
そのため$ npm run startでサーバーを立てた状態でマークダウンファイルの追加や変更を行っても反映されない。

マークダウンで画像を挿入
  • publicフォルダに画像ファイルを入れる

Reactで画像を入れるにはimportで記述するが、マークダウンファイル内にコンポーネントは記載できないのでこの方法を検討。

またはマークダウンファイルの中身を取得し、正規表現で画像のパスを取得し、動的にimportできるようにする方法も考えられる(試していないので未確認)。

マークダウン内の内部リンク

export default {
  siteRoot: 'https://example.com',
  stagingSiteRoot: 'http://localhost:3000',
  //省略
}

static.config.jssiteRoot(本番用)とstagingSiteRoot(開発用)のパスを設定しておけば、絶対パスからドメインを取り除いた書き方でOK。


1:https://example.com/example-pageへのリンクの場合
[内部リンク1](/example-page/)

2:https://example.com/example/example-page2へのリンクの場合
[内部リンク2](/example/example-page2/)

相対パスでもリンクは繋がるが、React Static側が対応していないのでコンソールにエラーがでる(おそらくprefetch絡み)。

引用の中に段落(複数のpタグ)を入れる

> テキスト
>
> テキスト

上記のように空行を挟むことで、引用タグ内に段落を作ることができる。空行には>はあってもなくても問題なく、空行さえあればいい。

コンテンツなどへのアクセス

export default withRouteData((props) => (
  {console.log(props.markdown)}
  {console.log(props.markdown.title)}
  {console.log(props.markdown.content)}
));

独自に設定したものも同様で、props.markdowntitlecontentを繋げて値を取得可能。全てを確認したい場合はprops.markdownconsole.logで表示させる。

マークダウンのファイル名で分岐

関連記事などをマークダウン外に書く場合、content.index.jsの方に記述する必要がある。例えば以下のようにすれば動く。


const RelatedLink = withRouteData((props) => {
  let name = props.markdown.filename;
  switch (name){
    case "example.md":
      return(
        <ul>
          <li><Link to="/example2">関連記事用リンク</Link></li>
        </ul>
      )
      break;
    case "example2.md":
      return(
        <ul>
          <li><Link to="/example3">関連記事用リンク</Link></li>
        </ul>
      )
      break;
    default:
      return(
        <ul>
          <li><Link to="/example4">関連記事用リンク<</Link></li>
        </ul>
      )
      break;
  }
})

export default () => (
  <RouteData>
    {(props) => (
      <article>
        <ContentPage {...props} />
        <RelatedLink />
      </article>
    )}
  </RouteData>
);
titleタグの設定

上記のページのコードをベースに以下のようにすれば、マークダウン内に設定されたtitleの値を取得してtitleタグに反映可能。


import React from 'react'
import { withRouteData, Head } from 'react-static'
import { ContentPage } from 'react-static-plugin-markdown'

export default withRouteData((props) => (
  <article>
    <Head>
      <title>{props.markdown.data.title}</title>
    </Head>
    <h1>{props.markdown.filename}</h1>
    <ContentPage {...props}/>
  </article>
));

titleタグに対して「ページタイトル – サイトタイトル」のようにする場合はいかのようにすれば実現可能。


import React from 'react'
import { RouteData, Head, SiteData } from 'react-static'
import { ContentPage } from 'react-static-plugin-markdown'

export default (props) => (
  <SiteData>
    {({title}) => (
    <RouteData>
      {(props) => (
        <article>
          <Head>
          <title>{props.markdown.data.title} - {title}</title>
          </Head>
          <h1>{props.markdown.data.title}</h1>
          <ContentPage {...props}/>
        </article>
      )}
    </RouteData>
    )}
  </SiteData>
);

問題点

index.mdではTOPページが対応できない

TOPページとして表示させるためにindex.mdを作った場合、下記のアドレスであればアクセスし表示可能。

  • example.com/index

内部リンクの指定で/indexのようにすればこの状態でも良いかもしれないが、システム的にTOPページとは認識されていないことに変わりはないのであまり良い手には思えず。
そこで検討したのが以下の方法。

  • TOPページはマークダウンファイルは使わず、Pageフォルダにindex.jsを入れる通常の方法で構築する

react-static-plugin-markdownはマークダウンとjsの併用が可能(同名が存在した場合はおそらくjsが優先)な模様で、確認した範囲では不具合はなし。

逆にindex.jsがないとディレクトリにアクセスした時にexample.com/example/routeInfo.json 500のようなエラーがコンソールに出る(おそらくprefetch絡み)。

以上のことから、index.mdを使った場合でもページの表示自体に問題はないようだが、内部的にはやはりindex.jsがない時点で仕組み上問題ある模様。

この問題は公式が用意している設定で解決できそうな気はするが、その情報が見つけられず。今後のアップデートに期待。

マークダウン内でInlineHTML(通常のHTMLタグ)が使えない
プラグインの中身はreact-markdownのようなのでプラグイン内に記述を追加すれば可能に思えるが、現状では不可の模様。この部分は今後のアップデートでの対応を期待。
目次の自動生成ができない
少なくとも公式では用意されていない。InlineHTMLが使えない状況なので、マークダウンの変換タイミング次第では難しいかもしれない。
自動ではないがマークダウンファイル内のtitleと同様にしてアンカーを設定すればいけるとは思う。手動なので手間はかかるが。

結び

概ねうまくいきました。
一部にまだ問題はありますが設定が簡易で使いやすいプラグインに思えます。
react-markdownなどを使う方法もありますがそれらは設定が結構ややこしいようで、こういった比較の点でも手が出しやすいかもしれません。

とはいえなにぶん新しすぎるプラグインなので、今後のアップデートを期待したいと思います。

0人がこの記事を評価

役に立ったよという方は上の「記事を評価する」ボタンをクリックしてもらえると嬉しいです。

連投防止のためにCookie使用。SNSへの投稿など他サービスとの連動は一切ありません。

コメント欄