PostCSSをwebpackでサクッと動かせるサンプル

間違っているなどありましたらご指摘お願いいたします:bow:

**参考**

- [最新版で学ぶwebpack 4入門 - スタイルシート(CSSやSass)を取り込む方法 - ICS MEDIA](https://ics.media/entry/17376#postcss-autoprefixer)
- [webpack 4 入門 - Qiita](https://qiita.com/soarflat/items/28bf799f7e0335b68186)
- [npm-scriptでPostCSS - Qiita](https://qiita.com/axcelwork@github/items/c546e1c8cbe20fd99e4a)
- [style-loaderを使ってstylesheetをrequireする - Qiita](https://qiita.com/nekobato/items/43122e0ff7d260b2b0cc)
- [PostCSSで別ファイルをimportする際の注意点 - Qiita](https://qiita.com/kikunantoka/items/8fad8917ae8049a1bed4)

# 確認バージョン

- webpack 4

# 最小限で動かす

参考:[michael-ciniawsky/postcss-load-config: Autoload Config for PostCSS](https://github.com/michael-ciniawsky/postcss-load-config)

[サンプルはこちら](https://github.com/okumurakengo/00006_postcss_webpack_example/tree/master/sample_01)

```bash:bash
npm init -y
npm i -D webpack webpack-cli style-loader css-loader postcss-loader postcss-nested
```

```js:./webpack.config.js
module.exports = {
    mode: 'development',
    module: {
        rules: [{
            test: /\.pcss/,
            use: [
                'style-loader',
                'css-loader',
                {
                    loader: 'postcss-loader',
                    options: { plugins: [ require('postcss-nested') ] },
                },
            ],
        }]
    }
};
```

loaderは`use: []`の配列の下から順に適用されていきます。

今回の例では、`.pcss` ファイルに対して、 

1. `postcss-loader` がプラグインを使用して、cssでネストした書き方をプレーンなcssに変換
2. `css-loader` でcssをjsにバンドルする機能
3. `style-loader` で `<head>` の最後尾に `<style>` を追加する機能

という順で適用されていきます

```js:./src/index.js
import './style.pcss';
```

```scss:./src/style.pcss
p {
    color: seagreen;
    span {
        color: deepskyblue;
    }
}
```

```html:./index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="dist/main.js"></script>
</head>
<body>
    <p>Heloo <span>World!</span></p>
</body>
</html>
```

```bash:bash
npx webpack
```

PostCSSを使ってcssをネストして書くことができました

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/8e971618-e4ef-d7ba-60fc-005ce890fae3.png)


# PostCSSの設定を別ファイルにする

[サンプルはこちら](https://github.com/okumurakengo/00006_postcss_webpack_example/tree/master/sample_02)

```bash:bash
npm init -y
npm i -D webpack webpack-cli style-loader css-loader postcss-loader postcss-nested
```

### `.postcssrc.json`

```js:./webpack.config.js
module.exports = {
    mode: 'development',
    module: {
        rules: [{
            test: /\.pcss/,
            use: ['style-loader', 'css-loader', 'postcss-loader'],
        }]
    }
};
```

```json:./.postcssrc.json
{
    "plugins": {
        "postcss-nested": {}
    }
}
```

```bash:bash
npx webpack
```

先ほどと同じように実行されることが確認できました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/712bf37a-9a0c-b98f-dd1e-f49e0e039e12.png)


### `.postcssrc.yml`

yamlで記述することもできます

```yaml:.postcssrc.yml
plugins:
  postcss-nested: {}
```

### `.postcssrc.js` or `postcss.config.js`

設定ファイル内にロジックが必要な場合はこちらで記述する

この例ではロジックはないですが、以下のようにするとjsonやyamlの設定ファイルと同じように動かすことができました

```js:.postcssrc.js
module.exports = {
    plugins: {
        'postcss-nested': {}
    }
};
```

```js:postcss.config.js
module.exports = {
    plugins: {
        'postcss-nested': {}
    }
};
```

# cssファイルにする

[サンプルはこちら](https://github.com/okumurakengo/00006_postcss_webpack_example/tree/master/sample_03)

jsにcssをバンドルするという方法でやってきましたが、
最終的にcssファイルを出力し、htmlからlinkタグでcssを取得する方法でやってみます

参考

- https://github.com/ics-creative/170330_webpack/blob/master/tutorial-sass-extract-plugin/webpack.config.js
- [node.js - With Webpack, is it possible to generate CSS only, excluding the output.js? - Stack Overflow](https://stackoverflow.com/questions/29760894/with-webpack-is-it-possible-to-generate-css-only-excluding-the-output-js)

```bash:bash
npm init -y
npm i -D webpack webpack-cli css-loader postcss-loader postcss-nested extract-text-webpack-plugin@next
```

↑ webpack 4だと、`extract-text-webpack-plugin` だとうまく動かないため、 `extract-text-webpack-plugin@next` をインストールするようにしましょう ※2019/02/23現在


```js:./webpack.config.js
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    mode: 'development',
    entry: './src/style.pcss',
    output: {
        path: `${__dirname}/dist`,
        filename: '[name].css', // 生成するjsファイル名
    },
    module: {
        rules: [{
            test: /\.pcss/,
            use: ExtractTextPlugin.extract({
                use: [
                    'css-loader',
                    {
                        loader: 'postcss-loader',
                        options: { plugins: [ require('postcss-nested') ] },
                    },
                ]
            }),
        }]
    },
    plugins: [
        new ExtractTextPlugin('[name].css'), // cssファイルを生成されたjsファイルと同じ名前にし上書きする -> cssファイルのみ出力という結果になる
    ],
};
```

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="dist/main.css">
</head>
<body>
    <p>Heloo <span>World!</span> from css file</p>
</body>
</html>
```

cssファイルを出力しhtmlから読み込むことができました

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/797e6b66-9325-f592-b452-50da49e18305.png)


# ソースマップを有効にする

[サンプルはこちら](https://github.com/okumurakengo/00006_postcss_webpack_example/tree/master/sample_04)

```bash:bash
npm init -y
npm i -D webpack webpack-cli style-loader css-loader postcss-loader postcss-nested
```

```js:./webpack.config.js
module.exports = {
    mode: 'development',
    module: {
        rules: [{
            test: /\.pcss/,
            use: [
                'style-loader',
                {
                    loader: 'css-loader',
                    options: {
                        sourceMap: true,
                    }
                },
                {
                    loader: 'postcss-loader',
                    options: { 
                        sourceMap: true,
                        plugins: [ require('postcss-nested') ] 
                    },
                },
            ],
        }]
    }
};
```

ソースマップが有効になりました

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/f2f8caa5-1cc5-b0d2-ccf9-b53de9e7be16.png)


# sassと併用する

[サンプルはこちら](https://github.com/okumurakengo/00006_postcss_webpack_example/tree/master/sample_05)

```bash:bash
npm init -y
npm i -D webpack webpack-cli style-loader css-loader postcss-loader autoprefixer sass-loader node-sass 
```

```js:./webpack.config.js
module.exports = {
    mode: 'development',
    module: {
        rules: [{
            test: /\.scss/,
            use: [
                'style-loader',
                'css-loader',
                {
                    loader: 'postcss-loader',
                    options: { plugins: [ require('autoprefixer') ] },
                },
                'sass-loader',
            ],
        }]
    }
};
```

```scss:./src/style.scss
body {
    background: yellowgreen;
    div {
        transform: scale(.7);
    }
}
```

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="dist/main.js"></script>
</head>
<body>
    <div>BOX</div>
</body>
</html>
```

scssとpostcssからのautoprefixerを併用できました

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/d30cd31c-d8b7-d4b2-edd9-df7cb01a00a5.png)

# `css-loader` の `@import` を使う際の注意点

### `@import`の動作を確認

- まず`css-loader`などを使わない状態の`@import`の動作を確認

```css:sample.css
@import "import.css";

p {
    font-weight: bold;
}
```

```css:import.css
body {
    background: yellowgreen;
}
```

sample.cssとimport.cssで2回通信が発生しています

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/5f11f73c-e4ae-7b3d-7e4e-c1cd54b46952.png)


- 次に`css-loader`を使った場合の`@import`の動作を確認

```bash:bash
npm init -y
npm i -D webpack webpack-cli style-loader css-loader postcss-loader postcss-nested
```

```js:./webpack.config.js
module.exports = {
    mode: 'development',
    module: {
        rules: [{
            test: /\.css/,
            use: ['style-loader', 'css-loader'],
        }]
    }
};
```

```js:./src/index.js
import './sample.css';
```

```css:./src/sample.css
@import "import.css";

p {
    font-weight: bold;
}
```

```css:./src/import.css
body {
    background: yellowgreen;
}
```

```bash:bash
npx webpack
```

通信は、`./dist/main.js`を取得する1回だけとなり、`<style>`タグが2つ追加されるという動きになります

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/45e35587-2982-8fed-007a-2406acfbe1fd.png)

- この`@import`をpostcssと使うときにデフォルトだとうまくいきません

```js:./webpack.config.js
module.exports = {
    mode: 'development',
    module: {
        rules: [{
            test: /\.pcss/,
            use: [
                'style-loader',
                'css-loader',
                {
                    loader: 'postcss-loader',
                    options: { plugins: [require('postcss-nested')] },
                },
            ],
        }]
    }
};
```

```js:./src/index.js
import './sample.pcss';
```

```scss:./src/sample.pcss
@import "import.pcss";

div {
    h1 {
        color: green;
    }
}
```

```scss:./src/import.pcss
div {
    h2 {
        color: red;
    }
}
```

```bash:bash
npx webpack
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/0652069a-8124-7f0e-3c2d-fefa7d245e1f.png)

このように、`postcss-nested`は`sample.pcss`には適用されますが、`import.pcss`には適用されていません。
プレーンなcssの構文としては間違っているため、h2の`color:red;`も反映されていません。

---

### `importLoaders`を設定するとうまくいく

```js:./webpack.config.js
module.exports = {
    mode: 'development',
    module: {
        rules: [{
            test: /\.pcss/,
            use: [
                'style-loader',
                {
                    loader: 'css-loader',
                    options: {
                        importLoaders: 1, // importするときに適用するloaderの数を設定、sassとpostcssを使っていた場合は「2」と設定する
                    },
                },
                {
                    loader: 'postcss-loader',
                    options: { plugins: [require('postcss-nested')] },
                },
            ],
        }]
    }
};
```

```bash:bash
npx webpack
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/bc1c37f5-1b32-a7b5-e39f-e908fc767dd2.png)

`@import`で取得した内容にも、`postcss-loader`が適用されたことが確認できました。

[サンプルはこちら](https://github.com/okumurakengo/00006_postcss_webpack_example/tree/master/sample_06)

参考:[Clarify importLoaders documentation? · Issue #228 · webpack-contrib/css-loader](https://github.com/webpack-contrib/css-loader/issues/228)

### `postcss-import`を使っても良い

`postcss-import`を使ってimportすることでも、↑の問題を回避することができるようでした

```bash:bash
npm init -y
npm i -D webpack webpack-cli style-loader css-loader postcss-loader postcss-nested postcss-import
```

```js:./webpack.config.js
module.exports = {
    mode: 'development',
    module: {
        rules: [{
            test: /\.pcss/,
            use: [
                'style-loader',
                'css-loader',
                {
                    loader: 'postcss-loader',
                    options: { plugins: [
                        require('postcss-import'),
                        require('postcss-nested'), 
                    ]},
                },
            ],
        }]
    }
};
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/66f21166-0dd9-1a42-da92-1d5714483237.png)

[サンプルはこちら](https://github.com/okumurakengo/00006_postcss_webpack_example/tree/master/sample_07)

---

最後まで読んでいただいてありがとうございましたm(_ _)m