nextjsでmaterial-uiを導入した時にコンパイルエラーでハマった話

# はじめに
next.jsでmaterial-uiで使用されているフォントを導入した時に以下のコンパイルエラーでハマったので解法を記録しておきます。

```:compile_error
./node_modules/typeface-roboto/index.css 2:0
Module parse failed: Unexpected character '@' (2:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| /* roboto-100normal - latin */
> @font-face {
|   font-family: 'Roboto';
|   font-style: normal;
```

# 結論
このissueの通りに対処すれば動きます。
https://github.com/zeit/next-plugins/issues/432

```bash
yarn add @zeit/next-css
yarn add -D url-loader
```

```js:next.config.js
const withCSS = require("@zeit/next-css");
module.exports = withCSS({
  webpack: config => {
    config.module.rules.push({
      test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
      use: {
        loader: "url-loader",
        options: {
          limit: 100000,
          name: "[name].[ext]"
        }
      }
    });
    return config;
  }
});
```

# コンパイルエラー発生までの流れ

## nextjs導入

公式のDocに従ってnextjsを導入します。
https://nextjs.org/learn/basics/getting-started/setup

```bash
yarn init -y
yarn add react react-dom next
mkdir pages
```

```json:package.json
"scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
},
```

```js:pages\index.js
const Home = () => <h1>Hello World!</h1>;

export default Home;
```

```bash
yarn dev
```

ここまでは何の問題も無くHelloWorldが表示されるはずです。

## material-ui導入

続いてmaterial-uiを導入
公式が入れろと言ってるのでフォントも一緒に入れる
https://material-ui.com/getting-started/installation/

```bash
yarn add @material-ui/core typeface-roboto
```

```js:pages\index.js
+ import "typeface-roboto";
```

ここで`yarn dev`を行うと以下のコンパイルエラーが発生します。

```:compile_error
./node_modules/typeface-roboto/index.css 2:0
Module parse failed: Unexpected character '@' (2:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| /* roboto-100normal - latin */
> @font-face {
|   font-family: 'Roboto';
|   font-style: normal;
```

# 解決法

結論で貼ったissueの通りに対処すると無事私達のHelloWorldが帰ってきます。
再度掲示します。

```bash
yarn add @zeit/next-css
yarn add -D url-loader
```

```js:next.config.js
const withCSS = require("@zeit/next-css");
module.exports = withCSS({
  webpack: config => {
    config.module.rules.push({
      test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
      use: {
        loader: "url-loader",
        options: {
          limit: 100000,
          name: "[name].[ext]"
        }
      }
    });
    return config;
  }
});
```

# なぜ治るのか
これで終わってはissueを貼っただけで味気ないのでなぜこれで治るのかを考えます。

`next.config.js`で何をしているのかを考えます。
`test`に記載した正規表現にマッチするファイルはパースの際に`use`内に記載したloaderを使う といったconfigを作成しwebpackに設定する、といった事をしています。

今回導入した`typeface-roboto`の`index.css`を見るとわかるように`@font-face`を使って拡張子が`woff`, `woff2`のファイルを読み込んでいます。

```css:typeface-roboto\index.css
/* roboto-100normal - latin */
@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-display: swap;
  font-weight: 100;
  src:
    local('Roboto Thin '),
    local('Roboto-Thin'),
    url('./files/roboto-latin-100.woff2') format('woff2'), /* Super Modern Browsers */
    url('./files/roboto-latin-100.woff') format('woff'); /* Modern Browsers */
}
```
webpackはデフォルトだとこのような特殊な拡張子のファイルは上手くパースできません。

よってこのように`next.config.js`で明示的に特殊なparser(今回は`url-loader`)を指定してあげることによってパースを成功させることができます。

勿論今回parserが必要なのは`woff`, `woff2`だけなので正規表現にこれら2つだけ記載した場合でも動きます。

webpackのloaderについての解説はこの方の記事がわかりやすかったです。
https://qiita.com/takano-h/items/1a6a5a0b9d25a677f7d2