0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

create-react-appとpugとstylus

Last updated at Posted at 2020-03-02

その1
https://qiita.com/DaisukeNishi/items/dae74d5dcf5ddb171b3d
その2
https://qiita.com/DaisukeNishi/items/e93a3448668f65df7a91
その3
https://qiita.com/DaisukeNishi/items/697fb3579d7dd69324b3
その4
https://qiita.com/DaisukeNishi/items/801e1b1e02487e26e905
その6
https://qiita.com/DaisukeNishi/items/c8982546c803d2c5dc99

※これは5回目にあたります。

##create-react-app+pug+stylus簡単→そんな事なかった。
最初からjsxなんて書かない!俺はpugで全てやるんだと意気込んだが、

pugについての結論は、
逆にトランスパイル後のjsxの姿を想像できてないとツライだろうと思った。
なので、ある程度jsxの達人になってからpugでラクに見通せるようにする方が、
学習の順序としては近道だろう。

CSS-Modulesについてすっごい調べたけど、stylus-loaderのコンフィグを
ejectしないでやろうとするとcustomize-craにメソッドがなくて非公式プラグイン使ったり
react-dev-utilsに書いてある処理やextensionsの書き換えの所で
ハマるので、そっち方面で進めるのは、やめたほうが良いと思う。

stylusについてでた結論は、普通にstyled-jsx使ったほうがラクだと思った。
Keita Ishibashi(usagi-f)さんもstyled-jsxをオススメしてたし。
Githubのスターもそっちの方が多いし、ネットで解決案を探しやすい。

##目的
###で、この記事の目的とは?
Reactを使いたい。
yarn ejectする選択肢はない。
・とにかくpugstylusを使いたい。

それを、なんとかする記事です・・まぁ最初はなんとかなるんですよ。
「わーい、書けた書けた〜♪このまま行ける!」って思ったんですけど、

下記のやりかたを突き詰めていくと、結局hashされたCSSにしたいなと思ったら
むしろyarn ejectした方がラクだし、pugのメリットを捨てなければいかんと思う。

なので今回この記事は、失敗を糧にしてもらう、というのと
CSS-Modules...?そんなものは知らんなぁ...という感じです。

##下準備
###必要なプラグインを揃える
babel-plugin-〇〇のいくつかのプラグインには
devDependencyにしておくと動かないものがあるので-Dを付けない事にしています(言い訳)

$ npm install -g create-react-app
$ create-react-app {yourProject}
$ cd {yourProject}

//基本セットと、「○○-loader」などを追加する
$ yarn add sass node-sass stylus pug
$ yarn add stylus-loader extract-text-webpack-plugin pug-loader json-loader

//babel系プラグインを追加する
$ yarn add babel-plugin-transform-react-pug
$ yarn add babel-plugin-transform-react-jsx

//(追記)→styled-jsxを使った方がいい。引き返すなら今ですよー!
$ yarn add styled-jsx
$ yarn add styled-jsx-plugin-stylus

//下記プラグインを使うと遠回りな気がする
$ yarn add babel-plugin-transform-jsx-css-modules
$ yarn add babel-plugin-react-pug-classnames
$ yarn add babel-plugin-react-css-modules

//eslint系プラグインを追加する
$ yarn add eslint-plugin-react-pug eslint-plugin-css-modules

//※overrideツールを追加する
$ yarn add react-app-rewired customize-cra customize-cra-add-stylus-loader
$ touch .eslintrc
$ touch .babelrc

###react-scriptsを取り出す
「いきなり何を言ってるんだ?結局直にwebpack.config.jsいじってるじゃん!」
と思うかもですが、直にいじるデメリットを軽減する方法を紹介しますのでご勘弁を。

react-scriptをホームディレクトリに複製し名前を(例:react-scripts-pug-stylus)とします。
適当で良いですが、公式パッケージや他のプロジェクトと混乱しない名前がよいです。

$ cp -r ./node_modules/react-scripts ../react-scripts-pug-stylus
$ cd ../react-scripts-pug-stylus
$ open ./config/webpack.config.js

css-loadersass-loader
create-react-appした時にデフォで用意されますが
そのままではstylusが読み込めないので、stylus-loaderを追加していきます。

webpack.config.js
//(50行目あたり)
const sassRegex = /\.(scss|sass)$/;
const stylRegex = /\.(styl)$/; //←追加
const sassModuleRegex = /\.module\.(scss|sass)$/;
const stylModuleRegex = /\.module\.(styl)$/; //←追加

sassの設定をコピーします。

webpack.config.js
//(500行目あたり)
 {
  test: sassRegex,
  exclude: sassModuleRegex,
  use: getStyleLoaders(
     {
       importLoaders: 3,
       sourceMap: isEnvProduction && shouldUseSourceMap,
     },
   'sass-loader'
 ),
 sideEffects: true,
},
//ここから下に追記をします。
{
  test: stylRegex,
  exclude: stylModuleRegex,
  use: getStyleLoaders(
    {
     importLoaders: 3,
     sourceMap: isEnvProduction && shouldUseSourceMap,
    },
  'stylus-loader'
 ),
 sideEffects: true,
},
webpack.config.js
{
  test: sassModuleRegex,
  use: getStyleLoaders(
    {
      importLoaders: 3,
      sourceMap: isEnvProduction && shouldUseSourceMap,
      modules: {
        getLocalIdent: getCSSModuleLocalIdent,
      },
    },
    'sass-loader'
  ),
},
//下に追加
{
  test: stylModuleRegex,
  use: getStyleLoaders(
    {
      importLoaders: 3,
      sourceMap: isEnvProduction && shouldUseSourceMap,
      modules: {
        getLocalIdent: getCSSModuleLocalIdent,
      },
    },
    'stylus-loader'
  ),
},

あとは、ファイル拡張子のextensions.stylを追加する。
別ファイルを参照するようになっています。

webpack.config.js
//(300行目あたり)
extensions: paths.moduleFileExtensions

pathって何?と思ったら、同じ階層に置いてあるpath.jsです。

path.js
const moduleFileExtensions = [
  'web.mjs',
  'mjs',
  'web.js',
  'js',
  'web.ts',
  'ts',
  'web.tsx',
  'tsx',
  'json',
  'web.jsx',
  'jsx',
  'styl' //←追加する
];

色々とプラグインを見てみたけど、これのスマートな代替策がない気がする。
純粋な.stylじゃなくても.jsxにした方が良いんじゃないかと後で思ったんですが、
それだと既存の資産を使えないので、、、このまま説明つづきます。

###.eslintrcを有効に

customize-craでも書き換えできるのですが、
どうせ今webpack.config.jsを書き換えてるんだし、もうここで書き換えちゃいます。

webpack.config.js
//(370行目あたり)
useEslintrc: false, //←trueにする

ちなみにcustomize-craでやるなら

config-overrides.js
const { override,useEslintRc,disableEsLint} = require("customize-cra");
module.exports = override(
  useEslintRc(".eslintrc"),
  //disableEsLint()
);

###.babelrcを有効に

customize-craでも書き換えできるのですが、
どうせ今webpack.config.jsを書き換えてるんだし、もうここで書き換えちゃいます。

webpack.config.js
//(2箇所ある)
babelrc: false, //←trueにする

ちなみにcustomize-craでやるなら

config-overrides.js
const { override,useBabelRc} = require("customize-cra");
module.exports = override(
  useBabelRc(".babelrc"),
);

###Githubに上げておく
webpack.config.jspath.jsを編集し終わったら、
このreact-scripts-pug-stylusを、ご自分で管理されているGithubに上げてください。
(例):https://github.com/daisuke240000/react-scripts-pug-stylus
※他人がカスタムしたreact-scriptsを使っても動かないです。

$ cd ../yourProject
$ yarn remove react-scripts

###名前を変えて読み込む
保存する時には名前を変えたのですが、
オーバーライドツール(react-app-rewiredなど)を使用する場合、
元のパッケージの名前がreact-scriptsにしておかないと動かないので、下記のようにします。

プロトコルはgit+ssh://...と書けるのですが、
開発環境の違いなどを考慮してhttps://の方が無難です。
(SourceTree使ってる人はsshでgitに接続しないため)

※下記の.json(.js)はシンタックスのハイライトのために付けているだけです。

package.json.js
"react-scripts": "^3.4.0",// yarn removeで削除される
"react-scripts": "https://github.com/daisuke240000/react-scripts-pug-stylus",
// ↑追記する。パッケージ名を同じ名前にしておかないとオーバーライドできない。
// (中略)
// ↓「npm scripts」をこのように改変します。
"scripts": {
  "start": "react-app-rewired start",
  "build": "react-app-rewired build",
  "test": "react-app-rewired test --env=jsdom",
  "eject": "react-app-rewired eject"
},

変更を保存し、package.lock.jsonyarn.lockを消して

$ yarn

パッケージを集めます。lockファイルが存在していると、書き直した時に見に行ってくれないです。
完了したらインストールされたパッケージ内容を確認。

$ open ./node_modules/react-scripts/config/webpack.config.js

成功ならばstylus-loaderbabelrc: trueになっています。
もしも更新されていなかったら、設定に失敗してると思いますので見直してください。
該当フォルダを削除し、lockファイルも削除し、package.jsonをもう一回確認して$ yarnです。

###.babelrcを編集
react-pugのクラス名の付け方に関してはclassNamestyleNameがあります。
CSS Modulesをやりたいので、最終的にはstyleNameを使おうと思うのですが、

「本当にstyleNameで良いんだっけ?」と思ったので、
検証用でスイッチできるよう、両方書いて片方をコメントアウトしておきます。

↓(.js)はシンタックスハイライトのために付けてるだけです。

.babelrc.js
{
  "presets": [
    "react-app"
  ],
  "plugins": [
    "transform-react-pug",
    // ["transform-react-pug",{"classAttribute": "styleName"}], //←あとで使います。
    // ["react-pug-classnames", {"classAttribute": "styleName"}],
    //["transform-jsx-css-modules", {"pathToStyles": "^\\.\\/module\\.scss$"}],
    "transform-react-jsx",
    "transform-jsx-css-modules",
    "react-css-modules"
  ]
}

###.eslintrcを編集
$ eslint --initで作成したものに、
react-pugplugin:react-pug/allを追加するのが無難だと思います。
$ eslint --initできない?グローバルにインストールした方がいいかもです。

↓(.js)はシンタックスハイライトのために付けてるだけです。

.eslintrc.js
{
  "env": {
    "es6": true,
    "node": true,
    "browser": true
  },
  "parserOptions": {
    "ecmaVersion": 6,
    "allowImportExportEverywhere": true
  },
  "plugins": [
    "react-pug" //←追加
  ],
  "extends": [
    "react-app",
    "plugin:react-pug/all" //←追加
  ],
  "rules": {
    "import/no-named-as-default": 0
  }
}

###config-overrides.jsを編集
上書きしているのに、ダメ押しでreact-app-rewiredを使います。
customize-cracustomize-cra-add-stylus-loaderを使います。
設定ファイルはプロジェクト直下にconfig-overrides.jsを作成します。

$ touch config-overrides.js
$ open config-overrides.js

####webpack設定上書き方法への考察:

#####オーバーライドツール、コレ1本で良いのでは?
babeleslintに関するwebpack.config.jsのオーバーライドツールは
react-app-rewiredだけを使えば良いのでは?と思ったのですが、
.stylstylus-loaderを追加するメソッドが、
非公式のプラグインしか見当たらないので、補助的に使う事にしました。

#####むしろreact-app-rewiredは必要ないのでは?
むしろ逆にreact-app-rewiredは、使わなくて良いのではないか?とも思ったのですが、
disableEsLint()Eslintを秒でオフにできるのは、とても使い勝手が良いですし、
そもそも.stylファイルを読み込む事をやらないんだったら、こっちが王道です。

また、react-scriptsのバージョンが上がるたびに改変リポジトリを作るのも不自由・非効率ですし、
できる事ならreact-app-rewiredcustomize-craにまとめられたらいいなと思っているので、
今回は、両方使ってみる事にしました。

このツールだけで、ほとんどオーバーライドする事が可能ですが、
独自の書き方を調べるのは若干面倒です。また、このやり方でstylusをよませる関連ネットに例文転がってないので、
誰もやってないような気がします。
特にaddStylusLoaderっていう、個人が作ってる拡張は、ぜんぜん使ってる人いない。

#####customize-cra+add-stylus-loaderを使ってる人が・・2人?
https://github.com/kingyinliang/cra-react/blob/7bb2df8a033732ac22e4c8726da8427378d411f3/config-overrides.js
https://github.com/zhzxang/tft-help/blob/5e5d1a1638fb0797c747227b8a08843c374025d2/config-overrides.js
世界で2人だけって・・何か、別のやり方があるんだろうと思います。

config-overrides.js
const { override,
  //addBabelPlugins,
  //useBabelRc,
  //useEslintRc,
  disableEsLint
} = require("customize-cra");
const addStylusLoader = require('customize-cra-add-stylus-loader');

module.exports = override(
  //...addBabelPlugins(         //←使うと、babelのプラグインを追加できます。
    // "babel-plugin-transform-react-pug",
    // ["babel-plugin-transform-react-pug",{"classAttribute": "styleName"}],
    // ["react-pug-classnames", {"classAttribute": "styleName"}],
    // "babel-plugin-react-css-modules",
    // "babel-plugin-transform-react-jsx"
  //),
  //useBabelRc(".babelrc"),
  //useEslintRc(".eslintrc"), //←使うと.eslintrcが有効になります。
  //addStylusLoader(          //←使うとstylus-loaderの設定できるようです。※ネットに例文がない
    //{
    //}
  //),
  disableEsLint()        //←.eslintをオフにします。
);

##表示される部分を編集
###css、scss、stylは正しく読み込まれているのか検証する
複製したり変換したりして、App.cssを色々な形に変換しておく。

####検証時にハイフンがめんどうになる問題
class名にハイフン使えないって、
まったく「ナンノコッチャ」だとは思いますが・・

本番で使わないけど、検証の途中でdiv(className=App-header)
という風な、ちょっとpugらしくない書き方をした場合に、
ハイフン(-)が別の意味になってしまいます。

それで変につまづかないように、
ここでは、あらかじめハイフン(-)を何か他の書き方にしておきます。
※普通はclass名はハイフン推奨です。
※pugでハイフンを使うとバグる(引き算としての処理になる)ので
むしろdiv(className=A-B)みたいな書き方は絶対できません。

App.js
//(※以下、抜粋です)
//<header className="App-header">
<header className="AppHeader">
//<img src={logo} className="App-logo" alt="logo" />
<img src={logo} className="AppLogo" alt="logo" />
//<a className="App-link" >
<a className="AppLink" >
App.css
/*App-logo {...}*/ 
.AppLogo {...}
/*App-header {...}*/
.AppHeader {...}
/*App-link {...}*/
.AppLink {...}

create-react-appの公式のドキュメントには
「もしCSS Modulesを使うなら、ファイル名を○○.module.cssにしなさい。」
と書いてある。(もうね、いろんな人がいろんな仕様いうからこんがらがってしまう)

$ cp App.css App.scss
$ cp App.css App.styl
$ cp App.css App.module.styl

scssstylusも、変換して中身を変えなくても動くはずです。
(※もしsugarssで解析できなかったら、正しいstylusの文法に書き換えてください)

App.jsで、一個ずつコメントアウトをはずしながら確認を行なう。

App.js
import React from 'react';
import logo from './logo.svg';
// 原型
import './App.css';
// import './App.scss';
// import './App.styl';
// import styles from App.module.styl 

htmlにあたる部分はpugに置き換えますが、
pugをトランスパイルする前に間違っているのか、
pugにトランスパイルした後に間違っているのか、
ESLintの設定ミスなのか、最初は分からないので、
$yarn startでサーブしながらチェックしていきます。

あと、ここでdisableEsLint()をしておく方が問題の切り分けはできるかもです。

###初期状態
まずは、クラス名だけ書き換えた状態で動いているのを見ておく。

App.js
import './App.css';
//(中略)
function App() {
  return (
    <div className="App">
      <header className="AppHeader">
        <img src={logo} className="AppLogo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="AppLink"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

まあコレは、当然動くでしょう。(古いブラウザじゃなかったら。。)
###名前付きで読み込みしたパターンも書いてみる。

styleNameは一旦使用せず、classNameでいく場合、
import styles from './App.module.scss';のような感じで、
外部ファイルをstylesとして読み込み、classNameの頭にstyles.をつける。

classNameの値を囲んでいる""を消し、{}にしておく。
"{}"でも動くけど、pugで書いた時に全文がJS扱いになるので、""で囲んであると動かない。

App.js
import styles from './App.module.styl';
//(中略)
function App() {
  return (
    <div className={styles.App}>
      <header className={styles.AppHeader}>
        <img src={logo} className={styles.AppLogo} alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className={styles.AppLink}
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

これも動くっぽい。pugjsxにトランスパイルした後、
こんな感じになってるんだろうな、というイメージ。

###htmlタグをpugに置きかえる
pugで書くけど、まだstyleNameは使わない。
全部JSで処理するので{}などは不要です。-あるとバグるって言ってたのココです。

App.js
import styles from './App.module.scss';
//(中略)
function App() {
  return pug`
    div(className=styles.App)
      header(className=styles.AppHeader)
        img(className=styles.AppLogo src=logo alt="logo")
        p
          | Edit 
          code src/App.js
          |  and save to reload.

        a(className=styles.AppLink href="https://reactjs.org" target="_blank" rel="noOpener noReferrer")
          | Learn React
  `;
}

もしここでPug is not defined.とでた場合は、
babel-plugin-transform-react-pugが読み込まれてないか、
プラグインの順番が前後逆になっていると思います。
pugを変換するのが先です。

###pug+styleNameの書き方

####まずはmoduleナシに戻す
pug+styleNameを使う前に、まずstylesを宣言してない状態に戻します。

App.js
import './App.styl';
//(中略)
function App() {
  return pug`
    div(className="App")
      header(className="AppHeader")
        img(className="AppLogo"
          src=logo
          alt="logo")

        p
          | Edit 
          code src/App.js
          |  and save to reload.

        a(className="AppLink"
          href="https://reactjs.org"
          target="_blank"
          rel="noOpener noReferrer")
          | Learn React
  `;
}

これは(あれ?一回説明したような気が)
ほぼ<>が消えただけで、トランスパイル後も形はあまり変わらないので、
問題なく動くと思います。

####pugらしい書き方をする
pugの場合、div.App(またはdivも省略して.App)というような書き方をします。
さらにpugっぽい記述にします。

App.js
import './App.styl';
//(中略)
function App() {
  return pug`
    div.App
      header.AppHeader
        img.AppLogo(src=logo alt="logo")

        p
          | Edit 
          code src/App.js
          |  and save to reload.

        a.AppLink(
          href="https://reactjs.org"
          target="_blank"
          rel="noOpener noReferrer" )
          | Learn React
  `;
}

問題なく動いている(気がする。眠くてよう確認してないけど)
これは.AppclassName="App"にトランスパイルしている。
あとはモジュール化するだけなのでclassNameの設定をstyleNameに変えれば行けるはず。

###※ご注意:ここから先、だんだんと泥沼にハマっていきます。

###pugでCSS Modulesどうやる?
このプラグインの説明によるとpugCSS Modulesする時は、
class属性をstyleNameとするらしい。
https://github.com/pugjs/babel-plugin-transform-react-pug#css-modules
そういうズバリな変換機能がありそうだな〜。夢がひろがる。


ここ大事なので、雰囲気で英語をよまずに、ちゃんと意味を理解して翻訳してみよう。
###CSS Modules
(方法1)Babelを使用してJSX専用のCSSモジュール(例:babel-plugin-react-css-modules)をオンにするか、
(方法2)webpack-loaderを使用してスタイルをキー値オブジェクトに変換するかどうかは、pugで使用できます。

####方法1
・「Babel-plugin-react-css-modules」を使用して、
classAttributeオプションをstyleName値に設定する必要があります。

babelrc.js
{
  "plugins": [
    ["transform-react-pug", {
      "classAttribute": "styleName"
    }]
  ]
}
App.js
import './styles.css' // .hello{color:red}

const withCorrectStyles = pug`
  div.hello I am a red text
`

実際にやってみたが、

.babelrc.js
"react-css-modules",
["transform-react-pug",{"classAttribute": "styleName"}],

Cannot use styleName attribute for style name 'App' without importing at least one stylesheet.
少なくとも1つのスタイルシートをインポートしないと、スタイル名「App」にstyleName属性を使用できません。

→ん〜stylusstylesheetだと認識してない。cssとかscssじゃないと読み込んでくれないんだろうか。

####違うモジュールのドキュメントをよくよむ
react-css-modules.stylのシンタックスを理解させるには・・・
これにオプションの設定をしておく必要がありそう。
https://www.npmjs.com/package/babel-plugin-react-css-modules

.babelrc
["react-css-modules", {
   "filetypes" : {
      ".styl" : {
          "syntax" : "sugarss"
      }
  }
}],

sugarssというのが必要になってくる

$yarn add sugarss

あ、これでエラーが消え、ページを読み込めるようにはなった。
でも肝心のスタイルがあたらない。んがが・・

ハッシュされた名前を正しく取得するやり方がありそう。
getLocalIdent的な関数があったと思うので、そこをちゃんと見直してみるか・・?
いや、ちょっとこのやり方で時間の消費もったいないし、他の方法をためしてみよう。
(方法1については、まだ続きを書けそうな気がする。)

####方法2
・stylesをObjectに変換するwebpack-loader、またはその他のアプローチ

App.js
import classes from './styles.css' // .hello{color:green}

const withCorrectStyles = pug`
  div(className=classes.hello) I am a green text
`

ここで「classAttribute」オプションを「styleName」値に設定し、
babel-plugin-transform-jsx-css-modules」を追加することにより、開発体験を改善できます。

.babelrc.js
{
  "plugins": [
    ["transform-react-pug", {
      "classAttribute": "styleName"
    }],
    "transform-jsx-css-modules"
  ]
}

ということなので、ドキュメントに近いソースを用意しておきます。

App.js
import styles from './App.module.styl';
function App() {
  return pug`
    div(className=styles.App)
      header(className=styles.AppHeader)
        img(className=styles.AppLogo src=logo alt="logo")
        p
          | Edit 
          code src/App.js
          |  and save to reload.

        a(className=styles.AppLink href="https://reactjs.org" target="_blank" rel="noOpener noReferrer")
          | Learn React
  `;
}

babelrcも上記のように書き換えておきます。(ここまでは、動く)


公式から開発体験を改善できる、と言われている
babel-plugin-transform-jsx-css-modulesの英語を、実装前によく読んでおこう。

###babel-plugin-transform-jsx-css-modules
JSXのclassName属性を変換して、css-modulesの参照を取得します。
注:プロジェクトでCSSモジュールを有効にするのではなく、
自分で作成したと仮定します(たとえば、webpackやcss-loaderを使用して)。
(※うーん、よく読もうと思ったが、途中なんのこっちゃわからん)

####Example(例)

app.js
import './styles.css'
 
const Component = () => (
  <div styleName="root">
    <h1 className="paragraph">Hello World</h1>
    <p className="global" styleName="local">I'm an example!</p>
  </div>
)

↓こんな感じでトランスパイルされるでしょう

app.js
import __CSSM__ from './styles.css'
 
const Component = () => (
  <div className={__CSSM__['root']}>
    <h1 className="paragraph">Hello World</h1>
    <p className={["global", __CSSM__["local"]].join(" ")}>I'm an example!</p>
  </div>
)

/%\.\/module\.scss$/に設定すると、。/ module.scssで開始および終了するimportを処理します。

babelrc.js
{
  "plugins": [
    ["transform-jsx-css-modules", {
      "pathToStyles": "^\\.\\/module\\.scss$"
    }]
  ]
}
import './module.scss'

↓こんな感じでトランスパイルされるでしょう

import __CSSM__ from './module.scss'

翻訳をおわります。
つまり・・?これで、名前付きでimportしなくても、scopedなCSSができるっつーことですかね?
もう一回ソース見直してみます。

App.js
import './App.styl';
function App() {
  return pug`
    div(className="App")
      header(className="AppHeader")
        img(className="AppLogo" src=logo alt="logo")
        p
          | Edit 
          code src/App.js
          |  and save to reload.

        a(className="AppLink" href="https://reactjs.org" target="_blank" rel="noOpener noReferrer")
          | Learn React
  `;
}

↓コンパイルできてる状態。じゃあ、これはどうなんだろか?できるんじゃないか?

App.js
import './App.styl';
function App() {
  return pug`
    div(styleName="App")
      header(styleName="AppHeader")
        img(styleName="AppLogo" src=logo alt="logo")
        p
          | Edit 
          code src/App.js
          |  and save to reload.

        a(styleName="AppLink" href="https://reactjs.org" target="_blank" rel="noOpener noReferrer")
          | Learn React
  `;
}

・・・できませんでした。エラーを読みます。
React does not recognize the styleName prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase stylename instead.

App.js
import './App.styl';
function App() {
  return pug`
    .App
      header.AppHeader
        img.AppLogo(src=logo alt="logo")
        p
          | Edit 
          code src/App.js
          |  and save to reload.

        a.AppLink(href="https://reactjs.org" target="_blank" rel="noOpener noReferrer")
          | Learn React
  `;
}

・・・トランスパイル後がエラーでてるんだから、当然トランスパイル前も同じでしょう。。。
React does not recognize the styleName prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase stylename instead.

###ご注意:ここから先は、さらに、とてもハマります
React does not recognize the styleName prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase stylename instead.
「styleNameを認識できません。もしDOMのカスタム属性として使いたいなら、stylenameにしてください。」

...もしかして、こういう事?

.babelrc.json
["transform-react-pug",{
  "classAttribute": "stylename"
}],

####全然違いました。
<div stylename="App">
コレ、全然jsxとして機能しない。ただのhtmlのカスタム属性だった。この先エラーから辿れなくなって、キツイ。

####追加でReactにstyleNameを認識させるプラグインが必要かもしれない。

多分、コレかな。
https://www.npmjs.com/package/babel-plugin-react-pug-classnames
React-pugのサブコンポーネントを呼び出す問題を解決します。
https://github.com/ezhlobo/babel-plugin-transform-jsx-classname-componentsの改良バージョン)


ここ、英語の説明をちゃんと読むべきだと思う。
####babel-plugin-react-pug-classnames:
また、className(styleName)の配列またはオブジェクト値を自動的に解析し、
classnamesのような関数を介して変換します。
すべてのクラス名にエレメント名を自動的にプレフィックスすることにより、BEMタイプの修飾子の命名を追加します。

(ん〜〜〜〜これはどうなんだろう。BEMタイプの修飾子を追加?いやはやstyleNameを認識させたいだけなんやけど)

###まず.babelrcの設定を変更する
初期設定時にコメントアウトしていた設定を使います。
["transform-react-pug",{"classAttribute": "styleName"}],
["react-pug-classnames", {"classAttribute": "styleName"}],
これでWebpackが認識できない属性を追加してあげれる、とおもう。

.babelrc.js
{
  "presets": [
    "react-app"
  ],
  "plugins": [
    //"transform-react-pug",//←コッチをコメントアウトする
    ["transform-react-pug",{"classAttribute": "styleName"}],
    ["react-pug-classnames", {"classAttribute": "styleName"}],
    //"transform-react-jsx",//←いらないのかな。。
    "transform-jsx-css-modules"
  ]
}

?エラーが出てしまう

ReferenceError: div is not defined

なんだコレは、エラー出ないどころか、重症化してしまって、
pugの中身が正しく変換してない。

###ダメだ‥何度やってもここから先の手がかりがない
stackoverflowを漁っても、流石にこれじゃ検索のしようがない。
→ハマってしまったので、次の投稿にしようかと思います。
プラグインの順番か相性かどっちかな。
CSS Modulesへの道は遠い

##できたことはできたよ、オススメはせんけど

しかしコレでpugstylusを使って書けるようになります。
最終的に、styleName使わないなら、まあ動くよ、というApp.jsはこんな感じでした。
styleNameだけ切り分けてテストしてみないと原因特定できないや。まあそれは今度

App.js
import React from 'react';
import logo from './logo.svg';
import './App.styl';
function App() {
  return pug`
    div.App
      header.AppHeader
        img.AppLogo(src=logo alt="logo")

        p
          | Edit 
          code src/App.js
          |  and save to reload.

        a.AppLink(
          href="https://reactjs.org"
          target="_blank"
          rel="noOpener noReferrer")
          | Learn React
  `;
}
export default App;

最終的なstylusはこのような感じ

App.styl
.App
  text-align center

.AppLogo
  height 40vmin
  pointer-events none

@media (prefers-reduced-motion: no-preference)
  .AppLogo
    animation App-logo-spin infinite 20s linear

  .AppHeader
    background-color #282c34
    min-height 100vh
    display flex
    flex-direction column
    align-items center
    justify-content center
    font-size calc(10px + 2vmin)
    color white

.AppLink
  color #61dafb

@keyframes App-logo-spin{
  from{
    transform rotate(0deg)
  }
  to{
    transform rotate(360deg)
  }
}

最終的な.babelrcはこんな感じ。

.babelrc.js
{
  "presets": [
    "react-app"
  ],
  "plugins": [
    "transform-react-pug",
    //["transform-react-pug",{"classAttribute": "styleName"}],
    //["react-pug-classnames", {"classAttribute": "styleName"}],
    "transform-react-jsx",
    "transform-jsx-css-modules"
  ]
}

最終的な.eslintrc.jsはこんな感じ

.eslintrc
{
  "env": {
    "es6": true,
    "node": true,
    "browser": true
  },
  "parserOptions": {
    "ecmaVersion": 6,
    "allowImportExportEverywhere": true
  },
  "plugins": [
    "react-pug"
  ],
    "extends": [
    "react-app",
    "plugin:react-pug/all"
  ],
  "rules": {
    "import/no-named-as-default": 0
  }
}

config-overrides.jsはこんな感じ

config-overrides.js
const { override, disableEsLint } = require("customize-cra");
module.exports = override(
  //useBabelRc(".babelrc"),
  //useEslintRc(".eslintrc"),
  disableEsLint()
);

ここに書いた方がいい設定と、.babelrcなどに書いた方が良い設定の判断はつきませんが
プラグインは.babelrcに書いたほうが分かりやすかったです。

最終的なpackage.jsonはこちら。

package.json
{
  "name": "sample",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.3.2",
    "@testing-library/user-event": "^7.1.2",
    "babel-plugin-react-css-modules": "^5.2.6",
    "babel-plugin-react-pug-classnames": "^0.3.1",
    "babel-plugin-transform-jsx-css-modules": "^1.0.0",
    "babel-plugin-transform-react-jsx": "^6.24.1",
    "babel-plugin-transform-react-pug": "^7.0.1",
    "customize-cra": "^0.9.1",
    "eslint-plugin-css-modules": "^2.11.0",
    "eslint-plugin-react-pug": "^0.8.4",
    "node-sass": "^4.13.1",
    "react": "^16.13.0",
    "react-app-rewired": "^2.1.5",
    "react-dom": "^16.13.0",
    "react-scripts": "https://github.com/daisuke240000/react-scripts-pug-stylus",
    "stylus": "^0.54.7",
    "stylus-loader": "^3.0.2"
  },
  "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test --env=jsdom",
    "eject": "react-app-rewired eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

###styleName…
ネットで調べても調べてもこの問題は解決しないので、
styleNameとかもう死んだ規格なんじゃないかと思っています。
styleNameに関するリンクをココにはる予定。
 ↓
https://qiita.com/DaisukeNishi/items/617b7f9b4dde0bdeb3b9
(※ただの愚痴を貼っただけになってしまった)

###参考資料
https://html5beta.com/tools/css2stylus.html
https://github.com/dehimer/customize-cra-add-stylus-loader
https://github.com/arackaf/customize-cra/pull/144
adjustStyleLoadersの機能はありそうですが、使い方がわからない。
https://github.com/arackaf/customize-cra/blob/master/api.md#adjuststyleloaderscallback


https://github.com/timarney/react-app-rewired
https://github.com/gajus/babel-plugin-react-css-modules/issues/41
https://qiita.com/yikeda6616/items/0e31a920d533d70c0bd9
https://github.com/webpack-contrib/css-loader/issues/877
https://github.com/webpack/webpack/issues/8973
https://github.com/facebook/create-react-app/issues/5113
https://laracasts.com/discuss/channels/elixir/babel-plugin-react-css-modules-not-transforming-stylename-in-react
https://github.com/arackaf/customize-cra#with-webpack
https://github.com/timarney/react-app-rewired/issues/348
https://github.com/pugjs/babel-plugin-transform-react-pug#classattribute
https://github.com/timarney/react-app-rewired


http://www.beguru.work/2019/01/06/create-react-app-%E3%81%A7-babelrc%E3%82%92%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B/
https://kic-yuuki.hatenablog.com/entry/2019/09/08/111817
https://github.com/facebook/create-react-app


https://stackoverflow.com/questions/56513346/how-to-use-pug-templating-engine-with-reactjs
https://qiita.com/TakuyaHara/items/f560d34aaa7857b32c82
https://www.npmjs.com/package/babel-plugin-transform-react-pug
https://github.com/pugjs/babel-plugin-transform-react-pug#eslint-integration
https://github.com/ezhlobo/eslint-plugin-react-pug
https://html2pug.now.sh/

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?