設定不要で簡単にNode.jsアプリケーション構築できるZero Serverを試してみた

Zero Serverについて公式ページを読んで試したみたという内容です。
詳しく知りたい方は公式を参照するようお願いします。
間違いなどありましたらご指摘お願いいたします。 :bow:

- https://zeroserver.io/
- https://github.com/remoteinterview/zero

# Zero Server とは

※githubのreadmeの説明の部分をgoogle翻訳↓

> Zeroは現代のWeb開発を単純化するためのWebフレームワークです。 パッケージ管理やルーティングを気にせずにアプリケーションを構築できます。 Node.js、React、HTML、MDX、および静的ファイルを組み合わせてコードを記述し、それらをすべてフォルダーに入れるのと同じくらい簡単です。 ゼロはそれらすべてに役立つでしょう。 作業を簡単にするために、ルーティング、バンドル、およびトランスパイルのための通常のプロジェクト構成がゼロで抽象化されています。

自分でいろいろ設定しなくても、`require('moment')` と書けば、Zero Serverが自動で[moment](https://momentjs.com/)をインストールして、解決してくれます。

# Installation

```bash:bash
npm i zero
```

# Hello World

時刻を教えてくれるアプリケーションを作成する

```js:time.js
const moment = require("moment")

module.exports = (req, res) => {
  var time = moment().format('LT');   // 11:51 AM
  res.send({time: time })
}
```

```bash:bash
npx zero
```

http://localhost:3000/time にアクセスすると、

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/1dedee53-2ff6-54a9-5bc1-4149c840acad.png)

**time**.jsで作成しましたので、localhost:3000/**time** にアクセスすると内容を表示してくれます。

`moment` を自動でインストールして使えているのが確認できました。

---

サーバーを稼働し続けた状態で、`index.jsx` を作成する。

```jsx:index.jsx
import React,{ Component } from 'react'

export default class extends Component {
  static async getInitialProps(){
    const { time } = await fetch("/time").then((resp) => resp.json())
    return { time }
  }

  render() {
    return <p>Current time is: {this.props.time}</p>
  }
}
```

http://localhost:3000/

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/417b22f0-198c-ffb3-a737-5e8536e62537.png)

先ほどの`/time` からjsonを受け取り、jsxも正しく動作しているのが確認できました。

webpackなどの設定をいじる必要がなく、簡単にアプリケーション構築できました!

# Static Files

https://github.com/remoteinterview/zero/tree/master/docs/static

画像やテキストファイルなどの扱いについて

.js, .ts, .jsx, .tsx, .htm, .html, .md, .mdx以外の場合は、プロジェクトディレクトリにファイルを置けばそのまま表示してくれるようでした。

※プロジェクト直下のディレクトリに`nihon-amagaeru.jpg` を置いた場合

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/8cbde562-c8e0-3b27-bf64-dc77f49afca2.png)

# Node.js (.js, .ts)

https://github.com/remoteinterview/zero/tree/master/docs/nodejs

```js:hello.js
module.exports = function(req, res) {
  res.send("Hello");
}
```

Zero は[Express.js](https://expressjs.com/)を使用しているようなので、req, resのリクエスト・レスポンスのオブジェクトはExpressのものと同じ。

---

`./api/login.js` とファイルを設置した場合は `http://localhost:3000/api/login` でアクセスできる

```js:/api/logion.js
module.exports = function(req, res) {
    res.send("Login Api");
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/5dc2c7e5-352c-0e8e-e781-db4157410d13.png)

### パラメータの取得

```js:param-test.js
module.exports = function(req, res) {
    console.log(req.body)
    res.send({body: req.body})
}
```

POST, PUT, PATCH, DELETE でパラメータを問題なく受け取れるようでした。

```bash:bash
$ curl http://localhost:3000/param-test -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "category=1&sort=asc"
{"body":{"category":"1","sort":"asc"}}
$ curl http://localhost:3000/param-test -X POST -H "Content-Type: application/json" -d '{"category":1, "sort":"asc"}'
{"body":{"category":1,"sort":"asc"}}
$ curl http://localhost:3000/param-test -X DELETE -H "Content-Type: application/json" -d '{"category":1, "sort":"asc"}'
{"body":{"category":1,"sort":"asc"}}
```

### Route Rewrites

```js:user.js
module.exports = function(req, res) {
    console.log(req.params)
    res.send({params: req.params})
}
```

`/user/luke`にアクセスした時に、`./user/luke.js`がなかった場合、`req.params`に`['luku']`と設定してくれます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/761533e7-035d-427f-4015-fc1c376e9e08.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/2f03ccb8-2b9e-2b96-6bb3-240017225a88.png)


### TypeScript

`.ts`ファイルにすると、TypeScriptとして動作させることができる

```ts:hello-ts.ts
import * as express from "express";

function handler(req: express.Request, res: express.Response) {
  res.send("Hello TypeScript")
}
export default handler
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/5ebd8587-0805-b39a-ef69-d25130d0ccad.png)


# React

https://github.com/remoteinterview/zero/tree/master/docs/react

```jsx:hello-react.jsx
export default () => <h1>Hello React</h1>
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/b9aeb110-aeb2-f97d-a9fb-712443dab3ba.png)

### Populating `<head>`

```jsx:react-helmet.jsx
import {Helmet} from "react-helmet";

module.exports = () => (
  <div>
    <Helmet>
        <meta charset="UTF-8" />
        <title>Page Title</title>
        <link rel="canonical" href="http://mysite.com/example" />
    </Helmet>
    <h1>Hello World</h1>
  </div>
)
```


`react-helmet`が使えるので、metaタグなどの扱いも簡単です

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/f6879096-a596-213c-bb76-92c7f3501a30.png)

### Importing CSS/Sass

cssとscssがサポートされているようです。

```jsx:react-style
import "./style.scss"
module.exports = ({name}) => (
  <h1>Hello {name}</h1>
)
```

```style.scss
body {
    h1 {
        color: blue;
    }
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/73c2cdc1-cbdd-d4a5-79ca-7ab037dc4655.png)


### TypeScript

`.tsx`とするとことで使用することができました。

```tsx:react-ts.tsx
import * as React from "react";

export default class HelloWorld extends React.Component<{}, {}> {
    render() {
       return (<b>Hello TypeScript</b>);
    }
}
```

# HTML (.htm, .html)

バンドラーはparcelが使われているとのことです。なので`<script>`タグの`src`から自動で解析してくれました。

```html:html-test.html
<!DOCTYPE html>
<html lang="en">
<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">
    <script src="./style.js"></script>
    <title>Document</title>
</head>
<body>
    <h1>Hello</h1>
</body>
</html>
```

```js:style.js
import "./style.scss";
```

```scss:style.scss
body {
    h1 {
        color: blue;
    }
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/20d5b975-af08-e8e0-239b-dcd0f45aa1d7.png)

# Markdown / MDX (.md, .mdx)

自動で`.md`ファイルをhtmlに変換してくれる

```md:markdown.md
# Markdown in Zero
Zero renders `.md` files too.
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/413a27ce-79e6-7d83-15dc-b01e9823dd98.png)

```md:mdx-test.mdx
import Btn from "./component/btn"

# Hello, world!

<Btn />
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/142910/900959b9-39e6-3410-0cd7-088295f0bd10.png)

---

[自分で試したコード](https://github.com/okumurakengo/00009_zero)

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