LaravelをReact化+SSRした際のつまった所

28/01/2020

個人開発のサイトReact化してみました

前回記事で書いたけど個人で開発のサイトReact化してみました。
誰にも望まれてないけど勝手にリニューアル。
目指せ不労所得。がんばるんだ俺。

SSR(server side rendering)

SEOの事は詳しくは良くわかりませんがが
多分Reactそのままだとよくないかと思われる。ので今回server side renderingしました。

React自体今回始めてじっくりと触った感じなので
わからんけど普通はnext.jsとかでやるのかな?
良くは知りません。

SSRは不要?

最近のクローラーはイケてるので
SSRは不要なのでは?って情報とか見て

じゃいいや。

って思ってたんだけども
元々あんまり無かったアクセスが
結構あからさまにさらに下がった気がするので
致し方なくやる事に。
誰にも望まれてないけど

laravel server side rendering

https://github.com/spatie/laravel-server-side-rendering

多分Lalavelでやるならこれでやると良いらしいという情報みてやってみた。
想定してたよりは簡単にできた。
でも面倒は面倒だけど、

あんま情報少ないと思うので
自分がつまったポイント書いてみます。

node pathの設定

Laladock

nodeのパスを設定しましょうって書いてあるので
普通はwhich nodeで出てきたやつ.envに入れればいいはず、です。
でも自分の場合はローカルでLaladock使ってたからか
nodeがありまへんえ的なエラーがでて結構困った。

結論言うとlaradock_workspaceの方じゃなくて

laradock_php-fpm
のphp-fpmコンテナにnodeインストールしてからの
node pathを指定しないと駄目っぽい。

僕の場合は
laradock/php-fpm/Dockerfile
の適当な所に

RUN curl -sL https://deb.nodesource.com/setup_12.x | bash - \ 
    && apt-get update \
    && apt-get install -y nodejs

追記してから
dockerのphp-fpmリビルドしてーの

docker-compose build --no-cache php-fpm

which node

docker exec -it laradock_php-fpm_1 which node

のパス入れれば無事動きました。

リモートで

最初sshで入ってwhich nodeで出たpathを
特に気にせずそのまま入れてて

僕の場合~/(チルダ)から始まってるパスだったので
laravelからだとnginxのホームディレクトリ指しちゃってるの気づかず少し詰まった。

なのでルートディレクトリから指定した方が確実かと思う。多分。

あとはjsの話

初期表示

htmlかえってくるので
一瞬、生のhtmlがでちゃう。
生ででちゃう。ので

<style>body{display: none;}</style>

document.getElementsByTagName("body")[0].style.display = "block";

でひとまず対応した。
ローテクな感じになってしまったけど、これで良いのだろうか?
多分なんかありそうではある。けど、
困ってはないので一旦このまま

server.js

contextdispatch
laravel-serverside-renderingのパッケージからの関数なので
特に宣言とかは必要ないらしい。

がなんで使ってしまったのかtypescriptで初めてしまったので
そのままだとエラーがでます。
また面倒な事になってしまったなーと思ってたけど
declareを使えばいいっぽい。

declare var context;
declare var dispatch;

const html = ReactDOMServer.renderToString(
    <div id="root">
        <Provider store={store}>
            <StaticRouter location={context.url} context={context}>
                <Container />
            </StaticRouter>
        </Provider>
    </div>
);

こんな感じ。

ガッツリtypescript使って人からしたら当然?なのかな?
アンビエント宣言っていうらしい。
とりあえずは動いたので何でもいい。

ブライアンイーノ宣言。

createMemoryHistory

documentとかwindow使ってちゃ駄目ってのはサーバーサイドレンダリングだと割と有名な話らしい。
まぁnodeなんだからwindowは無いよね。って事かな?
ソレ先に言っといてよー。
とも思ったが仕方ない。誰にも望まれてないので。

話逸れたけど、
createBrowserHistoryでもエラーになっちゃいます。
かわりにcreateMemoryHistory使えばよいっぽい。

import { createBrowserHistory, createMemoryHistory, History } from "history";

const history: History =
    typeof document !== "undefined"
        ? createBrowserHistory()
        : createMemoryHistory();

export default history;

こんな感じ。

CSS

あとjQueryおじさんなので
カルーセルっていえばslickです。
react-slick使ってたのだけども、
server側ではcssをimportするとエラーになったので

こんな感じにしました。

if (typeof window !== "undefined") {
    require("slick-carousel/slick/slick.css");
}

ちなみにimport()だとなぜかエラー出たのでここだけ
requireで、理由はしらない。動いたからいいや。

import "slick-carousel/slick/slick.css";
//これはerror
if (typeof window !== "undefined") {
    import("slick-carousel/slick/slick.css");
}
//これもerror

webpackの設定が悪いのかも、ですが。

おわり

今の所lalavel側からとってきた。
eloquentのデータはserver側にしか反映しておらず
二度手間みたいなリクエストになっちゃってるので
そのうちちゃんとする予定。
忘れないうちに記事にしてみました。