主に技術的なことを書くブログ

浅めにマークアップ&フロントエンドの技術的なことをメモしていましたが、ざっくばらんに書いています。

webpack 4系、ts-loader 4系、storybook 4系にしたときに出る謎のエラーを解決

React で storybook を使ってコンポーネントベースのUI開発をするっていうのが、こんな書籍も出てるぐらい

Atomic Design ~堅牢で使いやすいUIを効率良く設計する

Atomic Design ~堅牢で使いやすいUIを効率良く設計する

今フロントエンド界隈では熱いみたいなので、挑戦してみたのですが、出鼻を盛大にくじかれたエラーの解決方法を盛大に記しておきたい。

webpackの設定はつらい。

TypeScriptのコンパイルは通るが、storybook が動かない

まず最新の webpack 4系、ts-loader 4系、@storybook/react 4系にすると、TypeScriptのコンパイルは通るが、storybook が動かない

Module build failed: TypeError: Cannot set property 'tsLoaderDefinitionFileVersions' of undefined

もしくは、

Module build failed: TypeError: Cannot read property 'afterCompile' of undefined

あたりのエラーというかワーニングが出てコンパイルできないので、ググってみると ts-loader のバージョンを 3.5.0 に下げろ、というギフハブイシューなどが見つかる。

stotybook は動いたが、TypeScript がコンパイルできない

しょうがなしに、ts-loader を 3.5.0 に下げて動かしてみる。なるほど、 stotybook は確かに動いた。が、今後は TypeScript がコンパイルできない。

さらに調べると、ts-loader はまぁ、4系でいいから、@storybook/react の方を 4.0.0-alpha.10 にあげてみろという話が見つかる。 すると、なんかまたよくわからないエラーが出たので、

このあたりの、公式ドキュメントを眺めつつ、

.storybook 以下の webpack.config.js やら、config.js の設定を見直す。

webpack.config.js の方は、path とか TypeScript 使ってたら ts-loader とかを設定する(react-docgen-typescript-webpack-plugin が一体なんなのかは今は放置)。

const path = require("path");
const TSDocgenPlugin = require("react-docgen-typescript-webpack-plugin");

module.exports = (baseConfig, env, defaultConfig) => {
  defaultConfig.module.rules.push({
    test: /\.(ts|tsx)$/,
    include: path.resolve(__dirname, "../src"),
    loader: require.resolve("ts-loader")
  });
  defaultConfig.plugins.push(new TSDocgenPlugin()); // optional
  defaultConfig.resolve.extensions.push(".ts", ".tsx");

  return defaultConfig;
};

config.js は

import { configure } from '@storybook/react';

// automatically import all files ending in *.story.tsx
const req = require.context('../src/stories', true, /.story.tsx$/);
function loadStories() {
  req.keys().forEach(filename => req(filename));
}

configure(loadStories, module);

とかで、storybook のファイルをちゃんと読むようにする。

webpack のバージョン 4以下つかってない?という謎エラー

それでも、webpack のバージョン 4以下つかってない?という謎エラーがでる。。

ERR! Module build failed: Error: You may be using an old version of webpack; please check you're using at least version 4
ERR!     at successfulTypeScriptInstance (/Users/xxxxxxxxxx/node_modules/ts-loader/dist/instances.js:168:15)
ERR!     at Object.getTypeScriptInstance (/Users/xxxxxxxxxx/node_modules/ts-loader/dist/instances.js:51:12)
ERR!     at Object.loader (/Users/nakagawa/Git/xxxxxxxxxx/node_modules/ts-loader/dist/index.js:16:41)
ERR!  @ ./.storybook/config.js 4:2-59
ERR!  @ multi ./node_modules/@storybook/react/dist/server/config/polyfills.js ./node_modules/@storybook/react/dist/server/config/globals.js ./.storybook/config.js

で、いろいろやり尽くした結果。storybook のコンポーネント作るファイル xxxx.story.tsx の方で読み込んでいる @storybook/*** 系アドオンのバージョンも全部 4.0.0-alpha.10 に揃えないとだめだった。

参考:

Wordpress のパーマリンク設定のカスタム構造の postname を .html から スラッシュ終わりにしたら、スラッグが数字のみのページが 404 になる

Wordpressパーマリンク設定のカスタム構造のパスを、 .html 終わりから f:id:nakagaw:20171026104630p:plain

/ 終わりに変更したら f:id:nakagaw:20171026104500p:plain

スラッグが数字のみのページが 404 になってしまいました。

いろいろ調べたのですが、

パーマリンクの使い方 - WordPress Codex 日本語版

一日に一投稿しか公開しないので %year%%monthnum%%day% というパーマリンクを使用したいと思うかもしれませんが、このリンクはその日の全投稿のアーカイブとして生成されることに注意してください。個別投稿へのリンクは、少なくとも %year%%monthnum%%day%%hour% にする必要があります。

これば別のプラグイン

ローカルタグ URL で 404 エラーが発生する場合は、WordPress の生成する内部書き換え規則がでしゃばり過ぎて UTW の書き換え規則よりも先に呼び出されるからです。この現象は通常、(/%postname%/ のような) カスタムパーマリンク構造を使用している時にのみ起こります。

あたりはものすごく臭うものの、ちょっとずれてて。 こんな誰もがハマりそうなところで全く情報がないのがもやっとしてます。

一番ちかいのが

WordPressのパーマリンク設定で絶対にやってはいけないこと – 数字だけの記事ファイル名

これかなっとおもったけど、4桁とか全く関係なく、数字だと何桁でもアウトな感じで、だいぶはまってたのですが。 この特定のURLを入力すると、どんな Riweire rule がかかってるかを調べるプラグインをおしえてもらって、調査してみると、、

wordpress.org

.html 終わりの場合

Rule:

(.+?)/([^/]+).html(?:/([0-9]+))?/?$

Rewrite 後:

index.php?category_name=$matches[1]&name=$matches[2]&page=$matches[3]

https://example.com/category-hoge/category-fuga/20171026.html
↓ 内部的にはこうなる
https://example.com/index.php?category_name=category-hoge/category-fuga&name=20171026
=> ページあり

/ 終わりの場合

Rule:

(.+?)/([^/]+)(?:/([0-9]+))?/?$

Rewrite 後:

index.php?category_name=$matches[1]&name=$matches[2]&page=$matches[3]

https://example.com/category-hoge/category-fuga/20171026/
↓ 内部的にはこうなる
https://example.com/index.php?category_name=category-hoge&name=category-fuga&page=20171026
=> Not found

アンダースコアひとつでもはいってると
https://example.com/category-hoge/category-fuga/20171026_/
↓ 内部的にはこうなる
https://example.com/index.php?category_name=category-hoge/category-fuga&name=20171026_
=> ページあり

解決策

?&name= のあとにページスラッグがあれば、そのあいだのカテゴリがどんなものであっても、該当のページに辿りつけるみたいなので、

function.php に以下の add_rewrite_rule を追記

// 数字 + スラッシュ で終わるページの 404 なくす
function custom_rewrite_basic() {
  add_rewrite_rule('category-hoge/([^/]+)(?:/([0-9]+))?/?$', 'index.php?category_name=category-hoge/$matches[1]&name=$matches[2]', 'top');
}
add_action('init', 'custom_rewrite_basic');

無事ページが表示されました。

これにハマった人でないと何の話やねん、って感じだと思いますが、そうなったときに見ていただければと思います。

参考:

Mac でさくっとローカルサーバーを起動する方法

Mac標準のターミナルからApacheを起動する

MacにはApacheが標準でインストールされているらいいです。

Apacheの起動

sudo apachectl start

ブラウザで http://127.0.0.1/ を確認すると、「It works!」と表示されるかと思います。

これは、/Library/WebServer/Documents/ 以下がドキュメントルートなので、そこを見ている感じです。

ifconfigコマンドで調べた自分のIPアドレス(192.168.x.x)に、同一ネットワークのiPhoneからアクセスできるので実機確認ができます。

Apacheの停止

sudo apachectl stop

起動状況の確認

ps agx | grep httpd

Apacheの再起動

sudo apachectl restart

参考:Mac標準のApacheの起動と停止 | Web制作・Webシステム(東京)の株式会社ワイワイエンジン

Pythonでもできる

MacにはPythonも標準でインストールされているらいいです。

python -m SimpleHTTPServer 8888

http://127.0.0.1:8888/ iPhoneからは http://192.168.x.x:8888/

Ctrl+c で停止。

参考:手っ取り早く Mac でローカルサーバーを立てる方法 - tacamy.blog

今更聞けない IPアドレスについてまとめ

127.0.0.1/(localhost/と同じ)

127.0.0.1というIPアドレスはよく利用されるため、通常は「localhost」という単純なホスト名でアクセスできるようになっている(ドメイン名は付かない。localhostという単一ラベルの名前としてのみ有効)。例えば「http://127.0.0.1/」は「http://localhost/」としてアクセスできるし、ローカル・コンピュータ上のFTPサーバに接続するには、「ftp localhost」とすればよい。  localhostはほとんどの場合127.0.0.1と同義に利用できるが、NetBIOS関連のアプリケーションでは意味が異なることがある。
引用元:"Windows TIPS:ローカル・ループバック・アドレス(127.0.0.1)とは? - @IT

192.168.x.x/

社内ネットワークなどではプライベート・アドレスを使うのが一般的になっている。社内からインターネットへアクセスするときは,インターネットとの境界に置いたゲートウエイ装置でIPアドレスをプライベートからグローバルに付け替えるアドレス変換という技術が使われている。
引用元:"ネットワークHOTTOPICS - なぜ「192.168.x.x」のアドレスを使う?:ITpro

0.0.0.0/

Local Addressの0.0.0.0はマシンが持っているすべてのIPアドレスを表しています。つまりマシンが複数のIPを持っていた場合、マシンの持つすべてのIPアドレスにおいて接続を受け付けているということになります。 それとは違いLocal Addressが指定されている場合は、接続先アドレスがそのアドレスの接続しか受け付けないようになっています。
引用元:"「0.0.0.0」や「127.0.0.1」の意味? - ネットワークセキュリティ - 教えて!goo

参考:Mac OS X LionでApache、PHP、MySQLを動かす | HAPPY*TRAP