😺

これから始めるTailwindCSS - PostCSS × Stylelint × VSCodeでとりあえず使えるようにする

2021/12/17に公開

目的

この記事では、TailwindCSSをVSCodeで使うための最小限の環境構築までを目的としています。CSSの圧縮などは扱いません。また、Stylelintについても、TailwindCSSの関連部分のみに触れます。

TailwindCSSのバージョン

3.0.5

はじめに Sass × webpackで開発している(た)方へ

TailwindCSSは、PostCSSプラグインです。Sassなどのプリプロセッサと併用もできますが、TailwindCSSを使う場合、Sassのようなプリプロセッサを使う必要はありません。PostCSSだけで完結します。もちろん、Sass同様の機能を使って開発できます。またTailwindCSSだけならwebpackも必要ありません。

参考:
https://tailwindcss.jp/docs/using-with-preprocessors

手順

ここから手順の説明です。

プロジェクトフォルダを作成

任意の場所にプロジェクトフォルダを作成します。

mkdir path/to/MyProject
cd path/to/MyProject 

package.jsonを作成します。

yarn init -y

TailwindCSSのインストール

TailwindCSSをインストールします。

yarn add tailwindcss

TailwindCSSを初期化します。 -p オプションをつけておくと、postcss.config.jsも一緒に作成されます。

npx tailwindcss init -p

プロジェクトフォルダに tailwind.config.jspostcss.config.js ができていることを確認します。

PostCSSとプラグインのインストール

yarn add -D postcss postcss-cli postcss-import postcss-preset-env postcss-sort-media-queries

postcss-cli

PostCSS用のコマンドを使えるようにする。

postcss-import

cssをsassのようにimportする。

postcss-preset-env

策定中の機能や記法などを使えるようにするプラグインをまとめたもの。autoprefixerもこちらで利用します。

postcss-sort-media-queries

同じ条件の複数のメディアクエリをひとつにまとめてくれて、さらにソートしてくれます。

PostCSSの設定

postcss.config.jsを以下のように書き換えます。

postcss.config.js
module.exports = (ctx) => {
  return {
    map: ctx.options.map,
    plugins: {
      'postcss-import': {},
      // tailwindcssに内包。tailwindcssの直前に書く。
      'tailwindcss/nesting': {}, 
      tailwindcss: {},
      'postcss-preset-env': {
        stage: 3,
        features: {
          'nesting-rules': false
        },
        autoprefixer: {}
      },
      'postcss-sort-media-queries': {},
    }
  }
}

npm scriptsの設定

package.jsonのscriptsを以下のように記述します。glob記法で、src/css配下のCSSをpublic/dist`にコンパイルするように指定します。アンダースコアから始まるCSSはimport用として出力しないようにしています。

package.json
{
  "scripts": {
    "css:build": "postcss src/css/**/[^_]*.css -d public/dist",
    "css:watch": "postcss src/css/**/[^_]*.css -d public/dist -w"
  }
}

Stylelintの設定

先にStylelintの設定をしておきます。
stylelin-config-recess-orderはなくても大丈夫です。その他お好みの拡張を入れてください。

yarn add stylelint stylelint-config-standard stylelint-config-recess-order
.stylelintrc.js
module.exports = {
  extends: [
    'stylelint-config-standard',
     // ほかはお好みで
    'stylelint-config-recess-order'
  ],

  rules: {
    "at-rule-no-unknown": [
      true,
      {
        ignoreAtRules: [
          "tailwind",
          "apply",
          "variants",
          "responsive",
          "screen",
        ],
      },
    ],
  }
}

また、VSCodeのsettings.jsonに以下を追加しておくと、不要なCSSのlintエラーが出なくなります。

settings.json
{
  "css.validate": false
}

TailwindCSSの設定

先ほどのCSSを以下のように書き換えます。

./src/css/index.css
@tailwind components;
@tailwind utilities;

一度コンパイルしてみましょう。

yarn css:build

以下のようにCSSファイルが出力されていれば成功です。まだCSSプロパティが何も表示されていなくても大丈夫です。

./dist/css/index.css
/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jc3MvaW5kZXguY3NzIiwiPG5vIHNvdXJjZT4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7SUNBQSxvQkFBQTtJQUFBO0FEQW1CO0FBQW5CO0lDQUEsb0JBQUE7SUFBQTtBREFtQjtBQUFuQjtJQ0FBLHFCQUFBO0lBQUE7QURBbUIiLCJmaWxlIjoiaW5kZXguY3NzIiwic291cmNlc0NvbnRlbnQiOlsiQHRhaWx3aW5kIHV0aWxpdGllcztcbiIsbnVsbF19 */

なぜなら、TailwindCSSの components や utilities は、HTMLやJSなどの入力ソースに使われているTailwindCSSのCSSクラスのみを出力してくれる、超天才だからです!

というわけで、実際にソースを作って試してみます。

./src/html/index.html;
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>TailwindCSSのテスト</title>
</head>
<body>

<div class="container">
  <h1 class="text-lg">TailwindCSSのテスト</h1>
  <p class="text-slate-200">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
  <p class="text-sm">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>

</body>
</html>

tailwind.config.jsでソースを指定します。content の部分にソースをglob表記で記述します。

tailwind.config.js
 module.exports = {
  content: [
    './src/html/**/*.html'
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

CSSをコンパイルしてみましょう。

yarn css:build

HTML側で使われているCSSクラスだけが出力されています。TailwindCSSの真骨頂ですね。

./dist/css/index.css
.container {
    width: 100%
}
.text-lg {
    font-size: 1.125rem;
    line-height: 1.75rem
}
.text-sm {
    font-size: 0.875rem;
    line-height: 1.25rem
}
.text-slate-200 {
    --tw-text-opacity: 1;
    color: rgb(226 232 240 / var(--tw-text-opacity))
}
@media (min-width: 640px) {
    .container {
        max-width: 640px
    }
}
@media (min-width: 768px) {
    .container {
        max-width: 768px
    }
}
@media (min-width: 1024px) {
    .container {
        max-width: 1024px
    }
}
@media (min-width: 1280px) {
    .container {
        max-width: 1280px
    }
}
@media (min-width: 1536px) {
    .container {
        max-width: 1536px
    }
}

/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jc3MvaW5kZXguY3NzIiwiPG5vIHNvdXJjZT4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7SUNBQTtBREFvQjtBQUNwQjtJQ0RBLG9CQUFBO0lBQUE7QURDbUI7QUFBbkI7SUNEQSxvQkFBQTtJQUFBO0FEQ21CO0FBQW5CO0lDREEscUJBQUE7SUFBQTtBRENtQjtBQURuQjtJQ0FBO1FBQUE7S0FBQTtBREFvQjtBQUFwQjtJQ0FBO1FBQUE7S0FBQTtBREFvQjtBQUFwQjtJQ0FBO1FBQUE7S0FBQTtBREFvQjtBQUFwQjtJQ0FBO1FBQUE7S0FBQTtBREFvQjtBQUFwQjtJQ0FBO1FBQUE7S0FBQTtBREFvQiIsImZpbGUiOiJpbmRleC5jc3MiLCJzb3VyY2VzQ29udGVudCI6WyJAdGFpbHdpbmQgY29tcG9uZW50cztcbkB0YWlsd2luZCB1dGlsaXRpZXM7XG4iLG51bGxdfQ== */

もちろん、実際のソースはHTMLだけではなくJSXなども含まれます。

また、今回はわかりやすくするため @tailwind base;を書いていませんでしたが、実際はこちらも使いましょう。

@tailwind base;
@tailwind components;
@tailwind utilities;

まとめ

package.json
{
  "name": "MyProject",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "css:build": "postcss src/css/**/[^_]*.css -d public/dist",
    "css:watch": "postcss src/css/**/[^_]*.css -d public/dist -w"
  },
  "dependencies": {
    "tailwindcss": "^3.0.5"
  },
  "devDependencies": {
    "postcss": "^8.4.5",
    "postcss-cli": "^9.1.0",
    "postcss-import": "^14.0.2",
    "postcss-preset-env": "^7.0.1",
    "postcss-sort-media-queries": "^4.2.1",
    "stylelint": "^14.1.0",
    "stylelint-config-recess-order": "^3.0.0",
    "stylelint-config-standard": "^24.0.0"
  }
}
tailwind.config.js
 module.exports = {
  content: [
    './src/html/**/*.html'
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
postcss.config.js
module.exports = (ctx) => {
  return {
    map: ctx.options.map,
    plugins: {
      'postcss-import': {},
      // tailwindcssに含まれている。tailwindcssの直前に書く。
      'tailwindcss/nesting': {},
      tailwindcss: {},
      'postcss-preset-env': {
        stage: 3,
        features: {
          'nesting-rules': false
        },
        autoprefixer: {}
      },
      // メディアクエリをまとめる
      '@lipemat/css-mqpacker': {},
    }
  }
}
.stylelntrc.js
module.exports = {
  extends: [
    'stylelint-config-standard',
    'stylelint-config-recess-order'
  ],

  rules: {
    "at-rule-no-unknown": [
      true,
      {
        ignoreAtRules: [
          "tailwind",
          "apply",
          "variants",
          "responsive",
          "screen",
        ],
      },
    ],
    // "no-descending-specificity": null
  }
}

Discussion