- 投稿日:2021-02-20T22:42:30+09:00
サーバーレスで動的サイト作成(Firebase Hosting + Cloud Functions + Node.js + Express + EJS)
本記事でやること
下記の構成でサーバレスで動的サイトを作成する。
- Firebase
- Firebase Hosting
- Firebase Cloud Functions
- Node.js
- Express(フレームワーク)
- EJS(テンプレートエンジン)
- Express Generator(雛形の作成)
プロジェクトディレクトリの新規作成から、Firebase へデプロイして動作確認をするところまでを掲載します。
各種ツールはインストールしておいてください。環境
- Windows 10
- Ubuntu(WSL) 18.04.5 LTS
- npm v6.14.11
- firebase v9.3.0
事前準備
- Firebase コンソールから新規プロジェクト作成する
- 料金プランを Blaze (従量制)に変更しておく ※ 使用量に応じて料金が発生するのでご注意ください
手順
新規プロジェクトフォルダを作成
mkdir testapp cd testappFirebase Hosting を初期化
firebase init hosting # 対話式の質問には下記のように回答してください。 ? What do you want to use as your public directory? public ? Configure as a single-page app (rewrite all urls to /index.html)? Yes ? Set up automatic builds and deploys with GitHub? Nopublic フォルダは必要ないので削除
rm -r publicexpress-generator で ソースフォルダを作成
# テンプレートエンジンは EJS を使用 express -e functionsnpm を初期化
npm initEJS をインストール
npm install -save ejs関連パッケージを削除・インストールしておく
npm uninstall debug --save npm install firebase-functions firebase-admin static-favicon morgan cookie-parser body-parserindex.js を編集
先頭と末尾に下記を追加
index.jsconst functions = require('firebase-functions'); (中略) module.exports.func_https = functions.https.onRequest(app);firebase.json を編集
firebase.json{ "hosting": { "public": "functions", "ignore": [ "firebase.json", "**/.*", "**/node_modules/**" ], "rewrites": [ { "source": "**", "function": "func_https" ← これに変更 } ] }, "functions": { ← 以下の3行を追加 "runtime": "nodejs12" ← 追加 } ← 追加 }ローカル環境で動作確認
Firebase エミュレータを実行して動作確認する
firebase emulators:startlocalhost にアクセスして下記画像のようになればOK
Firebase へデプロイ
firebase deploy -iWebコンソールで Hosting と Cloud Functions を確認すると、データがアップされています。
Hosting でURLを確認してアクセス
無事デプロイができました!参考にさせていただいた記事
【Firebase】Cloud Functions + Express + EJSで動的コンテンツを配信する
大変参考になりました。ありがとうございました。
- 投稿日:2021-02-20T19:00:50+09:00
【Node.js】Node.jsの3大フレームワークについて
プログラミング勉強日記
2021年2月20日
Expressを使うことが多いが、他のNode.jsのフレームワークが気になったので簡単にまとめる。Expressとは
ExpressはNode.jsを活用したWebアプリ開発を効率よく進めることができ、よく使われている標準的なものである。
特徴としては、情報量が多く日本語のリソースも多い。また、拡張モジュールが豊富なので追加することで柔軟な対応ができる。Expressは記述量が少なくサーバー制御が可能で複雑なシステムも簡単に拡張することができる。Meteorとは
Meteor(読み方:「メテオ」)フレームワークはフルスタックで、サーバー制御からフロントエンドまですべてをJavaScriptで書くことができる。MeteorはNode.jsをベースとしていて、JavaScriptとHTML, CSSだけでWebアプリを開発できるプラットフォームである。
特徴としては、デバイスを含めてプラットフォームに依存しなく簡単に記述することができる。また、迅速な開発が可能でSPAを早く構築して公開するまでをサポートする。既存の開発そのものを変革する仕組みであったり、モバイル向けのネイティブアプリ作成も可能であったりと、魅力的な機能が豊富にある。Sailsとは
MVCをサポートとした開発効率を重視したフレームワークである。
特徴としては、MVCをサポートしているRailsのような操作で開発環境を進められる。デフォルトでWeb SocketをサポートしたリアルタイムWebアプリ開発もできる。Web APIを簡単に作成して公開することもできる。参考文献
【Node.js入門】3大フレームワーク「Express」「Meteor」「Sails」の特徴とは?
Express Web フレームワーク (Node.js/JavaScript)
オープンソースのフレームワーク/Meteorとは
Node.jsのWebフレームワーク「Sails」を使ってpub/subアプリを作ってみる
- 投稿日:2021-02-20T14:00:16+09:00
LambdaからS3を利用する
はじめに
チュートリアル: Amazon S3 で AWS Lambda を使用するで公開されているチュートリアルを試しながら、LambdaからS3を利用した時のメモになります。
(Cloud9の環境構築はCloud9_環境構築2021にまとめています。)S3にアップロードされる画像のサムネイルを作成する
- IAM コンソールの [Roles] ページを開きます
- [ロールの作成] を選択します
- 次のプロパティでロールを作成します
- [信頼されたエンティティ] – [AWS Lambda]
- [Permissions (アクセス許可)] – [AWSLambdaExecute]
- ロール名 – lambda-s3-role
チュートリアルにあるサンプルを準備します。
$ cd ~ $ mkdie lambda-s3 $ cd lambda-s3 $ vi index.js --- (チュートリアルの内容) --- $ zip -r function.zip ./index.js $ aws lambda create-function --function-name CreateThumbnail \ --zip-file fileb://function.zip --handler index.handler --runtime nodejs12.x \ --timeout 10 --memory-size 1024 \ --role arn:aws:iam::<<作成したロールを渡してください>>:role/lambda-s3-role \ --cli-binary-format raw-in-base64-out $ aws lambda update-function-configuration --function-name CreateThumbnail --timeout 30 //TIMEOUT=30$ cd ~/enviroment/ $ mkdir nodejs $ cd nodejs $ npm init ※パラメータはデフォルト値を指定します。 $ npm install sharp // 画像処理パッケージをインストールします。 $ cd ~ $ zip -r nodejs.zip ./nodejs/ // ディレクトリ名は変更できないようです。 $ less nodejs.zip // 内容を確認します。 $ aws lambda publish-layer-version \ --layer-name <mylayer> \ --zip-file fileb://nodejs.zip \ --compatible-runtimes nodejs12.x $ aws lambda update-function-configuration \ --function-name CreateThumbnail \ --layers <yourlayerバージョンARN> // 動作確認 $ vi inputFile.txt --- (チュートリアルの内容) ※画像ファイルとバケット(src/dist)を準備します。 --- $ aws lambda invoke --function-name CreateThumbnail --invocation-type Event --payload fileb://inputFile.txt outputfile.txt(note: export NODE_PATH=/home/ec2-user/environment/nodejs/node_modules)
上記LambdaとVue Applicationsを連携します。
How to Build Serverless Vue Applications with AWS Amplifyで公開されているチュートリアルを連携します。
$ aws lambda add-permission --function-name CreateThumbnail \ --principal s3.amazonaws.com \ --statement-id s3invoke \ --action "lambda:InvokeFunction" \ --source-arn arn:aws:s3:::(ソースバケット) \ --source-account (ユーザID12桁) // ポリシーの確認 $ aws lambda get-policy --function-name CreateThumbnailS3 バケットにLamdaへのイベントを設定する
通知を設定するには
Amazon S3 コンソールを開きます。
ソースバケットを選択します。
[Properties (プロパティ)] を選択します。
[Events (イベント)] で、以下の設定を使用して通知を設定します。
Name: lambda-trigger。
Events: All object create events。
Send to: Lambda function。
Lambda: CreateThumbnail。
- 投稿日:2021-02-20T10:58:28+09:00
【Node.js puppeteer7.1.0でブラウザ操作自動化&スクレイピング】
スクレイピングしたくてやっぱスクレイピングといえばPythonかなーと思ったけど、Node.js今自分の中で熱いからライブラリーー探したらあったよってこと?
読み方はパペッティア
Chromeの操作を自動化できるライブラリ
色々な操作をする時の参考になればいいなとおもう。
使ってみた感想はNode.js慣れしている人ならかなり簡単にスクレイピングできるなって感じです。
よく操作するクラスの種類
・Browser
ブラウザの生成、終了のときくらいしかつかわない・Page
最も利用するクラス。ページの移動、formへの入力、Elementの取得などができる・ElementHandle
Pageクラスの「.$()
,.$$()
,.$eval()
,.$$eval()
」などを利用してElementを取得したときに返されたりする。指定したElementに直接click()やhover()をさせたりできる。
【操作するブラウザを生成】
const browser = await puppeteer.launch({ headless: false //falseにしておくとBrowserが表示されて動く slowMo: 50 //ブラウザ操作のスピード調整ができる }) const page = await browser.newPage() await page.setViewport({ //ブラウザ幅、高さの設定 width: 1200, height: 800, })
【指定したURLにログイン】
// LOGIN_URL = formのあるページ // LOGIN_USER_SELECTOR = input[type=text] // LOGIN_USER = username // LOGIN_PASS_SELECTOR = input[type=password] // LOGIN_PASS = password // LOGIN_SUBMIT_SELECTOR = input[type=submit] // TARGET_URL = login後開きたいページ await page.goto(LOGIN_URL, { waitUntil: 'domcontentloaded' }) await page.waitForTimeout(2000) await page.type(LOGIN_USER_SELECTOR, LOGIN_USER) await page.type(LOGIN_PASS_SELECTOR, LOGIN_PASS) await Promise.all([ // ログインボタンクリック page.waitForNavigation({ waitUntil: 'networkidle0' }), page.click(LOGIN_SUBMIT_SELECTOR), ]) await page.goto(TARGET_URL)・{ waitUntil:
load
,domcontentloaded
,networkidle0
,networkidle2
} の4つのoptionがあり、ページ遷移が終わったことを決定するタイミングの違いがある。・
page.waitForTimeout(2000)
指定したミリ秒で処理を一時停止する。→
goto()
の後は数秒待たせないとtype()
によるform入力がうまく行かない確率が高まる。・
click()
とwaitForNavigation()
を同時に行うのは、click後のページ遷移が完了する前に次の処理を行ってエラーになるのを防ぐため。
【別ウィンドウ、サブウィンドウ、ポップアップへの対処法】
const [popup] = await Promise.all([ new Promise(resolve => page.once('popup', resolve)), page.click('a[target=_blank]'), ])・
click()
で開かれたサブウィンドウなどは[popup]
に入る。サブウィンドウやポップアップを操作するにはこの[popup]
を操作する。
【要素を取得するよく使う4つの方法+1】
const element = await page.$("#name") const elements = await page.$$(".names") const value = await page.$eval("#name", el => el.value) const values = await page.$$eval(".names", el => el.value) const nameArray = document.querySelectorAll('.names')・$(), $$(), は引数のセレクタでElementHandleクラスを生成する。
内部的に、
document.querySelector()
とdocument.querySelectorAll()
が行われている。・$eval(), $$eval()は第2引数に関数をセットすることで引数に指定した要素を操作した値を取得したりできる。
・ElementHandleクラスは、forEachなどができなくて不便なことがある。そういうときは、
document.querySelectorAll()
で要素を取得すれば普通にforEachなどを適用させられる。
【タブ切り替え】
await page.bringToFront() // page.に指定したページを操作できるように切り替える
【実際に使うときの流れ】
ログイン→ログイン後画面でクリック→出てきたサブウィンドウ操作→元画面に戻る→終了
const puppeteer = require('puppeteer') require('dotenv').config() const env = process.env (async () => { //ブラウザ生成 const browser = await puppeteer.launch({ headless: false //falseにしておくとBrowserが表示されて動く slowMo: 50 }) const page = await browser.newPage() await page.setViewport({ width: 1200, height: 800, }) //form入力&submitでログイン await page.goto(env.LOGIN_URL, { waitUntil: 'domcontentloaded' }) await page.waitForTimeout(2000) //少し待たせないと入力ミスが起きやすい await page.type(env.LOGIN_USER_SELECTOR, env.LOGIN_USER) await page.type(env.LOGIN_PASS_SELECTOR, env.LOGIN_PASS) await Promise.all([ // ログインボタンクリック page.waitForNavigation({ waitUntil: 'networkidle0' }), page.click(env.LOGIN_SUBMIT_SELECTOR), ]) //ログイン後ページへ飛ぶ await page.goto(env.TARGET_URL) //clickによって表示されたpopup取得 const [popup] = await Promise.all([ new Promise(resolve => page.once('popup', resolve)), page.click('input[value="~"]'), ]) //もとのページへback await page.goBack({ waitUntil: 'networkidle0' }) //ブラウザ終了 await browser.close() })()・dotenvモジュールで定数管理している
puppeteerを使う上での注意点
ページロードが終わるタイミングと要素取得のタイミングがズレると要素の取得ができなかったり、ページ遷移が終わる前に次の処理に行ってしまっていたりするので、常にタイミングには気をつけないといけない。
- 投稿日:2021-02-20T08:53:25+09:00
Node.js製サーバの起動方法をforeverからsystemdに移行する
foreverで起動していたExpressのサーバをOS再起動時に自動起動させたかったのでSystemd管理に移行します。
initd向けにforeverの自動起動の仕組みを提供するinitd-forever
というパッケージもあったり、forever自体を起動する方向もアリですが、Systemdでは自動再起動の制御が細かくなっているなど、foreverに期待していた役割自体も担えそうでしたのでシンプルにSystemd → Nodeにしました。
最低限の設定をイメージしてこんな感じになりました。/etc/systemd/system/mydaemon.service[Unit] Description=My Node.js Daemon [Service] User=myuser Group=mygroup #Environment="NODE_ENV=production" WorkingDirectory=/path/to/ ExecStart=/usr/bin/node app.js Restart=always [Install] WantedBy=multi-user.targetあとは
systemctl enable mydaemon.service
で自動起動有効化し、
systemctl start mydaemon.service
で起動します。
User
/Group
は指定しなければrootになってしまうため指定しています。
Environment
は今回不要でしたがExpressで使う機会が多そうなのでコメントアウト状態でサンプルとして入れています。
対象のスクリプトはnode app.js
で起動して、Ctrl+Cで終了させるような動きになっている必要があります。
Restart=always
によってプロセスが落ちても自動的に復帰させます。
デフォルトで10秒に5回の再起動に制限されますがStartLimitInterval
StartLimitBurst
で調整できます。foreverの
watch
に対応する機能は無さそうですが今回の目的には不要でした。
- 投稿日:2021-02-20T01:18:13+09:00
【React Native】簡単なAPI連携のアプリケーションを作成する ③ESLint+Prettierの導入(寄り道)
はじめに
本記事は下記の記事の続編になります。
【React Native】簡単なAPI連携のアプリケーションを作成する ①準備編
【React Native】簡単なAPI連携のアプリケーションを作成する ②住所検索の実装
実践的なアプリを作成するというよりは、ハンズオン的にReact Nativeを触ってみるといった趣旨になっています。
なお思いついた順で記事にしているため、本来は実装を開始する②の前に
本記事の内容であるLintやフォーマッターを実施する方が好ましいのと、
今回の内容は必須ではないため、スキップしていただいても問題ないと思います。
(毎回アレ?ってなるので備忘で残したかったんです。。)本記事で実現すること
VSCode上でコードを編集後、Ctrl+sなどで保存するとシュバッと綺麗にしてくれる。
フォーマッターでは判断できない場合はエラーになり綺麗にならない。
(たまにはLintを無視したいので抑制する)本記事で説明すること
- ESLintの適用手順
- Prettierの適用手順
本記事で解説できているか怪しいこと
- 最新のESLint+Prettierのベストプラクティスかどうか
→Prettier と ESLint の組み合わせの公式推奨が変わり plugin が不要になった
などの記事で触れられているように、去年くらいから公式の推奨方法などが変わっているそうです。
参考にした情報によっては現在のベストプラクティスとは異なる可能性があります。
今回紹介するのは手順の一例程度に捉えていただければ幸いです環境
- eslint:7.20.0
- eslint-config-prettier:7.2.0
- prettier:2.2.1
※eslint-plugin-prettierは入れないらしい。- VSCodeの拡張機能でESLintとPrettierを入れておく。
githubリポジトリ
https://github.com/pbyoshida/postal-app
導入編
それではローカル環境でのLint、フォーマッターの構築を進めていきます。
各モジュールの導入
とりあえずはnpmでインストールしていきましょう。
※Lintやフォーマッターは開発者が使うので--save-devを付けます。$ npm install --save-dev eslint eslint-config-prettier prettierpackage.json見てみましょう。
package.json(導入時点){ "main": "node_modules/expo/AppEntry.js", "scripts": { "start": "expo start", "android": "expo start --android", "ios": "expo start --ios", "web": "expo start --web", "eject": "expo eject" }, "dependencies": { "axios": "^0.21.1", "expo": "~40.0.0", "expo-status-bar": "~1.0.3", "react": "16.13.1", "react-dom": "16.13.1", "react-native": "https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz", "react-native-web": "~0.13.12" }, "devDependencies": { "@babel/core": "~7.9.0", "eslint": "^7.20.0", "eslint-config-prettier": "^7.2.0", "prettier": "^2.2.1" }, "private": true }devDependenciesに導入できていそうですね。
ESLintのセットアップ
以下のコマンドでセットアップを開始します。
$ npx eslint --init最初はどのようにESLintを利用するのかの選択です。
? How would you like to use ESLint? ... To check syntax only To check syntax and find problems > To check syntax, find problems, and enforce code style一番下を選択してコードスタイルを適用します。
次はモジュールの種類です。? What type of modules does your project use? ... > JavaScript modules (import/export) CommonJS (require/exports) None of these一番上のJavaScriptを選択します。
次はフレームワークの選択です。? Which framework does your project use? ... > React Vue.js None of these今回はReactなので一番上を選択します。
次はTypeScriptかどうかの選択です。? Does your project use TypeScript? » No / Yes今回は違うのでNoを選択。
次は実行環境です。? Where does your code run? ... (Press <space> to select, <a> to toggle all, <i> to invert selection) Browser √ NodeこちらはNodeを選択します。
次はコードのスタイルを聞かれます。? How would you like to define a style for your project? ... > Use a popular style guide Answer questions about your style Inspect your JavaScript file(s)今回はUdemyの講座で使用していたAirbnbのスタイルを適用しようと思います。
? Which style guide do you want to follow? ... > Airbnb: https://github.com/airbnb/javascript Standard: https://github.com/standard/standard Google: https://github.com/google/eslint-config-googleAirbnbを選択します。
次はconfigファイルの形式です。? What format do you want your config file to be in? ... JavaScript YAML > JSONここではjsonを選びましょう。(多分一般的かなと)
最後は依存するライブラリを自動的にインストールしてくれます。yesを選択してインストールしましょう。
(ついでにここまでの選択も載せておきます。)√ How would you like to use ESLint? · style √ What type of modules does your project use? · esm √ Which framework does your project use? · react √ Does your project use TypeScript? · No / Yes √ Where does your code run? · node √ How would you like to define a style for your project? · guide √ Which style guide do you want to follow? · airbnb √ What format do you want your config file to be in? · JSON Checking peerDependencies of eslint-config-airbnb@latest The config that you've selected requires the following dependencies: eslint-plugin-react@^7.21.5 eslint-config-airbnb@latest eslint@^5.16.0 || ^6.8.0 || ^7.2.0 eslint-plugin-import@^2.22.1 eslint-plugin-jsx-a11y@^6.4.1 eslint-plugin-react-hooks@^4 || ^3 || ^2.3.0 || ^1.7.0 ? Would you like to install them now with npm? » No / Yesさて、セットアップ後のpackage.jsonは以下になりました。
package.json(セットアップ後){ "main": "node_modules/expo/AppEntry.js", "scripts": { "start": "expo start", "android": "expo start --android", "ios": "expo start --ios", "web": "expo start --web", "eject": "expo eject" }, "dependencies": { "axios": "^0.21.1", "expo": "~40.0.0", "expo-status-bar": "~1.0.3", "react": "16.13.1", "react-dom": "16.13.1", "react-native": "https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz", "react-native-web": "~0.13.12" }, "devDependencies": { "@babel/core": "~7.9.0", "eslint": "^7.20.0", "eslint-config-airbnb": "^18.2.1", "eslint-config-prettier": "^7.2.0", "eslint-plugin-import": "^2.22.1", "eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-react": "^7.22.0", "eslint-plugin-react-hooks": "^4.2.0", "prettier": "^2.2.1" }, "private": true }セットアップ後は.eslintrc.jsonというファイルが作成されています。
.eslintrc.json{ "env": { "es2021": true, "node": true }, "extends": [ "plugin:react/recommended", "airbnb", "eslint-config-prettier", // 追加 "prettier" // 追加 ], "parserOptions": { "ecmaFeatures": { "jsx": true }, "ecmaVersion": 12, "sourceType": "module" }, "plugins": ["react"], "rules": { "import/prefer-default-export": 0, // 追加 "no-use-before-define": 0 // 追加 } }もしも無視したいESLintのルールなどがある場合には上記のファイルに追記していきます。
上では追加とコメントしている4行を追記しています。VSCodeの設定
続いてVSCodeの設定をしていきます。
.vscodeというフォルダを作成し、その中にsettings.jsonというファイルを作成します。
中身はとりあえずこんな感じにします。settings.json{ /* Linter and Formatter */ // linter "eslint.packageManager": "npm", // ESLintライブラリ解決時に使うパッケージマネージャ "editor.codeActionsOnSave": { "source.fixAll.eslint": true, // eslint "source.fixAll.stylelint": true // Stylelint }, // formatter "editor.defaultFormatter": "esbenp.prettier-vscode", // デフォルトフォーマッターをPrettier "editor.formatOnSave": true, "editor.formatOnPaste": true, "editor.formatOnType": true, // Prettier対象外言語 "prettier.disableLanguages": ["markdown"] }このあたりは好みがあると思うので、色々と試してみてください。
Prettierの設定
最後にPrettierの設定です。.prettierrcというファイルを作成し、その中に適用したいルールを記述します。
.prettierrc{ "trailingComma": "es5", "tabWidth": 2, "semi": true, "singleQuote": true }一部デフォルトでそうなっているようなものもありますが、とりあえずは上記のような形で記載します。
各オプションはドキュメントを参考にしてください。動作確認
動作をさせようとしていたらESLINTの箇所に下記のようなマークが出ていました。
そこをクリックして、
「Allow Everywhere」を押して承認します。ESLintの確認
前回のソースコードを見てみると2か所怒られていたようです。。
1個目はswitch文にdefaultのケースが無い
2個目はaddressが重複して定義されている
とのことで修正します。。
APIのステータスが200でも400でも500でもない場合って何なんだ、、と思いつつとりあえず予期しない動作としました。
2個目は変数名を変えています。ただし、どうしてもESLintのルールを無視したい時などがあれば以下のようにコメントしてください。
グローバルに無視する場合/* eslint-disable */次の1行だけ無視したい場合/* eslint-disable-next-line */Prettierの確認
こちらは適当にスペースを入れまくってみます。
こんな感じにガタガタでも、Ctrl+sで保存すると、
シュバッと綺麗に。気持ちいい。。最後に
前回の記事は「まぁこんな感じじゃないの」と思いながら実装していたので、改めてLintやフォーマッターを入れてみると全然整っていなかったことが分かります。
チームで開発する上ではこういった議論や指摘で時間をロスしないために、あらかじめルールを決めておくことが大切だと実感できますね。
今回は寄り道しましたが、次回もう一つのAPIを実行するコードを実装してシリーズを終わりたいと思います。2021/2/21 最終回を書きました。
→【React Native】簡単なAPI連携のアプリケーションを作成する ④天気情報表示の実装