【React Native】Expo CLIを利用してReact Nativeプロジェクトを作成する
あけましておめでとうございます。新年一発目の記事です。
今年もやっていきましょう。
今回はバックエンドAPIのドライバとしてクライアントアプリ(React Native)を作るためにExpoを使ったので、備忘録も兼ねてExpo CLIの紹介をしようと思います。
Expoとは
ExpoはReact Nativeによるクロスプラットフォームアプリ開発の支援サービスです。React Nativeのプロジェクト作成・ビルド・デプロイを容易にするCLIや、React Native上での認証等のロジック・カメラビューなどのUIコンポーネントの実装を簡単にしてくれるSDKなどを提供してくれます。
今回はExpo CLIを使用して、簡単に便利なReact Native環境を構築します。
Expo CLIのインストール
はじめにglobal環境上にnpm(またはyarn)を使用して expo-cli
をインストールします。
$ npm instal -g expo-cli
$ yarn add global expo-cli
余談ですが、 npm
でインストールするときに以下ようなエラーが出てインストールできない場合があります。この場合、 sudo
をつけることでインストール可能になります(rootlessのせい?)。
npm ERR! The operation was rejected by your operating system. npm ERR! It is likely you do not have the permissions to access this file as the current user npm ERR! npm ERR! If you believe this might be a permissions issue, please double-check the npm ERR! permissions of the file and its containing directories, or try running npm ERR! the command again as root/Administrator (though this is not recommended).
Expo CLIによるReact Nativeプロジェクトの作成
インストールが完了したら、以下のコマンドでReact Nativeプロジェクトが作成できます。
my-app
の部分は好みのプロジェクト名に変更してください。
$ expo init my-app
コマンドを実行すると、以下のような選択肢が出現します。
プロジェクト内のアプリテンプレートをどうするか聞かれますが、今回はサンプルのない状態から始めるので blank
を選択しEnter。
? Choose a template: ❯ blank minimum dependencies to run and an empty root component tabs several example screens and tabs using react-navigation
これだけです! これでReact Native(+Expo)プロジェクトの作成が開始されます。
Expoプロジェクトアプリをローカルで起動する
作成したプロジェクトルート上で npm start
または yarn start
を実行すると、アプリがローカルサーバ上で起動します。
$ yarn start yarn run v1.7.0 $ expo start [23:00:35] Starting project at /Users/aa367417/IBMProj/Kyoritu/Project/react_native/owner-client [23:00:37] Expo DevTools is running at http://localhost:19002 [23:00:37] Opening DevTools in the browser... (press shift-d to disable) [23:00:47] Starting Metro Bundler on port 19001. [23:00:49] Tunnel ready. exp://192.168.11.10:19000 ````` ここにQRコードが表示される ````` To run the app with live reloading, choose one of: • Sign in as @rk9902 in Expo Client on Android or iOS. Your projects will automatically appear in the "Projects" tab. • Scan the QR code above with the Expo app (Android) or the Camera app (iOS). • Press a for Android emulator, or i for iOS simulator. • Press e to send a link to your phone with email/SMS. Press ? to show a list of all available commands. Logs for your project will appear below. Press Ctrl+C to exit.
アプリが起動すると同時にブラウザが開き、Expo Developer Toolが開きます。このコンソール上ではアプリのログが表示されます。
Expo Developer Tool上または npm start
yarn start
を実行したコンソール上のQRコードをモバイル端末でスキャンすると、端末上でアプリが起動します。
・・・が、その前にアプリの起動に必要なExpo Clientアプリを端末にインストールする必要があります。iOSであればApple Store、AndroidであればGoogle Play Storeからインストールしてください。
Expo Clientを端末にインストールしてからQRコードをスキャンすると、以下のように初期状態のExporプロジェクトのアプリが起動できます。
ものの5分でプロジェクトが作成+アプリのローカル起動ができました。 QRですぐ端末上でデバッグできるのがいいですね!
以前は create-react-native-app
でExpoプロジェクト作成できたのに、なぜか作成できなくなってたので、新しく expo-cli
をインストールしました。
まだExpoに関しては未知の部分も多いので、ちょくちょく遊んでみようかなと思いました。
参考文献
【2018年終】約半年間、技術ブログを毎日書き続けた話
TL;DR
2019年はがんばります
概要
2018年ももう終わりなので、今日は技術的な話ではなく「ブログ書いててどうだったか」について書こうと思います。
なぜ、毎日ブログを始めたのか
技術ブログを毎日書くきっかけとなったのは、「SOFT SKILLS ソフトウェア開発者の人生マニュアル」という本でした。
- 作者: ジョン・ソンメズ,まつもとゆきひろ(解説),長尾高弘
- 出版社/メーカー: 日経BP社
- 発売日: 2016/05/20
- メディア: 単行本
- この商品を含むブログ (5件) を見る
この本はソフトウェアエンジニアにとってブログを書くことの重要性を一章丸々使って説いており、
ブログは、自分をマーケティングするための方法としては安くて簡単であり、しかも、自分の名前を外に出すために極めて役に立つ。
ブログを持っていると、より良い勤め先に落ち着くために役立つだけではなく、ソフトウェア開発者、コミュニケーターとして力量を上げるために役立ち、想像したこともないようなあらゆるチャンスが引き寄せられてくる。
など、(技術)ブログがいかにエンジニアのプレゼンスに貢献するかについて述べていました。
以前よりQiitaやはてブでいくつか記事を書いたことはあったのですが、更新頻度は半年に1~2回程度と少なめでした。SOFT SKILLを読み、ソフトウェアエンジニアにとってブログを(継続して)書くことは有益であるとを改めて感じた僕は、ブログ毎日書いてみるか、と半ばノリで始めることにしました。
結果
2月から毎日ブログを書き始め、(中抜けも3日位ありましたが)7月半ばまで約半年間毎日書き続けることができました。
・・・ですが、8月になって徐々に仕事が厳しい感じになり、そこからまたブログを書かなくなってしまいました(たまにちょこちょこ書いてはいたのですが)。
最近では徐々に仕事も落ち着き、また毎日ブログを再開しつつあります。
結果的に、平均して2日に一回くらいの更新頻度になりました。
技術ブログを毎日書き続けて気づいたメリット・デメリット
技術ブログをたまに書くのと毎日書くのでは、やっぱり違いました。
メリット
記事を書くほど知識が必要になり、結果学びになる
ブログの記事を書く以上、記事のネタに関する知識はある程度持っている必要があります。そのため、まだ自分の知らない技術に関して記事を書く場合そこそこの知識が必要になります。これを利用して、自分が全く知らないが学びたい技術をあえてネタにし、学習の機会として使っています。そのため僕のブログの記事で扱うネタのほとんどは、新規に学びたいがために最初は知らなかったものばかりです。
例えば、下記の記事は何も知らない状態から公式マニュアルを見つつ書いたものです。
上記記事ではWebpackのチュートリアルを通じて、「Webpackって結局何なん」という疑問を解決することを目的としました。記事を書くことで、「WebpackはWebアプリのコードを依存ライブラリ込みでひとまとめにすること」「ひとまとめにしたコードはミニマイズされること」「トランスパイルも自動適用されること」など、いろいろ学びがありました。
またこのWebpackをいじることでnpmのnpxやbabelなど他の技術にも関わることになるので、「他に何を学べばいいのか」を知るきっかけにもできます。このように自分の知らない技術・新しい技術を学ぶことで、さらに次の学ぶべき事柄を見つけることができ、知識の幅をどんどん広げることができます。
もちろんソフトウェアエンジニアには知識だけでなく、経験などの他の要素も必要ですが、「XXの問題にはこのような技術的解決案がある」などといった「技術に対するインデックスを貼れる」という点で知識を増やすことには価値があると僕は考えています。
少しずつだが着実に来訪者が増えていくので、楽しい
当然といえば当然ですが、毎日ブログを書いていると必然的に記事数が増えていき、読み手の欲しい情報も増えていきます。そうすると少しずつですが、確実に訪問者が増えていくのがわかります。アクセス解析で一日の訪問者数が増えていくのは見ていて普通に楽しいです。
ブログを半年に1~2回程度しか更新していなかった頃は、一日あたりのアクセス数は良くて20程度でしたが、現在では一日500位にはなりました。
コミュニケーションの起点になる
毎日ブログを書き始めてから、もっと色んな人に見てもらいたいという思いからTwitterやFacebookにも記事を共有するようになりました。すると色んな人から「ブログ書いてるやん」と話かけてもらえるようになり、そこから仕事の話や技術的な話に広げられたりすることが多くなりました。SOFT SKILLにあった「コミュニケーターとして力量を上げる」とは少し違いますが、他の人との接点を作れる良いメリットだと思います。
デメリット
趣味の個人開発の時間が減る
ブログを書いていてメリットも有るのですが、デメリットもあります。 特に、ブログを書いている間「コード書けてないな」と思うことが多くなりました。趣味の時間でブログを書く分、コードを書いたり、APIやDBの設計を考えたり、自作アプリについて構想を練る時間が減ってしまった感じがします。
じゃあ毎日ブログを書くことでコードを書いたり、APIやDBの設計を考えたり、自作アプリについて構想を練るのは不可能になるのか?というとそうではないです。ただブログを書くことで他のことに時間を割きにくくなるのは本当なので、注意深く時間繰りしないとブログ書いて一日が終わるみたいなことが頻繁に起きます。
来年の抱負
ブログ
2019年も毎日継続して書く
ブログを続けることによるメリットは確かに感じており、また普通に書いていて楽しいので今後も続けていこうと思います。
来年は
- 無理をしない程度に書く
- 自分、読者にとって価値のある記事を書く
といったところに気をつけて書いていこうと思います。
無理をしない程度に書く
なぜブログを書く上で無理をしないよう気をつけるのかというと、今回は継続してブログを書くことを重視しているからです。ブログの最終的な目標は記事を書くことによるスキル・プレゼンス等の向上なのですが、そのためにはまずブログが続くことが大事だと考えたためです。あとしんどいと楽しくないのでだめです。
自分、読者にとって価値のある記事を書く
自分、あるいは読者にとって価値のある記事であってこそ、その記事の存在価値が生まれると僕は考えています。価値とは、備忘録としての役割であったり、新しい学びの提供であったり様々ですが、とにかく誰かの「役に立つ」ことを意識して作成しています。
例えば、以下の記事は自分に当てたメモ的記事です。
この記事は、
- 一度実装済みだが、万が一忘れたときのためにメモとして残しておこう
- 他の人も同じ問題で困ってるかもしれないから共有しよう
という意識で書き残したものです。一番目は自分のため、二番目は読者のためという視点です。こんなかんじで、「誰かの役に立ったらハッピー」くらいの意識でブログを書いていくと、いつか誰かの役に立つ、価値のある記事になるのではないでしょうか。
ブログ以外
ブログだけにしない
先程のデメリットの話にも出てきたのですが、ブログを書き続けているとどうしても他の作業に時間が回らなくなってしまいます。今年は自分の時間を確保することを意識しながらもブログ活動は継続しつつ、
- 個人開発(今年は完成まで至らず。。。)
- 会社のコミュニティ活動(引き続き勉強会などやっていく)
- 外部コミュニティイベントへの参加(外部は今年で2回)
など引き続き行っていきたいと思います。
来年からも、引き続きよろしくお願いいたします。
【Spring】@TransactionalでTransactionManagerを明示的に指定する
メモ。
TL;DR
Spring で使用する@Transactionには、下記のように使用する Manager
を明示できます。
@Transactional("jpaTransactionManager")
複数のTransactionManagerの定義と@Transaction
Springにおける@Transactionは、デフォルトで用意されている一意のTransactionManagerを参照しています。
しかし、下記のように新たにTransactionManagerを@Configurationクラス内で定義したりすると、
protected PlatformTransactionManager getTransactionManager() { return transactionConfig.getJpaTransactionManager(); }
@TransactionはどのTransactionManagerを参照していいのかわからず、下記のようなエラーを吐いてしまいます。
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.transaction.PlatformTransactionManager' available: expected single matching bean but found 2: transactionManager,getJpaTransactionManager
@Transactionが使用するManagerを明示的に指定するには、@Transactionの引数にTransactionManagerの名称を渡します。@Transactionは指定したTransactionManagerに従い、Transaction管理を実行します。
@Transactional("jpaTransactionManager")
【Spring/Jackson】Rest API : JSON RequestBodyのプロパティをEnum型としてマッピングする
メモ。
SpringのControllerでは、 @RequestBody
を使用することでHTTPリクエストボディに設定されたパラメータをJSONで受け取ることができます。
@RestController public class FluitController { // Request Body にJSONを指定するAPI @RequestMapping(value = "/fluits", method = RequestMethod.POST) public FluitResponse post(@RequestBody FluitRequest req) { .... } }
このとき、 HogeRequest
が以下のような構造で定義されているとします。
@Data public class FluitRequest { private String name; private Integer price; private Integer category; }
FluitRequest::category
は以下の値域のみとり得るとします
HogeRequest req = new HogeRequest(); req.setCategory(1); // 1 : りんご req.setCategory(2); // 2 : みかん req.setCategory(3); // 3 : ぶどう
FluitRequest::category
のような有限集合の場合、Javaであれば列挙型を使用して定義したいところです。
public enum FluitCategory { APPLE, ORANGE, GRAPE }
FluitRequest
にAPI /fluits
のPOSTリクエストボディがマッピングされるとき、category
プロパティの値がそのまま FluitCategory
列挙型としてマッピングされたら便利ですね。
Jacksonが提供する JsonDeserializer
を拡張定義することで、独自のマッピングを実装することができます。これを利用し、リクエストボディマッピング用クラス FluitRequest
に型としてFluitCategory
を持つプロパティを定義できるようにします。
まず、列挙型 FluitCategory
を以下のように整数型IDとの紐付けます。
// 各列挙型オブジェクトがidを持つ @Getter public enum FluitCategory { APPLE(1), ORANGE(2), GRAPE(3); private int id; private FluitCategory(int id) { this.id = id; } public static FluitCategory value(int id) { // idとマッチするFluitCategoryオブジェクトがない場合独自例外を送出 return Arrays.stream(values()).filter(x -> x.id == id).findFirst().orElseThrow(() -> new HogeException()); } }
次に、以下のような JsonDeserializer
拡張クラスを定義します。
拡張する JsonDeserializer
のジェネリクス型には変換先の型である FluitCategory
を指定しています。
変換元の値は deserialize
メソッドの引数 jsonParser
から取得できます。
今回は元々整数型の値であった category
を変換したかったので、 getIntValue
で値を取得します。この値を元に FluitCategory::value()
でFluitCategory
に変換し返り値とします。
public class FluitCategoryDeserializer extends JsonDeserializer<FluitCategory> { @Override public FluitCategory deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException, JsonProcessingException { return FluitCategory.value(jsonParser.getIntValue()); } }
最後に、@Bean
として以下のような ObjectMapper
を定義します。
ここで定義されたObjectMapperがRequest BodyのJSONパース時に使用され、クライアントから整数型で送られたプロパティを FluitCategory
型プロパティとしてJava側で受け取った際に変換が実行されるようになります。
@Configuration public class JsonConfiguration { @Bean public ObjectMapper jsonObjectMapper() { ObjectMapper mapper = new ObjectMapper(); SimpleModule simpleModule = new SimpleModule(); simpleModule.addDeserializer(FluitCategory.class, new FluitCategoryDeserializer()); mapper.registerModule(simpleModule()); return mapper; }
【Spring】オリジナルの `.properties` ファイルを作成・読み込み
メモ。
Spring では application.properties
以外に独自の .properties
を生成し、その中で定義した値を使用することができます。
オリジナル .properties
ファイルの作成とプロパティの参照
例えば、オリジナルのプロパティファイル myconfig.properties
を以下のように作成したとします。
myconfig.properties
config.hoge=1 config.fuga='https://www.fuga.com' config.piyo.foo='foo.' config.piyo.bar=2
このプロパティファイルの設定をSpring内のコードにマッピングするための、 以下のようなクラスを定義します。
@Configuration @PropertySource("classpath:myconfig.properties") @ConfigurationProperties(prefix = "config") @Getter public final class MyConfig { public static class Piyo { private String foo; private Integer bar; } private Integer hoge; private String fuga; private Piyo piyo }
@PropertySource
指定したクラスにどのプロパティファイルの内容をマッピングするのかを指定します。 上の例では MyConfig
クラスに myconfig.properties
ファイルをマッピングするよう指定しています。 classpath:
はクラスパス配下であることを表し、 myconfig.properties
がクラスパスを通したディレクトリ下にあれば良いことを示しています。
@ConfigurationProperties
myconfig.properties
でどのようなプレフィックスを受け入れるかを設定しています。ここでは config
を指定しているので、MyConfigクラスはmyconfig.properties
の各パラメータ名の前に config.
を付けることを要求します。
マッピングの定義が完了したMyConfigクラスには @Configuration
(@Conponentが付加されたアノテーション)が付加されているので、下記のように他コンポーネントへDIによるインスタンス化を行うことができます。
@Service public class HogeService { private static final Logger logger = LoggerFactory.getLogger(LogUtils.class); @Autowired private MyConfig config; public void printFuga() { logger.info(config.getFuga()); } }
環境変数を参照する
下記のように @PropertySource
に渡すvalue値には外部環境変数への参照を記述することができます。
@PropertySource("classpath:myconfig-${ENV}.properties") // 環境変数を追
これにより、例えばデプロイ環境によって適用したいカスタム properties
ファイルの切り替えを行うことが可能です。
参考文献
【Angular】Angular CLIでライブラリの追加・ビルドを行う
Angular CLI
詳細は下記記事にて。
ng add
: 外部ライブラリを追加する
ng add
を使用すると、Angularプロジェクトへの外部ライブラリの追加を行えます(複数指定可能)。
Installing packages for tooling via npm.
の文言から、結局 npm
経由でパッケージインストールしていることがわかります。
$ ng add @angular/material @angular/cdk @angular/animations Installing packages for tooling via npm.
package.json
にも依存関係が記述されていることがわかります。
$ cat package.json | grep -E "material|cdk|animations" "@angular/animations": "~7.1.0", "@angular/cdk": "~7.2.0", "@angular/material": "^7.2.0",
ng build
: アプリをビルドする
ng build
でAngularプロジェクトをビルドし、 /dist
ディレクトリ配下にビルド済みファイルを出力します。
$ ng build Date: 2018-12-24T16:20:03.523Z Hash: bb05af5cc5e75024ef83 Time: 13417ms chunk {main} main.js, main.js.map (main) 10.9 kB [initial] [rendered] chunk {polyfills} polyfills.js, polyfills.js.map (polyfills) 223 kB [initial] [rendered] chunk {runtime} runtime.js, runtime.js.map (runtime) 6.08 kB [entry] [rendered] chunk {styles} styles.js, styles.js.map (styles) 179 kB [initial] [rendered] chunk {vendor} vendor.js, vendor.js.map (vendor) 3.69 MB [initial] [rendered] $ ls dist my-angular-app
ng update
: Angularプロジェクト及び依存ライブラリのバージョンをアップデートする
ng update
コマンドを実行すると、Angularアプリ及びアプリが依存するライブラリのバージョンをアップデートします。
$ ng update We analyzed your package.json and everything seems to be in order. Good work!
参考文献
【webpack】webpackを使用してWebアプリケーションをバンドルする
webpackとは
webPackとはモジュールバンドラと呼ばれるツールです。アプリーケーションが依存するjsモジュールを一つのjsファイルにまとめ上げ、依存関係の解決やトランスパイルを自動実行してくれます。内部的にモジュール同士の依存関係を表すグラフを自動で構築し、それに基づいて依存関係の解決をしてくれるので、設定ファイルなどなしに使用することができます(詳細な設定を記述したファイルを使用することもできます)。
・・・とはいったものの、「モジュールのバンドル」がいまいちピンと来なかったので、こちらのチュートリアルを実践してみました。
以下、チュートリアルのメモになります。
webpackのインストール
まず、webpack対象となる node
プロジェクトを作成します。
$ mkdir hello-webpack $ cd hello-webpack $ npm init -y
npm
でwebpackと、webpackのCLIツールをインストールします。
$ npm install webpack webpack-cli --save-dev
webpackを試しに使用する
実験環境準備
webpackを使用する前に、テスト用のモジュールを作ってみます。
最初のディレクトリ構成は以下の通り。
$ ls node_modules package.json package-lock.json
プロジェクトルートに以下のような index.html
を作成します。HTMLを見ると、 index.html
は <script>
タグ中でCDNによって茶刈 lodash.js
スクリプトをロードしていることがわかります。
<!doctype html> <html> <head> <title>Hello, webpack !!1!</title> <script src="https://unpkg.com/lodash@4.16.6"></script> </head> <body> <script src="./src/index.js"></script> </body> </html>
次に内部ロジック記述用スクリプトである src/index.js
を用意します。このスクリプトでは、先程 index.html
でロードしていた lodash
モジュールを使用しようとしているとします。が、 lodash
に対する依存関係が暗黙的で、 _
を未定義のグローバル変数として参照してしまっています。
function component() { let element = document.createElement('div'); element.innerHTML = _.join(['Hello', 'webpack'], ' '); return element; } document.body.appendChild(component());
上記の index.js
のような、参照できているようで参照できていない暗黙の依存関係は様々なバグを生んでしまいます。
このようなバグをなくすため、lodash
をnpmでのパッケージインストール & import に変更してしまいましょう!
npm での lodash
のインストール
先程用意した index.html
を、新たに生成した /dist
ディレクトリ配下に配置します。
dist └── index.html
次に、 lodash
をnpm経由でインストール。
$ npm install --save lodash
src/index.js
を修正します。明示的に lodash
を参照できるよう、下記一文をファイル先頭に追加します。
import _ from 'lodash';
dist/index.html
を編集します。
<script>
タグによる lodash
のロードをやめ、 参照先スクリプトを main.js
としました。これは後ほど使用するwebpackのバンドル後ファイルへの参照です。
webpackによるモジュールバンドル
上記の import
文によって、webpackが依存関係のグラフを自動作成可能になりました。
それでは、実際にwebpackでモジュールバンドルを行います。
npx
コマンドを使用し、 webpack
を実行します。
npx
についてはこちらを参照。
$ npx webpack Hash: 53680323beef520a74cd Version: webpack 4.28.2 Time: 445ms Built at: 2018/12/25 23:10:03 Asset Size Chunks Chunk Names main.js 1.03 KiB 0 [emitted] main Entrypoint main = main.js [0] ./src/index.js 189 bytes {0} [built] WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/
webpackが成功し、 dist/main.js
が生成されました!
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t){document.body.appendChild(function(){let e=document.createElement("div");return e.innerHTML=_.join(["Hello","webpack"]," "),e}())}])
どうやら「モジュールのバンドル」 とは
- 依存モジュールを一つの
js
にまとめること - スクリプトのミニマイズもする
- トランスパイルもする
といった操作のようです。
webpackを使ってみての感想ですが、「アプリの最適化」を行うのには素晴らしいツールだなと思いました。 アプリの複雑な依存関係を解決し一つのファイルにアプリのスクリプトをまとめることで、ビルド・デプロイするアプリを軽量化・高速化できるので、アプリの総仕上げとして良いのではないでしょうか。 (多くのフロントエンドCLIでもデフォルトで採用されているみたいですね)