Resct-Static V7 (マークダウン使用): メモ

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

以前試したバージョンがおそらくV6で、しばらく放置していたのをV7にあげたら新機能があったりエラーが出たりしたのでメモとして。

後ほど整えるかもしれませんが、とりあえず個人的メモの意図で適当に書いています。

前提

  • React-Staticの最新バージョンを入れ直す(この記事の書き始めでは7.1.0)
  • react-static creatで作った直後の状態から始める

以前の記事は以下より。

手順

  • グローバルにインストールしたReact-Staticを最新にアップデート
  • react-static createbasicを選んでプロジェクト作成
  • マークダウンを使えるようにするためにreact-static-plugin-mdxをインストール

V6からの違いなのかわかりませんが、2019.3ごろにReact-Static側でマークダウン用プラグインのreact-static-plugin-mdxが開発されていました。

この件に関しては以下のページに分けていますのでそちらで。

basicテンプレートを選ぶ理由

basicテンプレートであれば、最初からpagesフォルダに入れたJSファイルを出力するプラグインなどが同梱し設定されているためです。

  • react-static-plugin-source-filesystem
  • react-static-plugin-reach-router
  • react-static-plugin-sitemap

blankテンプレートでもこれらを入れることで実現できますが、他にも設定が必要になるようです。

各プラグインの詳細は以下で確認できます。

参考情報

発生したエラーなど

withSiteDatawithRouteDatauseSiteDatauseRouteDataへ必要に応じて変更

If you are unable to use a hook in your component, you may also use the RouteData component or withRouteData HOC to access routeData, though we suggest refactoring to hooks for future releases.

上記の部分が該当箇所の説明です。
使い方はreact-static/api.md at master · react-static/react-static · GitHubを参照。


import { useSiteData } from 'react-static'
export default () => {
  const { title } = useSiteData()
  return (
    <p>{title}</p>
  )
}
Suspense fallbackを追加しないとエラーになる

An internal error occured!
Error: 〇〇 suspended while rendering, but no fallback UI was specified.
Add a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.

上記エラーが出ます。

  1. react-static/api.md
  2. React Top-Level API – React

上記1に下記記述があり、hereで示されているのが2のページ。useSiteDataだけではなくuseRouteDataの方でも触れられています。

Note: Make sure to wrap components using useSiteData() with React’s <Suspense fallback=”…”></Suspense>. More information on the subject is available here.

例えば、子コンポーネント内でuseRouteDataを使った場合、呼び出す側の親コンポーネントで子コンポーネントを<React.Suspense fallback=…>で囲む必要があります。

最初から用意されているテンプレートで実際の状態を参照したい場合は、basicテンプレートのApp.jsを見ると、以下の記述が確認できます(下記は一部省略)。


function App() {
  return (
    <Root>
      <div className="content">
        <React.Suspense fallback={<em>Loading...</em>}>
          <Router>
            <Routes path="*" />
          </Router>
        </React.Suspense>
      </div>
    </Root>
  )
}

<Router>の子要素にはpathdefaultの追加が必須になっており、ないと以下のエラーがでます。


An internal error occured!
Invariant Violation: <Router>: Children of <Router> must have a `path` or `default` prop, or be a `<Redirect>`. 
ページ遷移後にスクロール位置が残る(ページ最上部に戻らない)

V7にすると、例えばページ中頃までスクロールした状態で別ページに移動した場合、画面が表示された時にページの最上部ではなく移動前のスクロール位置のままになってしまいます。

React RouterのScroll to topや、React-StaticのAnimated Routesも動きませんでした。

サポートフォーラムの上記でこの件が話されており、最下部にあるEvgeny Timoshenko氏の以下のコードを試し、求める動作になることを確認しました。


import React, { useEffect } from 'react';
import { Root, Routes } from 'react-static';
import { Router, Match } from '@reach/router';
const ScrollRestoration = () => {
  useEffect(() => {
    window.scrollTo(0, 0);
  });
  return null;
};
const App = () => {
  return (
    <Root>
      <React.Suspense fallback={<em>Loading...</em>}>
        <Match path="">{props => <ScrollRestoration {...props} />}</Match>
        <Router>
          <Routes path="*" />
        </Router>
      </React.Suspense>
    </Root>
  );
};
export default App;

今後のアップデートで治るのか別の仕組みが用意されるのか不明ですが、V7.1.0でもそのままなのでV8までこのままなのかもしれません。

おそらく普通は出ないエラー

以降に記載するエラーは、react-static createで作成したプロジェクト内のreact-staticのバージョンが6であったために発生する模様です。

以下の内容は正常にV7が入れば出ない、と思います。

core-jsのエラー

WARNING: We noticed you’re using the `useBuiltIns` option without declaring a core-js version. Currently, we assume version 2.x when no version is passed. Since this default version will likely change in future versions of Babel, we recommend explicitly setting the core-js version you are using via the `corejs` option.

You should also be sure that the version you pass to the `corejs` option matches the version specified in your `package.json`’s `dependencies` section. If it doesn’t, you need to run one of the following commands:

npm install –save core-js@2 npm install –save core-js@3
yarn add core-js@2 yarn add core-js@3

  • node_modules/react-static/babel-preset.js

上記内の記述に一行追加("corejs": 3)すればV6でもエラーを消すことはできました。


//以上省略
 presets: [
      !external
        ? [
            r('@babel/preset-env'),
            {
              targets: {
                browsers: PRODUCTION
                  ? ['last 4 versions', 'safari >= 7', 'ie >= 9']
                  : ['last 2 versions', 'not ie <= 11', 'not android 4.4.3'],
              },
              useBuiltIns: 'entry',
               "corejs": 3, // <--これを追加
              modules,
            },
//以下省略
  • node_modules/optimize-css-assets-webpack-plugin/.babelrc

上記にもuseBuiltInsの記述がありますが、こちらには追加しなくてもエラーは出ませんでした。

Autoprefixerのbrowsersオプオプション指定

Replace Autoprefixer browsers option to Browserslist config.
Use browserslist key in package.json or .browserslistrc file.

Using browsers option cause some error. Browserslist config
can be used for Babel, Autoprefixer, postcss-normalize and other tools.

If you really need to use option, rename it to overrideBrowserslist.

Learn more at:
https://github.com/browserslist/browserslist#readme
https://twitter.com/browserslist

怪しいところを消して試してみましたが消えず、該当の場所がわからずでV6では解決できず。

上記のようにありますが、すでに書いた通りV7にすれば解決します。

未解決の問題

構築方法や記述方法が悪いのか、作成したreact-staticのサイトではいくつか問題が残っています。

背景画像

distフォルダにビルドする際に、styled-componentsを用いて背景画像を指定しているとbase64に変換されるのですが、メインビジュアル用の画像がBade64に変換されず、同じ位置に書いたCSS記述も丸ごと消えました。

上記にあるlimit:10000が原因ではと思いますが、上限越えで変換されない場合は/static/bg.d3d4ab.pngのパスのままになり、おそらくこれが原因でbackground-imageを他の記述も丸ごと消えてしまうのではと思います。

ここで書かれているように設定でbase64に変換しないようにできるなら、回避策として成り立つかもしれません。

またはnode.api.jsを作ってlimitを書き換えるか(どう書けば良いのかまだ把握できていませんが)、以下方法でパスを指定して逃げるのが良いのかもしれません。

回避策

やむを得ないので、以前も参考にさせていただいた上記サイトの以下の記述を利用して、base64ではなく参照する形にしました。

process.env.PUBLIC_URL は、パブリックフォルダへのURLを持っています。これを接頭辞としてパスを指定します。

インライン画像(imgタグ)

背景画像ではなくimgタグによるインラインでも同様にBade64変換されない画像がある場合、ローカルでは表示されるもののbuildすると以下のような状態になります。

  • ブラウザで閲覧すると画像は表示される
  • 開発者ツールでは画像に対して500エラーが表示される
  • 500エラーの画像のパスは、本来の場所からルート直下に変更されている

Base64に変換されずにおかしくなるのを防ぐためにpublicディレクトリに入れていた場合、画像自体はstaticディレクトリに出力されているのですが、パスがルート直下に書き換えられているため、画像が存在せずエラーになってしまったようです。

前項ではできていた処理ができてないようです。

回避策

ちゃんとした解決策ではなくかなりだめな方法ですが、以下の作業で500エラーを消すことはできます。

  • エラーとして表示されている場所に、エラーとして表示されている名称にリネームした画像をアップする

他方、以下のURLにコードで解決可能という感じですが、実際に試したところ第3階層のページ(example.com/stage2/stage3stage3が該当)が404になってしまい利用できませんでした。


export default () => ({
  webpack: (webpackConfig, state) => {
    webpackConfig.module.rules = [{
    oneOf: [
        state.defaultLoaders.jsLoader,
        state.defaultLoaders.jsLoaderExt,
        state.defaultLoaders.cssLoader,
        {
          loader: 'url-loader',
          test: /\.(jpg|png)$/,
          query: {
            limit: 100,
            name: 'static/[name].[hash:8].[ext]',
          },
        },
        state.defaultLoaders.fileLoader,
      ]
    }]

    return webpackConfig
  }
})

上記はstatic.config.jsと同じ階層にnode.api.jsという名称でファイルを作成し、そこに記載する形です。

jpgpngの拡張子を持つファイルのURLがstaticディレクトリに入るように調整する内容なのでページの表示には関係ないはずですが、解決策も見つけられていません。

結び

しばらくぶりなので忘れている部分が多いのも理由ですが、初期状態での表示にも時間がかかりました。

1人がこの記事を評価

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

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

コメント欄