20200623のReactに関する記事は8件です。

Next.jsを使って、医師国家試験の勉強ノートを公開するブログを作った話

Next.jsを使って、医師国家試験の勉強ノートを公開するブログを作った話

表題の通りです。まずは完成品とレポジトリのURLをどうぞ。

サイト:https://chilvary-beta.vercel.app

GitHub:https://github.com/yokonao/chilvary-beta

作ったきっかけ

next.jsの公式チュートリアル(URLは以下)をやったら、構築の容易さとSPAのページ遷移の速さに感動したので。これで自分のブログ作ったら超便利じゃない?と思いました。単純なページ公開だけならバックエンドなしでも可能です。
https://nextjs.org/learn/basics/create-nextjs-app?utm_source=next-site&utm_medium=homepage-cta&utm_campaign=next-website

アーキテクチャ

アーキテクチャっていうのは大げさすぎるかもしれません。

  1. ローカルPCで書いたMarkdownファイルを作成
  2. MarkdownファイルをAWS S3にアップロード
  3. S3のデータを引っ張ってきて、静的サイトとしてビルド

Next.jsとは全く関係ありませんが、Markdownファイルのバージョン管理とアップロードは完全自動化しています。作業終了後Alfredをちょっと立ち上げてAppleScriptを起動すればアップロードが完了するようにしました。(AppleScriptでgit pushしてgithub actionsでS3にアップロード)。この話はまた別でしたい。

メリット

  • SPAなのでページ遷移はほぼ0秒
  • 超優秀なMarkdownエディタTyporaの力を借りることができる

参考:https://qiita.com/4_mio_11/items/223326c3289f6b2c2a07

実際の記事にはどんなこと書いてんの?

クエスチョンバンク(QB)を解きながら、疑問に思った点を調べてMarkdownファイルにまとめる。国試の勉強は長期戦なので、1年後の自分に向けて書いてます。

スタイルに関しては、Typoraのテーマで使用されているcssファイルとBulmaを併用してます。記事をローカルで作成した時とほぼ同じ見た目で公開しつつ、ヘッダーなどを作る際はBulmaのコンポーネントを利用できるになっています。

チュートリアルから進化している点

S3のディレクトリ構成が完成品のブログにそのまま反映されています。説明が難しいですがサイトを一度巡回していただければ、意図が伝わるはず...

本当に手元で作成したフォルダがそのままwebサイトになるイメージです。

Next.jsのすごいところ

このwebサイト、markdownファイルの中身をNext.jsに渡してあげれば成立するので以下のような拡張もできると思います。

  • データの置き場所をS3からデータベースにする

  • Markdown形式で記事をアップロードできるwebアプリを作成してS3を介してつなぐ

メディアサイトのようなものを作成しようとすると、認証機能など難しい点も出てくるでしょう。しかし、ローカルで作成した文書をSPAとして公開できるサイトをこれだけ簡単に自分で1から作れてしまうのは、Next.js様様かな、と感じます。もちろんGitHub Pagesなどもっと楽な選択肢もありますが、SPAや自由にカスタマイズできるというメリットは十分あると思います。

個人的には自分で見返す際もページ遷移に時間をとられないのでストレスフリーで気持ちいいです。普段やる気にならない勉強も記事作成という遊び感覚でできるようになりましたし。

今後

現在は、ビルド時に全てのページを静的に作成しているので、記事を追加・変更する際は再ビルドが必要になります。

しかし最近、Next.jsは静的なwebサイトに動的なページ更新機能を搭載できるようになりました。Incremental Static Regenerationというやつです。この機能を使いたかったのですが、現在はバグが存在するようなので実現できませんでした。

Next.jsのレポジトリではこのバグに関するissueに最優先事項のラベルがつけられていたので、修正がきたら導入したいと思っています。これさえ導入できれば、Markdownファイルの保存から公開までがほぼ自動化できる...

補足

Incremental Static Regenerationについては以下のサイトの説明が超わかりやすいです。(英語ですけど...)

https://arunoda.me/blog/what-is-nextjs-issg

件のバグのissue

https://github.com/vercel/next.js/issues/12851

https://github.com/vercel/next.js/issues/14382

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Next.jsを使って医師国家試験の勉強ノートを公開するブログを作った話

Next.jsを使って医師国家試験の勉強ノートを公開するブログを作った話

表題の通りです。まずは完成品とレポジトリのURLをどうぞ。

サイト:https://chilvary-beta.vercel.app

GitHub:https://github.com/yokonao/chilvary-beta

作ったきっかけ

next.jsの公式チュートリアル(URLは以下)をやったら、構築の容易さとSPAのページ遷移の速さに感動したので。これで自分のブログ作ったら超便利じゃない?と思いました。単純なページ公開だけならバックエンドなしでも可能です。
https://nextjs.org/learn/basics/create-nextjs-app?utm_source=next-site&utm_medium=homepage-cta&utm_campaign=next-website

アーキテクチャ

アーキテクチャっていうのは大げさすぎるかもしれません。

  1. ローカルPCで書いたMarkdownファイルを作成
  2. MarkdownファイルをAWS S3にアップロード
  3. S3のデータを引っ張ってきて、静的サイトとしてビルド

Next.jsとは全く関係ありませんが、Markdownファイルのバージョン管理とアップロードは完全自動化しています。作業終了後Alfredをちょっと立ち上げてAppleScriptを起動すればアップロードが完了するようにしました。(AppleScriptでgit pushしてgithub actionsでS3にアップロード)。この話はまた別でしたい。

メリット

  • SPAなのでページ遷移はほぼ0秒
  • 超優秀なMarkdownエディタTyporaの力を借りることができる

参考:https://qiita.com/4_mio_11/items/223326c3289f6b2c2a07

実際の記事にはどんなこと書いてんの?

クエスチョンバンク(QB)を解きながら、疑問に思った点を調べてMarkdownファイルにまとめる。国試の勉強は長期戦なので、1年後の自分に向けて書いてます。

スタイルに関しては、Typoraのテーマで使用されているcssファイルとBulmaを併用してます。記事をローカルで作成した時とほぼ同じ見た目で公開しつつ、ヘッダーなどを作る際はBulmaのコンポーネントを利用できるになっています。

チュートリアルから進化している点

S3のディレクトリ構成が完成品のブログにそのまま反映されています。説明が難しいですがサイトを一度巡回していただければ、意図が伝わるはず...

本当に手元で作成したフォルダがそのままwebサイトになるイメージです。

Next.jsのすごいところ

このwebサイト、markdownファイルの中身をNext.jsに渡してあげれば成立するので以下のような拡張もできると思います。

  • データの置き場所をS3からデータベースにする

  • Markdown形式で記事をアップロードできるwebアプリを作成してS3を介してつなぐ

メディアサイトのようなものを作成しようとすると、認証機能など難しい点も出てくるでしょう。しかし、ローカルで作成した文書をSPAとして公開できるサイトをこれだけ簡単に自分で1から作れてしまうのは、Next.js様様かな、と感じます。もちろんGitHub Pagesなどもっと楽な選択肢もありますが、SPAや自由にカスタマイズできるというメリットは十分あると思います。

個人的には自分で見返す際もページ遷移に時間をとられないのでストレスフリーで気持ちいいです。普段やる気にならない勉強も記事作成という遊び感覚でできるようになりましたし。

今後

現在は、ビルド時に全てのページを静的に作成しているので、記事を追加・変更する際は再ビルドが必要になります。

しかし最近、Next.jsは静的なwebサイトに動的なページ更新機能を搭載できるようになりました。Incremental Static Regenerationというやつです。この機能を使いたかったのですが、現在はバグが存在するようなので実現できませんでした。

Next.jsのレポジトリではこのバグに関するissueに最優先事項のラベルがつけられていたので、修正がきたら導入したいと思っています。これさえ導入できれば、Markdownファイルの保存から公開までがほぼ自動化できる...

補足

Incremental Static Regenerationについては以下のサイトの説明が超わかりやすいです。(英語ですけど...)

https://arunoda.me/blog/what-is-nextjs-issg

件のバグのissue

https://github.com/vercel/next.js/issues/12851

https://github.com/vercel/next.js/issues/14382

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactの問い合わせフォームの作成

プログラミングの勉強日記

2020年6月23日 Progate Lv.146
React Ⅳ

問い合わせフォームの作成

 今回はContactFormというコンポーネントを作成して作る。

React7.pngReact8.png

 フォームのJSXはHTMLとは違う書き方をするので気を付ける。フォーム全体は<form>タグで囲む。inputタグは<input />、textareaタグは<textarea />と書く。送信ボタンHTML同様にinputタグを使い、type='subimit'を指定する。表示名を変えたい場合にはvalue='表示名'とする。

<form>
  <textarea />
  <input type='submit' />
</form>

送信完了メッセージの作成

 フォームが送信されたかどうかはstateで管理する。そのためにisSubmittedという真偽値型のstateを用意する。falseのときはフォームをtrueのときは送信完了メッセージを表示する。なので、初期値はfalseである。

ContactForm.js
constructor(props){
  super(props);
  this.state={isSubmitted:false};
}
...

render(){
  let contactForm;
  if(this.state.isSubmitted){
    contactForm= //送信完了メッセージのJSX(※()で囲む)
  }else{
    contactForm= //フォームのJSX
  }
  ...
  return(
    <div>{contactForm}</div>
  );
  ...

onSubmitイベント

 フォームが送信されたときに処理を実行するには、formのタグに対してonSubmitイベントを指定する。

<form onSubmit = [()=>{処理}}> ... </form>

 stateの値を更新するメソッドを作成して、フォームの送信時に呼び出す。

ContactForm.js
//1.stateの値を更新するメソッドの定義
handleSubmit(){
  this.setState({isSubmitted:true});
}
...
render(){
  //2.フォーム送信時にメソッドを呼び出す
  <form onSubmit={()=>{this.handleSubmit()}}>
  ...

問い合わせフォームを作成する

ContactForm.js
import React from 'react';

class ContactForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isSubmitted: false,
    };
  }

  handleSubmit(){
    this.setState({isSubmitted:true})
  }

  render() {
    let contactForm;
    if (this.state.isSubmitted) {
      contactForm = (
        <div className='contact-submit-message'>
          送信完了
        </div>
      );
    } else {
      contactForm = (
        <form  onSubmit={()=>{this.handleSubmit()}} >
          <p>メールアドレス(必須)</p>
          <input />
          <p>お問い合わせ内容(必須)</p>
          <textarea />
          <input
            type='submit'
            value='送信'
          />
        </form>
      );
    }

    return (
      <div className='contact-form'>
        {contactForm}
      </div>
    );
  }
}

export default ContactForm;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

wasm-pack + WebWorker + react-scripts

前提

  • 重い計算を Rust + WebAssembly でやる
  • WebAssembly のパッケージは wasm-pack でビルドする
  • WebAssembly は WebWorker で動かす
  • アプリは React で書く
  • アプリの設定を頑張りたくないので react-scripts (create-react-app) を使う

react-app-rewired

react-scripts では、WebWorker と WebAssembly のロードができないので設定する必要がある。
react-scripts で eject せずに設定を追加するために react-app-rewired を使う。

worker-loader では WebWorker から WebAssembly を import できなかったので、workerize-loader を使う。

こんな感じで config-overrides.js を書く。

config-overrides.js
const path = require("path");

module.exports = function override(config, env) {
  config.module.rules.push({
    test: /\.worker\.js$/,
    use: { loader: "workerize-loader" },
  });

  const wasmExtensionRegExp = /\.wasm$/;

  config.resolve.extensions.push(".wasm");

  config.module.rules.forEach((rule) => {
    (rule.oneOf || []).forEach((oneOf) => {
      if (oneOf.loader && oneOf.loader.indexOf("file-loader") >= 0) {
        // Make file-loader ignore WASM files
        oneOf.exclude.push(wasmExtensionRegExp);
      }
    });
  });

  // Add a dedicated loader for WASM
  config.module.rules.push({
    test: wasmExtensionRegExp,
    include: path.resolve(__dirname, "src"),
    use: [{ loader: require.resolve("wasm-loader"), options: {} }],
  });

  return config;
};

これで拡張子が .worker.js のファイルを WebWorker として読み込めるようになる。

package.jsonscripts を以下のように書いておく。

package.json
  "scripts": {
    "build": "react-app-rewired build",
    "start": "react-app-rewired start"
  },

WebWorker の実装

こんな感じで WebWorker を実装する。

example.worker.js
export const twice = async (v) => {
  const { twice } = await import("example");
  return twice(v);
};

example は wasm-pack で作られたパッケージで、dynamic import で読み込む。

workerize-loader では、WebWorkerで呼び出せる関数を named export する。
async/await が使える。

アプリの実装

いい感じにアプリ側を実装する。
workerize-loader で import したモジュールは関数になっていて、呼び出すと関数を取り出すことができる。
関数は Promise を返すようになっている。

App.js
import React, { useState } from "react";
import worker from "./hoge.worker";

const { twice } = worker();

const App = () => {
  const [value, setValue] = useState(1);
  return (
    <div>
      <button
        onClick={() => {
          twice(value).then((result) => {
            setValue(result);
          });
        }}
      >
        click me
      </button>
      <p>{value}</p>
    </div>
  );
};

export default App;

実用例

凸包を計算して描画するプログラムを書いてみた。

https://likr-sandbox.github.io/convex-hull/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker-compose ~volumeの罠~

はじめに

 初投稿です。白菜と申します。プログラミングが趣味のしがない大学生です。先日コードを書いている最中に深めなツボにハマり、色々調べても関連する情報が出てこなかったので投稿させていただきます。

何が起こったのか

 windowsを使っておりまして、wsl2が正式に導入されたと聞き、wsl2上でDocker-desktopを動かしてみようと思い立ちました。環境を整えてかれこれ一か月ほど遊んでいて、己のPCの環境を汚さずに様々な言語に触れられて、激アツやんと思っておりました。dockerで立ち上げたコンテナにvscodeのRemote Developmentを利用して接続し、コンテナ内でコードの編集・デバッグを行っていました。

しかし、問題発生

 それはある日の暮れ、羅生門の下で雨やみを待ちながらコードを書いていた時のことでございます。springbootとかいう何某かがなんかとてもすごいつよいと聞いたので、試しておりました。日本語の公式チュートリアルのいくつかを軽く実装し、springMVCの基礎くらいはカンニングせずに書けるようになりました。調子に乗ってきたので、MySQLと連携させてデータベース処理やってみようと思い、dockerで環境を作りました。具体的には、

  • javaコンテナ
  • MySQLコンテナ
  • phpmyadminコンテナ(データベース管理で楽するため)

の三つをdocker-composeで一つのネットワークとして作りました。ついでに書いたコード保存しときたかったので、volumeでテキトーなディレクトリをjavaコンテナ上にマウントしました。
 しかしいざコードを書いてみると、データベースとの連携がうまくいきません。デバッグの度にデータベース接続エラーを吐き出します。コード自体はチュートリアルのほぼコピペなので、動かないはずがないのです・・・。これはコードじゃなくてdockerに原因があるんじゃないか?

症状

 上記以外にも、他のコンテナでも似たような症状が発生しました。以下はその一覧です。

  • MySQLとの連携がうまくいかない
  • というかおそらく連携用の設定ファイルの編集が反映されていない
  • 手動で反映させたら上手くいった
  • htmlを作成してコントローラと紐づけたのに、Not Foundと言われる
  • React環境を作ったが、yarn startに一分以上かかる
  • yarn start後、ファイルを編集してもブラウザに反映されない

共通しているのはファイルの編集・作成が反映されないということでした。

解決

 色々実験してみたところ、dockerのvloumeに問題があるという結論に達しました。windows上のファイルをvolumeに指定した時に、volume内のファイルの変更がリアルタイムで反映されなくなるようです。なのでvolume指定しなけりゃいいというのも一つの解決ではあるのですが、コードを永続的に保存しておきたい場合、いちいちwindows上にコピーして持ってくるのは手間です。
 
 volumeを使いつつ解決する方法があります。そもそもdocker for windows公式には以下のような記述があります。

Store source code and other data that is bind-mounted into Linux containers (i.e., with docker run -v :) in the Linux filesystem, rather than the Windows filesystem.

「volumeマウントするファイルは、Windows上じゃなくてLinux上に置いといた方がいいよ!」

・・・・・・すみませんでした。
ちらっと見たことはあったんですけど、マウント自体はちゃんと機能してたし、別にWindows上でもよくね?と思っていたんです。まさかこんな変な不具合が出るとは思ってもいなかったんです。

 というわけで、wsl2のLinux上に作ったディレクトリをマウントしてReact環境を作り直したら解決しました。yarn startが20秒になったし、コードを変更したら逐一反映されるようになりました。Reactおもしれえ。

終わりに

 結論、volumeでマウントするディレクトリはLinux上に作っておいた方がいいと思います。開発してる人たちが言ってるんだから多分間違いないです。我流でオラオラしようとしていた私が悪かったです。すみませんでした・・・。
 公式ドキュメントはしっかり読まなきゃダメてことですね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

create-react-appでhot reloadが効かなくなった話

会津大学でプログラム書いてる学生です。

備忘録代わりにcreate-react-appでreact書いてた際にhot reloadが効かなくなった話をします。

もくじ


かんきょう

  • ubuntu 18.04.4 LTS
  • create-react-app 3.3.1
  • react 16.13.1 くらい

あらすじ

久々にcreate-react-appでなんか作るか!と思いコーディング。
この際typescriptも入れよう!と思い途中からTypescriptを導入。
日をまたいで、さぁコーディングするかとnpm run startしたらホットリロードが効かないことに気づく。
なんかわからんけど効かない。
おそらく途中からtypescriptを導入したので、そのへんで色々あるのかなぁと予想。

しこうさくご

ためしたもの

react-app-rewire-hot-loaderを導入

  • react-app-rewire
  • react-hot-loaderみたいなのも導入する必要があったっぽい

結果として「react-dev-utils/crossspawnがないぞ」って怒られてlocalhost立てられなかった。
解決方法は不明。

create-react-appのプロジェクトを削除し、--typescriptオプションで最初からtypescript対応プロジェクトにした

ウキウキでnpm run startしてもホットリロードは効かず。
プロジェクトファイル消してもっかいつくれば大丈夫でしょ!とか思ったらそうでもなかった。

たいおうさく

上手くいったのは環境変数を追加したらなんとかなりました。
参考記事に感謝。

echo CHOKIDAR_USEPOLLING=true >> .env

参考

Is it possible to get hot-reload with typescript working? #6503
react-app-rewire-hot-loader
vagrant上でcreate-react-appのhot-reloadが効かない場合の対応

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Chefのチュートリアル

このチュートリアルでは、Chefについて学び、Chefを使ってAlibaba Cloud上でシンプルなReact.jsサイトを設定、構築、デプロイする方法を学びます。

本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。

前提条件

このチュートリアルに従うには、以下のものが必要です。

  • 2つのAlibaba Cloud Elastic Compute Service (ECS)インスタンスがUbuntu 16.04でインストールされており、少なくとも2GBのRAMを持っています。これらのインスタンスのうち1つはChefノードに、もう1つはChefサーバに使用されます。また、これらのインスタンスでは、ポート22、80、443が開いていることを確認してください。
  • Chefノードとサーバの両方に使用する完全修飾登録ドメイン(またはFDQN)。Alibaba Cloudドメインを購入するか、Freenomで無料で取得することができます。

Chefを知る

Chefはいくつかの異なるコンポーネントで構成されています。これらのコンポーネントを理解することが重要なので、ここではChefの3つの主要なコンポーネントを簡単に見ていきましょう。

  • Chefサーバー:このコンポーネントは設定データのハブとして機能し、設定レシピ、cookbooks、ノードに適用されるポリシー、Chefによって管理されている各登録ノードを記述するメタデータがすべて保存される中心的な場所として機能します。また、このコンポーネントは、組織内の他のすべてのマシン(またはノード)がデプロイメント設定の目的で使用する中央マシンでもあります。
  • Nodes:ノードの重要なコンポーネントは、物理的または仮想的なもので、Chefを使用して管理できるマシンと理解することができます。Chef-clientは各ノードにインストールされ、各ノードを希望の状態に設定するために使用されます。ノードはchef-clientを使用してchefサーバーと対話し、レシピ、テンプレート、ファイル配布などの設定情報を取得します。
  • Workstation: Chef ワークステーションは、Chef の設定情報を作成または編集する場所です。設定ファイルはChefサーバーにプッシュされ、任意のノードにデプロイできるようになります。ワークステーションからChefサーバーとのやりとりは、knifechefコマンドラインツールを使用して行われます。

環境の設定

いよいよ実用的なことをする時が来ました。このチュートリアルでは、環境を設定し、chef を使って React.js アプリケーションを構築するために必要なツールをインストールします。

ワークステーションの設定

ワークステーションは基本的にはChefの設定の詳細をオーサリングする場所です。ワークステーションはあなたが選択したOSであれば何でも構いません。つまり、Linux、MacOS、Windowsの全てがここで動作することになります。

1.ChefDKパッケージをインストールします。Chef DK (開発キット)には、インフラストラクチャの開発とテストに必要なすべてのツールが含まれています。このチュートリアルを書いている時点では、現在の安定版(4.0.60)を使用しています。このリンクをクリックして、お使いのOSに基づいたChef DKをダウンロードしてください。

2.Chef DKをインストールしたことを確認し、コマンドラインからChef DKにアクセスできることを確認します。これを行うには、chef —versionを実行してインストールを確認することができます。

 chef@workstation:~$ chef --version
   Chef Development Kit Version: 4.0.60
   chef-client version: 15.0.300
   delivery version: master
   berks version: 7.0.8
   kitchen version: 2.2.5
   inspec version: 4.3.2
  1. MacおよびLinuxユーザーの場合は、Chef開発キットに含まれているRubyのバージョンがデフォルトのRubyのバージョンとして設定されていることを確認する必要があります。これを行うには、以下の手順に従ってください。
  • ターミナルを開き、which rubyを実行します。以下のような結果が得られるはずです。
   chef@workstation:~$ which ruby
       /usr/bin/ruby
  • chef shell-initサブコマンドを使用して、ChefDKに含まれるRubyをシステムRubyとして設定する必要があります。ChefDKによって使用されるアプリケーションは、ワークステーション上にも存在する可能性のある他のRuby開発ツールから分離することができます。
  chef@workstation:~$ echo 'eval "$(chef shell-init bash)"' >> ~/.bash_profile && source ~/.bash_profile

zshfish、Windows PowerShell (posh) など、bash とは異なるシェルを使用している場合は、SHELL_NAME をシェルに、SHELL_PROFILE をシェルプロファイルに置き換えて、以下のコマンドを実行してください。

 chef@workstation:~$ echo 'eval "$(chef shell-init SHELL_NAME)"' >> ~/.SHELL_PROFILE && source ~/.SHELL_PROFILE
  • もう一度which rubyコマンドを実行して、Chef開発キット版のrubyを使用していることを確認すると、以下のような出力が得られるはずです。
  chef@workstation:~$ which ruby
      /opt/chefdk/embedded/bin/ruby

4.次に、ワークステーション用の react-app-repo という作業ディレクトリを作成する必要があります。このためにchef generate repo repo_nameコマンドを使用することになります。これにより、Chefが必要とするファイルやフォルダ構造が作成されます。

 chef@workstation:~$ chef generate repo react-app-repo && cd react-app-repo

5.ワークステーションの設定が完了したので、Chefサーバーの設定と設定を行います。

Chefサーバーの設定

Chefサーバーを設定するには、以下の手順に従います。

1.ChefサーバーとしてUbuntu 16.04でインストールされたAlibaba Cloud ECSインスタンスをスピンアップし、ポート80、22、443が開いていることを確認します。クラウドでChefサーバを実行している場合は、セキュリティグループを通じてこれらのポートが開いていることを確認します。

2.Chefサーバーには、解決可能なドメインとホスト名が必要です。サーバーのホスト名がパブリックホスト名と一致していることを確認する必要があります。これは、以下のコマンドを実行することで可能です。

  chef@chef_server:~$ echo YOUR_DOMAIN_NAME | xargs sudo hostname

3.学習のために、このチュートリアルのために以下のbashスクリプトを作成しました。これはChef-serverパッケージをダウンロードしてインストールする際に役立つはずです。

  • 以下のスクリプトをサーバ上のパス /tmp/installChefServer.sh にコピーしてください。
   chef@chef_server:~$ sudo vi /tmp/installChefServer.sh

  bash
      #!/usr/bin/env bash

      BOLD='\e[1m'
      GREEN='\e[92m'
      NC='\e[0m'

      updateLinuxPackages() {
        printf "${BOLD}${GREEN}=================================== Updating all packages ============================================ ${NC}\n"
        apt-get update

      }


      createDirectories() {
        if [ ! -d /creds ]; then
          mkdir /creds
        fi
        if [ ! -d /downloads ]; then
          mkdir /downloads
        fi
      }

      downloadAndInstallChefServer() {
        if [ ! -f /downloads/chef-server-core_12.19.26-1_amd64.deb ]; then
          printf "${BOLD}${GREEN}=================================== Downloading the Chef server package... ================== ${NC}\n"
          wget -nv -P /downloads https://packages.chef.io/files/stable/chef-server/12.19.26/ubuntu/16.04/chef-server-core_12.19.26-1_amd64.deb
        fi

        if [ ! $(which chef-server-ctl) ]; then
          printf "${BOLD}${GREEN}=================================== Installing Chef server =================================== ${NC}\n"
          dpkg -i /downloads/chef-server-core_12.19.26-1_amd64.deb
          chef-server-ctl reconfigure

          printf "${BOLD}${GREEN}=================================== Waiting for services ====================================== ${NC}\n"
          until (curl -D - http://localhost:8000/_status) | grep "200 OK"; do sleep 15s; done
          while (curl http://localhost:8000/_status) | grep "fail"; do sleep 15s; done

          printf "${BOLD}${GREEN}============================= Creating user ========================== ${NC}\n"
          # creating user format: chef-server-ctl user-create USER_NAME FIRST_NAME LAST_NAME EMAIL 'PASSWORD' --filename FILE_NAME
          chef-server-ctl user-create admin admin admin admin@example.com 'notsecure' --filename /creds/chefadmin.pem

          printf "${BOLD}${GREEN}============================= Creating oganization with user ========================== ${NC}\n"
          # creating org format: chef-server-ctl org-create SHORT_ORG_NAME 'FULL_ORG_NAME' --association_user USER_NAME --filename FILE_NAME
          chef-server-ctl org-create chef "Chef-learn, Inc." --association_user admin --filename organization-validator.pem

          printf "${BOLD}${GREEN}============================= Adding Web UI for chef  ========================== ${NC}\n"
          chef-server-ctl install chef-manage
          chef-server-ctl reconfigure
          chef-manage-ctl reconfigure --accept-license
        fi

        printf "${BOLD}${GREEN}==================================== Your Chef server is ready! ================================== ${NC}\n"
      }

      main() {
        updateLinuxPackages
        createDirectories
        downloadAndInstallChefServer
      }

      main

  • このスクリプトでは、以下の情報を持つユーザーも作成します。

    • ユーザー名: admin
    • Firstname:admin
    • Lastname: admin
    • 電子メール: admin@example.com
    • パスワード: notsecure
  • 以下のコマンドを実行してスクリプトを実行可能な状態にします。

  chef@chef_server:~$ sudo chmod u+x /tmp/installChefServer.sh
  • 最後にスクリプトを実行します。少し時間がかかるかもしれません。
  chef@chef_server:~$ sudo /tmp/installChefServer.sh

4.ブラウザ上のChefのWebインターフェースにホスト名でアクセスできます。

image.png

ワークステーションがChef Serverと通信するように設定する

ワークステーションとChefサーバー間の通信を確立するために、すでにChefDKに含まれているKnifeユーティリティツールを利用します。

基本的に、Knifeは、Chefサーバーを認証するために2つのファイルを必要とします。

  • knifeの設定ファイル knife.rb には、Chef サーバーの URL、RSA 秘密鍵(SSH 鍵)の場所、cookbookのデフォルトの場所などの情報が含まれています。

  • RSA秘密鍵は、Chefサーバに送信されるすべてのリクエストを認証するために使用されます。公開鍵はChefサーバーが保持し、プライベート鍵はワークステーションが保持します。

ワークステーションとChefサーバー間の通信を確立するには、以下の手順に従ってください。

1.knife configureコマンドを実行して、knifeの設定を作成します。

YOUR-HOST-NAMEをchef-serverドメイン名に、SHORT-ORG-NAMEchefに置き換えます。また、クライアントキーを配置するための出力で指定されたパスをメモしておきます。

  chef@workstation:~$ knife configure
    WARNING: No knife configuration file found. See https://docs.chef.io/config_rb_knife.html for details.
    Please enter the chef server URL: [https://devops1c.mylabserver.com/organizations/chef]: https://YOUR-HOST-NAME/organizations/SHORT-ORG-NAME
    Please enter an existing username or clientname for the API: [user] admin
    *****

    You must place your client key in:
    /home/user/.chef/chefadmin.pem
    Before running commands with Knife

    *****
    Configuration file written to /home/user/.chef/credentials

2.あなたの react-app-repo ディレクトリに knife.rb ファイルを作成して、knife がcookbooksの場所を知っていることを確認する必要があります。

  chef@workstation:~$ mkdir .chef && echo 'cookbook_path ["#{File.dirname(__FILE__)}/../cookbooks"]' >> .chef/knife.rb

また、installChefServer.shスクリプトでユーザーを作成した時に作成したSSH鍵ファイルを、scpコマンドを使ってchef-serverからワークステーションにコピーする必要があります。

Note ~/.chef/admin.pemはクライアントキーを置くために指定されたパスですが、knife configureコマンドの出力で指定されたパスと異なる場合は変更してください。

そして、以下の項目に置き換えてください。

IP-ADDRESS-OR-HOSTNAME は、chef-serverのパブリックIPアドレス/ホスト名に置き換えます。

USERはChefサーバーのユーザー名に置き換えてください。

PATH_TO_YOUR_SSH_KEY は、Chefサーバの ssh-key へのパスに置き換えてください。

   chef@workstation:~$ scp -i PATH_TO_YOUR_SSH_KEY USER@YOUR-IP-ADDRESS-OR-HOSTNAME:/creds/chefadmin.pem ~/.chef/admin.pem

あるいは、サーバへのアクセスを得るための認証手段としてパスワードを使用している場合は、以下のコマンドを実行することもできます。

 chef@workstation:~$ scp USER@YOUR-IP-ADDRESS-OR-HOSTNAME:/creds/chefadmin.pem ~/.chef/admin.pem

3.次に、以下のコマンドを使用してChefサーバーからSSL証明書を取得し、検証する必要があります。

chef@workstation:~$ knife ssl fetch
    WARNING: Certificates from www.mydomainname.com will be fetched and placed in your trusted_cert
    directory (/home/user/.chef/trusted_certs).

    Knife has no means to verify these are the correct certificates. You should
    verify the authenticity of these certificates after downloading.

    Adding certificate for www_mydomainname_com in /home/user/.chef/trusted_certs/www_mydomainname_com.crt

knife ssl checkコマンドを実行して、SSL構成を確認します。

  chef@workstation:~$ knife ssl check
     Connecting to host ec2-34-207-124-26.compute-1.amazonaws.com:443
     Successfully verified certificates from ec2-34-207-124-26.compute-1.amazonaws.com

これでワークステーションの設定が完了し、knifeを使ってChefサーバーに接続できるようになりました。次のパートでは、ノードの設定を行います。

ノードの設定とブートストラップ

Chefで設定を管理する作業を開始する前に、作業するノードが必要になります。これを行うには、Ubuntu 16.04をインストールした別のECSインスタンスを作成し、ワークステーションからKnifebootstrapサブコマンドを利用します。ノードサーバを作成するだけで、ほとんどの作業はworkstationから行われます。

1.Ubuntu 16.04をインストールした別のAlibaba Cloudインスタンスを作成し、ポート80、22、443、3000が開いていることを確認します。react.jsアプリケーションはポート3000で実行されます。

2.以下のコマンドを実行して、ノードサーバのホスト名がパブリックホスト名と一致していることを確認する必要があります。

では、次のように置き換えます。

  • IP-ADDRESS-OR-HOSTNAMEをノードサーバのパブリック IP アドレス/ホスト名に置き換えます。

  • ノードサーバ上のユーザの名前を持つUSER

  • PATH_TO_YOUR_SSH_KEY にノードサーバの ssh-key へのパスを指定します。

 chef@workstation:~$ ssh -i PATH_TO_YOUR_SSH_KEY USER@YOUR-IP-ADDRESS-OR-HOSTNAME 'echo YOUR_DOMAIN_NAME | xargs sudo hostname'

3.ワークステーションから、新しいクラウドサーバーをChefサーバーが管理するノードにブートストラップするには、以下のコマンドを実行します。

以下では、

  • IP-ADDRESS-OR-HOSTNAMEをノードサーバのパブリックIPアドレス/ホスト名に置き換えます。

  • ノードサーバ上のユーザの名前を持つUSER

  • PATH_TO_YOUR_SSH_KEY にノードサーバの ssh-key へのパスを指定します。

  • reactJS-nodenode_nameを指定します。node_nameはノードに与えたい名前であることを理解してください。

 chef@workstation:~$ knife bootstrap IP-ADDRESS-OR-HOSTNAME --connection-user USER --sudo -i PATH_TO_YOUR_SSH_KEY --node-name NODE-NAME
    Bootstrapping 34.76.3.167
    [34.76.3.167] -----> Installing Chef Omnibus (stable/15)
    [34.76.3.167] 
    [34.76.3.167] downloading https://omnitruck.chef.io/chef/install.sh
    ......
    [34.76.3.167] Getting information for chef stable 15 for ubuntu...

    [34.76.3.167] Installing chef 15
    [34.76.3.167] 
    [34.76.3.167] 
    [34.76.3.167] Thank you for installing Chef Infra Client! For help getting started visit https://learn.chef.io
    [34.76.3.167] 
    [34.76.3.167] Starting the first Chef Infra Client Client run...
    [34.76.3.167] 
    [34.76.3.167] +---------------------------------------------+
    [34.76.3.167] 
    [34.76.3.167]  2 product licenses accepted.
    [34.76.3.167] 
    [34.76.3.167] +---------------------------------------------+
    [34.76.3.167] 
    [34.76.3.167] Starting Chef Infra Client, version 15.0.300
    [34.76.3.167] 
    [34.76.3.167] resolving cookbooks for run list: []
    [34.76.3.167] Synchronizing Cookbooks:
    [34.76.3.167] Installing Cookbook Gems:
    [34.76.3.167] Compiling Cookbooks...
    [34.76.3.167] [2019-07-01T06:52:36+00:00] WARN: Node reactJS-node has an empty run list.
    [34.76.3.167] Converging 0 resources
    ........
    [34.76.3.167] Running handlers:
    [34.76.3.167] 
    [34.76.3.167] Running handlers complete
    [34.76.3.167] Chef Infra Client finished, 0/0 resources updated in 02 seconds

あるいは、サーバへのアクセスを得るための認証手段としてパスワードを使用している場合は、以下のコマンドを実行してください。

 chef@workstation:~$ knife bootstrap IP-ADDRESS-OR-HOSTNAME -N NODE_NAME -x USER -P 'PASSWORD' --sudo

4.自分のノードがChefサーバーに関連付けられていることを確認するには、knife node listコマンドを実行します。

 chef@workstation:~$ knife node list
    reactJS-node

knife node showコマンドを実行することで、ノードのデータを見ることができます。

knife node show NODE-NAME
chef@workstation:~$ knife node show reactJS-node
   Node Name:   reactJS-node
   Environment: _default
   FQDN:        ip-172-31-56-238.home.internal
   IP:          41.215.245.118
   Run List:    
   Roles:       
   Recipes:     
   Platform:    ubuntu 16.04
   Tags:

React.jsアプリケーションの構築

chefサーバー、ワークステーション、ノードのセットアップが完了したので、 react.jsアプリケーションを構築する準備が整いました。以下のようなcookbookを書くことになります。

  • node.jsのセットアップとインストール
  • pm2をインストールします。pm2はプロセスマネージャーであり、react.jsアプリの動作を維持するのに役立ちます。
  • react.jsアプリケーションをインストールします。

  • react.jsアプリケーションを起動します。

そのためにchef executebashリソースを使うことになります。これらのリソースはどちらもコマンドやスクリプトを実行するために使用します。execute リソースは単一のコマンドを実行するために、bash リソースは複数行のコマンドを実行するために使用します。構文やプロパティの詳細については、execute リソースと bash リソースのドキュメントを参照してください。

ワークステーションの cookbooks/example/attributes/recipes ディレクトリにある default.rb ファイルを開き、以下のように置き換えてください。

bash 'Install Node.js' do
 cwd "/home/ubuntu"
 code <<-EOH
   curl -sL https://deb.nodesource.com/setup_8.x -o nodesource_setup.sh
   bash nodesource_setup.sh
   apt-get install nodejs -y 
   EOH
end

execute 'Install pm2' do
 cwd "/home/ubuntu"
 command 'npm install pm2 -g'
end

execute 'Setup react app' do
 cwd "/home/ubuntu"
 command 'npx create-react-app my-app'
 only_if do ! File.exist?('/home/ubuntu/my-app') end
end

bash 'Start application' do
 cwd "/home/ubuntu"
 code <<-EOH
   cd my-app
   pm2 start npm -- start
   EOH
end

cookbookを実行するためには、Chefサーバーにアップロードする必要があります。このファイルに変更を加えるたびに、再アップロードする必要があることに注意してください。react-app-repoディレクトリにあることを確認して、このコマンドを実行してください。

chef@workstation:~$ knife upload cookbooks/example

以下のコマンドを使用して、ノードのrun_listにCookbookのrecipeを追加する必要があります。

chef@workstation:~$ knife node run_list add reactJS-node 'recipe[example]'
reactJS-node:
  run_list: recipe[example]

run_listの詳細はドキュメントで確認できます。

さて、knife sshコマンドを使ってreactJS-nodeにcookbookをデプロイします。

そして、以下のように置き換えてください。

  • USERをノードサーバ上のユーザ名に置き換えてください。

  • PATH_TO_YOUR_SSH_KEY にノードサーバの ssh-key へのパスを指定します。

chef@workstation:~$ knife ssh 'name:reactJS-node' 'sudo chef-client' --ssh-user USER --ssh-identity-file PATH_TO_YOUR_SSH_KEY

これで、ブラウザのウィンドウに http://NODE_SERVER_IP_ADDRESS:3000 を貼り付けて react.js アプリケーションにアクセスできるようになりました。このようなページが表示されるはずです。

image.png

結論

このガイドでは、Chefを始める上での柔軟な基礎を解説しています。Chefの詳細については、Chefの公式ドキュメントを参照して、chef rallyを学ぶことからご覧ください。

アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ApolloClient(React Hooks)でMutation後にQueryをRefetchする。

ApolloClientにて、useMutationでデータを更新した後にuseQueryのデータを再取得する方法に関して
ざっと調べた結果です。

useQueryのrefetch関数を利用する。

useQuery関数の戻り値に含まれるrefetch関数を実行することで、データの再取得ができます。
useMutation関数が同一コンポーネント内、もしくはすぐ配下のコンポーネントならば、
こちらの関数を利用すれば事足ります。

const { data, loading, error, refetch } = useQuery(ANY_GET_QUERY);

const [update, { loading, error }] = useMutation(ANY_SET_QUERY, {
  onCompleted() {
    refetch();
  },
});

FETCHING DATA > Queries > Refetching - APOLLO DOCS
API > @apollo/react-hooks > useQuery > Result

useMutationのrefetchQueriesオプションを利用する。

いくつかのWidgetを組み合わせた構成の画面などで、兄弟関係のコンポーネントのQueryをRefetchさせたい場合は、
useMutation関数のオプション引数refetchQueriesが便利です。

更新したいクエリ名を配列で渡すと、Mutation完了後に該当Queryを実行してくれます。
更新対象の可能性があるクエリ名を最大数記載しても、該当コンポーネントが無ければ
余分なクエリが実行されることはありません。

/**
 * Widget A : リストの表示
 */
const QUERY_A = gql`
  query QueryA {
    list(id: $id) {
      id
      name
    }
  } 
`;

const { data, loading, error } = useQuery(QUERY_A);

/**
 * Widget B : リストの表示
 */
const QUERY_B = gql`
  query QueryB($id: ID!) {
    list(id: $id) {
      id
      date
    }
  } 
`;

const { data, loading, error } = useQuery(QUERY_B);

/**
 * Widget C : リストの更新
 */
const [update, { loading, error }] = useMutation(QUERY_B, {
  refetchQueries: [
    'QueryA',
    'QueryB'
  ],
});

単にクエリ名を渡すのみの場合、クエリの引数は前回のものがそのまま活用されます。
名前文字列の代わりにvariablesを指定したオブジェクトを渡すことも可能です。
配列の代わりにuseMutationの結果を受け取る関数を渡すこともできます。

const [update, { loading, error }] = useMutation(QUERY_B, {
  refetchQueries: ( mutationResult ) => {
    return [
      'QueryA',
      {
        query: 'QueryB',
        variables: { id: mutationResult.id }
      }
    ]
  },
});

Updating after a mutation - APOLLO DOCS
useMutation API > Options - APOLLO DOCS
react-hoc API > options.refetchQueries - APOLLO DOCS

onCompleat関数が呼ばれない

refetchされたいくつかのクエリのうち、onCompleat関数が呼ばれるものと呼ばれないものがありました。
今のところ原因は不明です。。。
useQueryの戻り値のdataはちゃんと新しくなっていたので、取り急ぎonCompleatを利用せず、
代わりにReactのuseMemoを活用することで対処しました。
(情報求ム)

参考情報

https://github.com/apollographql/apollo-client/issues/1831

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む