Preactをはじめる

# はじめる

この記事は preact の動作するプロジェクトの初期状態を組み立てるところまでです。preactならびに React に関するプログラミングの知見は一つも含まれません。ご注意下さい。

preactはサイズ軽量な React.js 「ぽい」ライブラリです。公式でも「Reactの再実装ではない」とうたわれていますが、まず同等の書き味が楽しめます。(JSXによるものが大きい気もする)

## プロジェクトを作成する

```bash
mkdir preact-entry
cd preact-entry
npm init -y
```

## 関連ライブラリのインストール

### webpackのインストール

```sh
npm install --save-dev webpack webpack-cli webpack-dev-server
```

### babel のインストール

オブジェクトスプレッド代入とかクラスプロパティとか欲しい気がするので preset-state-2 を入れています。`babel-preset-preact`は更新1年前ですがまあいいでしょう。(やってること[これだけだし](https://github.com/developit/babel-preset-preact/blob/master/index.js))

```sh
npm install --save-dev babel-core babel-loader babel-preset-env
npm install --save-dev babel-preset-stage-2
npm install --save-dev babel-preset-preact
```

### preact のインストール

```sh
npm install --save-dev preact
```

### eslint のインストール

JSX周りのルールを使いたいので `eslint-plugin-react` を入れます。

```sh
npm install --save-dev eslint eslint-config-eslint eslint-plugin-react
```

## 設定ファイルの作成

### webpack.config.js

エントリポイントは `./src/index.js`、出力先は `dist/`、開発用サーバのベースディレクトリは `public/` とします。

```js
module.exports = {
  entry: [
    './src/index.js'
  ],
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: ['babel-loader']
      }
    ]
  },
  resolve: {
    extensions: ['*', '.js', '.jsx']
  },
  output: {
    path: __dirname + '/dist',
    publicPath: '/',
    filename: 'bundle.js'
  },
  devServer: {
    contentBase: './public'
  }
};
```

### .babelrc

```json
{
  "presets": [
    "env",
    "preact",
    "stage-2"
  ]
}
```

### .eslintrc.js

ベースとして `eslint:recommended` を利用し、カスタマイズする方針でいきます。

`react/jsx-uses-react` と `react/jsx-uses-vars` あたりをまず追加します。`no-console` はデバッグ時にほしいので残す。`no-empty-pattern` は props とか state とりあえず使わないけど消さないパターンが多いので残す。・・・などなど。とりあえずこのくらいあれば違和感はないかと。

```js
module.exports = {
  extends: "eslint:recommended",
  env: {
    browser: true,
    commonjs: true,
    es6: true
  },
  parser: "babel-eslint",
  parserOptions: {
    sourceType: "module",
    ecmaFeatures: {
      jsx: true
    }
  },
  rules: {
    "no-console": "off",
    "no-empty-pattern": "off",
    "linebreak-style": ["error", "unix"],
    "react/jsx-no-bind": ["error", { "ignoreRefs": true }],
    "react/jsx-no-duplicate-props": "error",
    "react/self-closing-comp": "error",
    "react/prefer-es6-class": "error",
    "react/no-string-refs": "error",
    "react/require-render-return": "error",
    "react/jsx-uses-react": "error",
    "react/jsx-uses-vars": "error",
  },
  plugins: [
    "react"
  ],
  settings: {
    react: {
      pragma: "h"
    }
  }
}
```

### .eslintignore

VSCodeなどで webpack.config.js を開いた時にいちいち指摘がされて嫌なので `.eslintignore` にチェック対象外となるファイルについて書いておきます。

```
webpack.config.js
dist/*
```

## プログラミング

###  public/index.html

以下のような index.html を作って public/ 以下に置きます。

```html
<html>
<head>
  <title>Preact Entry</title>
  <script src="/bundle.js" ></script>
</head>
<body>
  <div id="mount"></div>
</body>
</html>
```

### src/index.js

以下のようにしました。

```js
import { h, render } from "preact";

/**
 *
 * @param {props} props
 * @param {state} state
 */
const Hello = ({ }, { }) => <div>Hello Preact</div>;

document.addEventListener("DOMContentLoaded", () => {
    render(
        <Hello />,
        document.getElementById("mount")
    );
});
```

### package.json 

実行スクリプトを用意します

```
  "scripts": {
    "eslint": "eslint src/",
    "start": "webpack-dev-server --config ./webpack.config.js --mode development"
  },
```

## 実行します

```sh
npm run start
```

<img width="307" alt="スクリーンショット 2018-04-25 15.11.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/17911/0f7f671c-7f0f-716e-b66a-e9543db83288.png">


動いた。よしよし。

## まとめ

この段階で build した結果がだいたいディスク上で10kbを切るくらいです。Mac標準の gzip で圧縮すると 3.8KB。

```
$ ls -lh dist/
total 24
-rw-r--r--  1 ma2saka  staff   9.5K  4 25 14:33 bundle.js
-rw-r--r--  1 ma2saka  staff   3.8K  4 25 14:33 bundle.js.gz
```

「3kb」を標榜するのも納得のサイズ感かな?