Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all 8833 articles
Browse latest View live

pupetterを使ってAmazonの欲しいものリストの情報を取得する

$
0
0

概要

pupetterを使ってAmazon.co.jpから欲しい物リストをスクレイピングする手法のメモです。

下記のように欲しいものリストのIDを指定する事で、商品名と価格、商品IDを取得できる形にします。

サンプルコードのGitHubリンク

実装
// 欲しい物リストのIDを指定constitemList=awaitamazonWishScraper.getProductInfo('hogehoge');console.log('itemList',JSON.stringify(itemList));
itemListの中身
[{"title":"ProductA","price":3278,"productID":"429711111X"},{"title":"ProductB","price":1234,"productID":"429711112X"},]

背景

Amazonの欲しいものリストをスクレイピングで取得する例は、何点か見つかりましたが、紹介されているものの多くは、現在は使えないものでした。
というのも以前は、一定数商品が存在する場合にはページの切り替え行なっていましたが、現在はAjaxで同じページ内で画面をスクロールする事で非同期に読み込む方法に変更されたためです。

scroll.gif

こうなると、GETリクエストを投げてHTMLの解析だけではなく、ブラウザの操作をエミュレートして、スクロールを行うようなヘッドレスブラウザが必要になります。
今回は、puppeteerというヘッドレスブラウザを使用して実現します。

前提

MacOS 10.15.3(19D76)
VS Code 1.42.1
node.js v12.14.1
puppeteer 2.1.0

実装

実装方法の検討

画面スクロール

前述の通り、一定数以上の商品が登録されている場合にはページのスクロールを行いデータを読み出す必要があります。
puppeteerにはブラウザ内で任意のjsが実行可能なので、画面をスクロールさせる処理を実行します。

スクロールの停止(全商品読み込み完了の検知)

スクロールを続けた後に、全ての商品が読み込み終わった事を検知する必要があります。
欲しい物リストの末尾には、下図のようなリストの末尾を示す情報が表示されます。
この部分のタグが検知されたら、全ての商品の読み込みが終わったと判断します。

スクリーンショット 2020-02-18 1.57.34.png

該当箇所のタグ
<divclass="a-row center-align-text full-width-element"><divid="no-items-section-anywhere"class="a-section a-spacing-none">リスト最後
 </div></div>

商品情報の取得

全ての情報が画面に描画されたのならば、後は通常のスクレイピングと同様にHTMLタグを解析するだけです。

実装コード

欲しいものリストサイトへのアクセス

puppeteerを初期化して、欲しいものリストのIDからURLを特定してアクセスします。
今回は表示される情報量を減らし、スクレイピングの効率を上げるためにデスクトップPCではなく、iPhone(スマホ)をシミュレートします。

この部分の処理は、puppeteerの基本的な動作方法ですので詳細は割愛します。

constpuppeteer=require('puppeteer');constdevices=require('puppeteer/DeviceDescriptors');constiPhone=devices['iPhone 8'];consturlbase='https://www.amazon.co.jp/hz/wishlist/ls/';asyncfunctiongetProductInfo(wishListId){constbrowser=awaitpuppeteer.launch({headless:true,args:['--no-sandbox','--disable-setuid-sandbox']});try{constpage=awaitinitPage(browser);// 欲しいものリストのURLを開くawaitpage.goto(urlbase+wishListId);// スクレイピング(中身は後述)returnawaitscrapePage(page);}catch(err){console.error(err);throwerr;}finally{browser.close();}}asyncfunctioninitPage(browser){constpage=awaitbrowser.newPage();awaitpage.emulate(iPhone);returnpage;}

欲しいものリストサイトへのアクセス

実装方法の検討で説明した通り、

  1. リストの末尾が見つかるまで画面をスクロールする
  2. HTMLをquerySelectorで解析する

といったことを実施します。
querySelectorでのデータの切り出しは、生のHTMLを確認しながら商品ブロック単位で情報を取得するように対応しています。

asyncfunctionscrapePage(page){returnawaitpage.evaluate(async()=>{// スクロールでの移動距離と待機間隔msconstdistance=500;constdelay=100;// リストの末尾が検知されない限りループするwhile(!document.querySelector('#no-items-section-anywhere')){// 500pxずつスクロール移動して、100ミリ秒待機するdocument.scrollingElement.scrollBy(0,distance);awaitnewPromise(resolve=>{setTimeout(resolve,delay);});}// 全ての商品の表示が終わったらスクレイピングを実施constitemList=[];// 商品の情報のBOX単位でデータを切り出す[...document.querySelectorAll('a[href^="/dp/"].a-touch-link')].forEach(el=>{constproductID=el.getAttribute('href').split('/?coliid')[0].replace('/dp/','');consttitle=el.querySelector('[id^="item_title_"]').textContent;letprice=-1;constpriceEle=el.querySelector('[id^="itemPrice_"] > span');if(priceEle&&priceEle.textContent){price=Number(priceEle.textContent.replace('','').replace(',',''));}itemList.push({price:price,title:title,productID:productID});});returnitemList;});}

まとめ

簡単にはですが、puppeteerを使ってAmazonの欲しいものリストから情報を一覧取得する法法を紹介しました。
スクロールをシミュレートし、非同期で読み込まれるデータの取得を実現しています。
こういったユーザの操作が必要となる処理に関しても、puppeteerを使う事で簡単に実現ができました。

サンプルコードのGitHubリンク


QualityForward APIとNode.jsライブラリを使って一日の作業件数を集計する

$
0
0

QualityForwardはクラウドベースのテスト管理サービスです。Web APIを提供しています。そのWeb APIを使いやすくするため、Node.jsライブラリも開発中です。

今回はそのNode.jsライブラリを使って、一日の作業件数を集計してみます。

準備

まずはライブラリを読み込みます。APIキーは.envファイルに書き出しています。

import*asdotenvfrom'dotenv';dotenv.config();import{QualityForward}from'qualityforward-node';

必要な変数の準備

まず今日の作業分を集計するので、必要な変数と当てはまるテストケースを格納する変数を用意します。

(async()=>{consttoDay=newDate;letresult=[];// 後の処理もこの中に記述})();

QualityForwardオブジェクトの初期化をします。

constclient=newQualityForward(process.env.API_KEY);

テストフェーズの取得

最初にテストフェーズをすべて取得します。

consttestPhases=awaitclient.getTestPhases();

次にすべてのテストフェーズについて、テストケースを取得します。

for(consttestPhaseoftestPhases){for(consttestSuiteAssignmentoftestPhase.test_suite_assignments){consttestCycles=awaittestSuiteAssignment.getTestCycles();// : 次の処理はこの中に記述}}

テスト結果の取得

すべてのテストサイクルについて、テスト結果を取得します。テスト結果の中で本日作業分をフィルタリングします。

for(consttestCycleoftestCycles){consttestResults=awaittestCycle.getTestResults();constary=testResults.filter(t=>{if(t.executed_at.getFullYear()===toDay.getFullYear()&&t.executed_at.getMonth()===toDay.getMonth()&&t.executed_at.getDate()===toDay.getDate()){returnt;}});Array.prototype.push.apply(result,ary);}

テスト結果ごとにグルーピングする

TestResultが取得できたら、例えばテスト結果ごとにグルーピングしてみます。

constgroup={};for(lettestResultofresult){if(!group[testResult.result])group[testResult.result]=0;group[testResult.result]++;}console.log(`本日の作業結果`);for(letresultingroup){console.log(`  ${result} : ${group[result]}件`);}

そうすると以下のような出力が得られます。

$ npx ts-node test.ts 
本日の作業結果
  pass : 4件
  fail : 1件
  skip : 1件
  cut : 1件
  block : 1件
  qa : 1件

作業件数を蓄積していくことで、品質の可視化にも繋がるでしょう。

まとめ

QualityForwardを使えばExcelなどで行っていた煩雑なテスト管理がクラウドベースでできるようになります。ライブラリを使うことで既存システムとの連携も用意です。ぜひお試しください!

QualityForward

Firebase FunctionsでRealtime databaseにdataを送信する

$
0
0

恒例

https://firebase.google.com/docs/functionsドキュメントを読んでください

Firebase CLI をインストールする

npm install -g firebase-tools

Coding

mkdir test
cd test
mkdir functions
cd functions
vi package.json
{"name":"mytest","description":"mytest","dependencies":{"firebase-admin":"~7.1.1","firebase-functions":"^2.2.1"},"devDependencies":{"chai":"^3.5.0","chai-as-promised":"^6.0.0","firebase-functions-test":"0.1.6","mocha":"^5.0.5","sinon":"^4.1.3"},"scripts":{"ci-test":"npm install && npm run test","serve":"firebase serve --only functions","shell":"firebase experimental:functions:shell","start":"npm run shell","deploy":"firebase deploy --only functions","logs":"firebase functions:log"},"engines":{"node":"8"},"private":true}
vi index.js
'use strict';constfunctions=require('firebase-functions');constadmin=require('firebase-admin');admin.initializeApp();exports.send_data=functions.https.onRequest(async(req,res)=>{consttime=req.query.time;consttext=req.query.temp;constsnapshot=awaitadmin.database().ref('/test').push({time:time,text:text});res.redirect(303,snapshot.ref.toString());});exports.read_data=functions.https.onRequest((req,res)=>{varref=admin.database().ref("test");returnref.orderByChild("time").limitToLast(10).once('value').then(function(snapshot){res.send(snapshot.val());});});

Deploy

cd functions && npm install&&cd ..
firebase deploy

送信方法

https://us-central1-[MY_PROJECT].cloudfunctions.net/send_data?time=20200218&text=uppercasemeをアクセスする

DATAを読み取る方法

https://us-central1-[MY_PROJECT].cloudfunctions.net/read_dataをアクセスする

Node.jsで画像変換処理

$
0
0

目次


sharp

sharp - 概要

Node.jsをサーバとして利用した時に、画像リサイズ処理の最適な方法は何かを調査する。
有名どころでは、ImageMagick。ただ、調べると sharpというNodeモジュールが、
ImageMagickよりも速くリサイズ可能とのことなので、これを調べてみる。

参考

Node.js の画像変換モジュール sharp の使い方 基本的な使い方はこれ一つでok
https://r17n.page/2019/08/15/nodejs-sharp-image-converter-how-to-resize/

Node.jsのライブラリsharpでリサイズを試してみる 読みやすい上の記事のライト版
https://blog.kozakana.net/2019/04/sharp-resize/

Node.jsのライブラリsharpの出力形式について 出力形式についてのまとめ
https://blog.kozakana.net/2019/04/sharp-output-format/

sharp - 環境構築

npm i sharp

sharp - 使い方

sharp(`画像ファイルパス or 画像ファイルバイナリ`)
  .resize(1080, 1080)
  .toFile(`出力パス`)

node-imagemagick

node-imagemagick - 概要

sharpは直感的ですごく使いやすいが、heic形式(iPhoneで撮った写真の形式)については対応していないとのこと。

※公式のQ&Aのやり取りを見ると、対応する方法があるみたいだが、少し複雑。

その為、heic形式も対応するとなると、imagemagickを利用する必要があり、
imagemagickをNodeから実行する方法として、node-imagemagickというnodeモジュールがある。

node-imagemagick - 環境構築

// imagemagickのインストール
brew install imagemagick

// node-imagemagickのインストール
npm i imagemagick

node-imagemagick - 使い方

convertの例。imagemagickはコマンドが多すぎるので、都度調査する。

const im = require('imagemagick')

// imagemagickのコマンドを配列形式で指定する
im.convert(['/path/image/image.png' '/path/image/image.jpg'], (err)=> {
  console.log('image magick convert finish')
})

// コマンド文字列を半スペでsplitするほうが使いやすい
const cmd1 = `/path/image/image.png /path/image/image.jpg`
im.convert(cmd1.split(' '), (err)=> {
  console.log('image magick convert finish')
})

// 一つの画像から複数種類の画像を書き出す場合のコマンド文字列例
const cmd2 =
  `${file.path} `+
  `-resize 3840x1080 -write ${filePath}image.jpg ` +
  `-resize 1080x1080 -write ${filePath}imageProFile.jpg ` +
  `-resize 150x150 -write ${filePath}thumbnail.jpg`

im.convert(cmd2.split(' '), (err)=> {
  console.log('image magick convert finish')
})

GraphicksMagick

GraphicksMagick - 概要

おまけ。
node-imagemagickのgithubリポジトリのReadMeを確認すると、長い間メンテナンスされていない為、GraphicksMagickを利用推奨とのこと。

使い方もsharpの用にメソッドチェーン方式なので、使いやすそうなので良き。
※ただ、heicの書き出しがうまくいかなかったので不採用。

GraphicksMagick - 環境構築

// imagemagickとgraphicsmagickのインストール
brew install imagemagick
brew install graphicsmagick

// WebPに対応する場合
brew install imagemagick --with-webp

// gmモジュールのインストール
npm i gm

GraphicksMagick - 使い方

const gm = require('gm')

gm('/path/to/my/img.jpg')
.resize(240, 240)
.noProfile()
.write('/path/to/resize.png', function (err) {
  // 書き出し完了後の処理
});

Express.jsでミニマムなローカルサーバ構成

$
0
0

目次


概要

簡易的なREST APIをサクッと作りたい・・・。
しかし、その為にバックエンドエンジニアの方にお願いしたり、PHPを調べながら書いたりしたくない!
自分でちゃちゃっとJSで書きたい!!
Express.jsは、そんな人向けのNode.js(サーバサイドJS)のフレームワークです。

環境構築

npm i express  
もしくは、  
Nuxt.jsの環境構築時にExpress選択 ← **おすすめ**

Express.jsのみでAPIを作る方法

Express.jsの基本的な使い方は下記の通り。

1. モジュールをロードしてインスタンス化
2. ポート番号を指定して待受開始
3. アプリケーションの処理を記述

ブラウザから /api/list/ にアクセスし、結果を表示する様なapiを作りたい場合、下記のようになる。

// 1.expressモジュールをロードし、インスタンス化後、変数appに代入
const express = require('express')
const app = express()

// 2.listen()メソッドを実行し、3000番ポートで待ち受け
const server = app.listen(3000, () => {
  console.log(`node port:${server.address().port}`)
})

// ---------- ↑ここまでが基本 ----------
// 仮の配列を作成
const list = [
  {id: 1, keyword: 'test1'},
  {id: 2, keyword: 'test2'}
]

// 3.urlに応じた処理を記述
// app.getとした場合は、getリクエスト。
// app.postとした場合は、postリクエストの時に動作する。
app.get('/api/list/', (req, res, next) => {
  // 定義したデータを返す
  res.json(list)
})

Express.jsをNuxt.jsで利用してみる

Nuxt.jsの環境作成時に Expressを選択した場合は、server/index.js に Express.js を記述するためのファイルが作成される。

npm run dev実行時は、このserver/index.jsが読み込まれる。

Nuxt.jsからExpress.jsを利用する場合は、APIを作る方法で記述した1,2は記述済み(^^)

早速、URLをブラウザに入力し、HelloWorldを表示するAPIを作ってみる。

Nuxt.js + Express.js = 😣

上記を踏まえ、簡単♪簡単♪と思って、以下のようにserver/index.jsに書き、

ブラウザでアクセスすると・・・

app.get('/api/', (req, res, next) => {
  res.json({'api': 'test'})
})

404エラー

Why!!!???

LIGの記事を読んでみると、
Nuxtに「serverMiddleware」を設定して、API サーバ的な動きをさせてみた

公式を読んでみると、
API: serverMiddleware プロパティ
どうやらserverMiddlewareを利用すれば、理想としている簡易APIが作れそうだ!
早速手順にそって、簡易APIを作ってみる!

Nuxt.js + Express.js + serverMiddleware = 😆

api記述用ファイルを準備

  1. apiディレクトリをNuxtプロジェクト直下に作成
  2. api/index.jsを作成
  3. api/index.jsに以下を記述
const express = require('express')
const app = express()

app.get('/', function(req, res) {
  res.send('HelloWorld');
});

module.exports = {
  path: '/api/',
  handler: app
};

※この時点で、npm run devでローカルサーバを立ち上げ、

http://localhost:3000/api/にアクセスしてもPage Not Foundと表示される。

serverMiddleWareを設定

nuxt.config.jsに、上記で作成したapi/index.jsを読み込む様に追記する。

module.exports = {
  serverMiddleware: ["~/api/"],
}

npm run dev でサーバ再起動後、ブラウザで下記にアクセス。
http://localhost:3000/api/

HelloWorldと表示された!!😆

Nuxt.jsに設置したjsonファイルから結果を取得するAPI

やりたいこと

  1. Nuxt.jsディレクトリ内に、jsonファイルを設置
  2. ブラウザでapiのURLにアクセスするとjsonの内容が表示される

準備

※serverMiddleWareは設定済み
1. Nuxt.jsプロジェクト直下に、databaseというディレクトリを作成
2. database/list.json というjsonファイルを作成
3. list.jsonに仮データとして、下記を記述

[
  {
    "key": "A1",
    "name": "test"
  }
]

api/index.jsの設定

以下を記述

const fs = require('fs')

app.get('/list/', (req, res) => {
  fs.readFile('${__dirname}/../database/list.json', 'utf-8', (err, data) => {
    if(err) {
      res.status(500).send(err)
    } else {
      console.log('data',data)
      res.status(200).send(data)
    }
  })
})

↓元々のソースのこの部分は間違い!!
requireは、最新の状態ではなく、ソース読み込み時の状態のため、
常に最新を読みたい場合のファイル読み込みは、 fs.readFileで!
const list = require('../database/list.json')
res.send(list)

npm run devでローカルサーバを立ち上げ、 http://localhost:3000/api/list/にアクセス。

表示された!😆

[
  {
    key: "A1",
    name: "test"
  }
]

/api/list/◯◯ の様なurlで動的に処理する場合

パス部分に*、コールバック関数のreq.paramsを利用すれば、urlの /list/◯◯の◯◯の部分を取得可能。

app.get('/list/*', (req, res) => {
  console.log(req.params)
})

/list/1は、 { '0': '1' }と出力される。

もう少し厳密に、◯◯部分を取得したい場合は、 :を利用する。

app.get('/list/:id/:operation?', (req, res) => {
  console.log(req.params)
})

?は未指定でもokという意味。?を記述しない場合、

/list/aaa/bbb はokだが、 /list/aaa といったurlは404扱いになる。

/list/1は、 { id: '1', operation: undefined }と出力される。

/list/aaa/bbbは、 { id: 'aaa', operation: 'bbb' }と出力される。

Nuxt.jsに設置したjsonファイルにデータを書き込むAPI

やりたいこと(一旦、通信部分は省く)

指定のファイルに、オブジェクト形式のデータを追加する。
→ ファイル書き込みが出来ないといけない。

api/index.jsに記述

ファイル読み込みと同じくファイル操作系は、 fsモジュールを利用し、下記の様な処理手順を踏む。

1. fs.readFileでjsonの内容を読み込む
2. 読み込んだ内容をjsonオブジェクト化
3. 追加処理(本来は、postで受け取った値を追加する)
4. 最新の内容を fs.writeFileSync で書き込む

ソースの内容を抜粋すると以下の様になる。

const express = require('express')
const app = express()
const fs = require('fs') // fsモジュールをロード

app.get('/create/', (req, res) => {

  // fs.readFileでjsonの内容を読み込む
  fs.readFile(`${__dirname}/../database/list.json`, 'utf-8', (err, data) => {
    if(err) {
      res.status(500).send(null)
    } else {
      // 読み込んだ内容をjsonオブジェクト化
      const jsonObject = JSON.parse(data)

      // 追加処理(本来は、postで受け取った値を追加する)
      jsonObject['A3'] = { 'key': 'A3' }

      try {
        // 最新の内容を fs.writeFileSync で書き込む
        fs.writeFileSync(
          `${__dirname}/../database/list.json`,
          JSON.stringify(jsonObject, undefined, '  ')
        )
        res.status(200).send('ok')
      } catch(e) {
        res.status(500).send(null)
      }
    }
  })
})

fsモジュールを利用して、ファイル操作を行う際、

ファイル読み込みには、 readFile , readFileSyncがあり、
ファイル書き込みには、 writeFile , writeFileSyncがある。

それぞれの違いは、同期か非同期かというところ。

Sync系は処理がシンプルに書けるが、Node.js特有のノンブロッキングIOが利用できない。
非同期系は、ノンブロッキングIOが利用出来るが、複雑な処理になると、コールバック地獄になりがち。
なので、同期か非同期かはそれぞれ利用するタイミングを考える必要がある。

Node.js QRコードを生成する

$
0
0

簡単にQRコードを生成できたのでメモ書き

$ mkdir qr 
$ cd qr
$ npm init
$ npm install qrcode
$ touch index.js
index.js
constQRCode=require('qrcode');QRCode.toFile('foo.png','Hello World');
$ node index.js

↓foo.png

スクリーンショット 2020-02-18 23.09.46.png

RasDashを使ってみた

$
0
0

RasDashは「メモリやCPU使用率、センサの値などを表示するNode.js製ダッシュボード」です。
MOON GIFTさんの「RasDash - Raspberry Pi用のダッシュボード」という記事を見て、面白そうと感じたので、使ってみました。

導入

下記の手順で導入。最後のsystemctl enable RasDash.serviceは自動起動するために入力しただけなので、実行しなくても問題なし。

$git clone https://github.com/sykeben/RasDash.git ~/RasDash
$cd ~/RasDash/
$sudo ./install_deps
$sudo ./service_manager install$sudo ./service_manager start
$sudo systemctl enable RasDash.service

表示

http://<Raspberry piのIPアドレス>:5808/dash/0をブラウザで表示。
各値はリアルタイムに反映される。
RasDashの画面

ポート変更

デフォルトでは、ポート番号5808へ接続している。
~/RasDash/config.jsonに記述された数値を変更すれば、他のポート番号に変更できる。

{
    "port": 5808
}

表示内容変更

ダッシュボードに載せる情報は下記のファイルで変更可能。
表示するボードの順番を修正:~/RasDash/views/pages/dash_0.ejs

さいごに

htmlやjavascript、cssの知識はもちろん、EJSというNode.jsのテンプレートエンジンに関する知識が必要なようです。

RasDashの他の項目をいじれるよう、暇を見つけていろいろ試してみます。

Cloud9上でYarnでbootstrap material designを導入する

$
0
0

railsで、初心者のメンターをしていて、非Macユーザーで、環境がcloud9のケースで、yarnでbootstrapを導入しました。あまり記事がなかったので、備忘録で書きます。

環境

windows(64bit)
ruby 2.6.4
Rails 5.2.4
Cloud9上で開発

Node.jsのバージョンアップ

Nodeのstableなバージョンをインストールします。

$ nvm install stable

Yarnのインストール

$ npm install -g yarn

bootstrap material designを導入

package.jsonを生成

$ yarn init

bootstrap material designを追加

$ yarn add bootstrap-material-design

インストール

$ yarn install

マニフェストファイルへ読み込みのpathを記載

app/assets/javascripts/application.js
//=requirebootstrap-material-design/dist/js/bootstrap-material-design.js
app/assets/stylesheets/application.scss
@import'bootstrap-material-design/dist/css/bootstrap-material-design';@import'font-awesome-sprockets';@import'font-awesome';

ここまでブラウザ画面で確認しても、

Sass::SyntaxError

が出る。

config/initializers/assets.rb
Rails.application.config.assets.paths<<Rails.root.join('node_modules')

こちらの記載でファイルが読み込めるように設定。

サーバーを再起動すれば、無事表示!


Cloud9上でYarnでbootstrap material designを導入する

$
0
0

railsで、初心者のメンターをしていて、非Macユーザーで、環境がcloud9のケースで、yarnでbootstrapを導入しました。あまり記事がなかったので、備忘録で書きます。

環境

windows(64bit)
ruby 2.6.4
Rails 5.2.4
Cloud9上で開発

Node.jsのバージョンアップ

Nodeのstableなバージョンをインストールします。

$ nvm install stable

Yarnのインストール

$ npm install -g yarn

bootstrap material designを導入

package.jsonを生成

$ yarn init

bootstrap material designを追加

$ yarn add bootstrap-material-design

インストール

$ yarn install

マニフェストファイルへ読み込みのpathを記載

app/assets/javascripts/application.js
//=requirebootstrap-material-design/dist/js/bootstrap-material-design.js
app/assets/stylesheets/application.scss
@import'bootstrap-material-design/dist/css/bootstrap-material-design';@import'font-awesome-sprockets';@import'font-awesome';

ここまでブラウザ画面で確認しても、

Sass::SyntaxError

が出る。

config/initializers/assets.rb
Rails.application.config.assets.paths<<Rails.root.join('node_modules')

こちらの記載でファイルが読み込めるように設定。

サーバーを再起動すれば、無事表示!

AWS Lambda@Edge で 環境変数を使う方法 (Node.js)

$
0
0

はじめに

Lambda ならば、環境変数という項目があり、
そこにキーと値を書けば process.envオブジェクトから取得できました。

参考URL

AWS Lambda で環境変数を渡してみる(Node.js)

Lambda@Edge にも同じく環境変数の入力欄があるのですが、
どういうわけかまだサポートされてないらしく、
2020年2月時点では使用できません。

初見殺しもいいところですね。

でも、環境変数が使いたい時はあると思います。
色々模索した結果、以下の方法に落ち着きました。

結論 dotenvライブラリを使う

ローカル環境とかにdotenvライブラリを導入します

$ cd /path/to/project
$ npm install dotenv

次に、 .envファイルを用意して、そこに環境変数を色々書いておきます。

$ touch .env
$ vi .env

私はかつてLaravel5(PHP)を使っていたので、それに習った書き方をしています。
Laravelいいよね。

.env
APP_ENV=production
APP_URL=https://www.example.com
APP_DEBUG=false

ここまで出来たら、これらをZIPファイルにまとめて、
Lambda@Edgeにアップロードします。

ZIPファイルでアップロードする方法は、
ネットに腐るほど書いてますのでググってください

【絶対にすること】 エディタで隠しファイルを表示する

2020.02.19 追記

下の方法よりもっと簡単な方法がありました。
プロジェクトフォルダの右の歯車をクリックした後、「Show Hidden Files」をクリックするだけです

3.png

ファイルアップロードが終わったら、
以下の手順に従い、コンソールエディタで
「.env」などの隠しファイルが表示されるようにしてください
(将来の Lambda@Edge のアップデートで表示方法が変更になる可能性があります)

1.png

① エディタ右上の歯車マークをクリック
② User Settings をクリック
③ Tree and Go Panel をクリック
④ Hidden File Pattern: から 次のように 「, .*」 を削除

*.pyc, __pycache__, .*
↓
*.pyc, __pycache__

2.png

これにより、隠しファイルが表示されるので
どこに設定ファイルがあるかがわかるようになりますね。

(筆者は動作確認のために .envファイルを複数用意していますが、
必要ありません。「.env」ファイルだけが使用されます)

環境変数の取得方法

Lambdaで環境変数を取得する方法と全く同じやり方で取得できます。
つまり、 process.envオブジェクトから取得できます。

varENV=require('dotenv').config();varappUrl=process.env['APP_URL'];console.log(appUrl);// e.g. "https://www.example.com"

私の場合、毎回 process.envって書くのがだるいので
Laravelのenv関数みたいな感じにラッピングしてから使用しています

index.js
/* =====================================================================
*  Load External Modules
* =================================================================== */try{varENV=require('dotenv').config();// 環境変数が使えるようになったらこのモジュールは不要}catch(ex){// if module is not existsconsole.error(ex);}/**
 * Get Envrionment Variable
 * Lambda@Edgeは2020年2月時点では環境変数が使えないから
 * DotEnvライブラリで代用する(環境変数もDotEnvも process.env で値を取得できる)
 *
 * @param  string key (should be write UPPERCASE)
 * @param  mixed defaultValue [optional]
 * @return mixed
 */functiongetEnv(key,defaultValue=null){varmyKey=key.toUpperCase();returnprocess.env[myKey]?process.env[myKey]:defaultValue;}functionloadProfile(){varenv=newObject();env.APP_URL=getEnv("APP_URL","https://www.example.com");env.APP_ENV=getEnv("APP_ENV","development");env.APP_DEBUG=getEnv("APP_DEBUG",true);env.S3_BUCKET_NAME=getEnv("S3_BUCKET_NAME","my-s3-bucket-name");env.EC2_URL=getEnv("EC2_URL","");returnenv;}exports.handler=async(event,context,callback)=>{varrequest=event.Records[0].cf.request;varenv=loadProfile();console.log(env["APP_URL"]);// e.g. "https://www.example.com" console.log(env["APP_ENV"]);// e.g. "production" .env に定義されているので その値が使用されるconsole.log(env["S3_BUCKET_NAME"]);// e.g. "my-s3-bucket-name" .env に定義されていないので getEnv関数の第2引数が使用されるcallback(null,request);};

もっと良い方法をご存知の方が
いらっしゃいましたらコメントください。

Node.jsで動画変換処理

$
0
0

目次


概要

Node.jsをサーバとして利用した時に、動画加工処理の最適な方法は何かを調査する。
有名どころでは、ffmpeg。

参考

Node.jsでffmepgを使って動画からサムネイル/静止画を生成する
https://qiita.com/nasbi_suganuma/items/222cd894e09b7c5e9652

それFFmpegで出来るよ! ffmpeg自体の説明と操作
https://qiita.com/cha84rakanal/items/e84fe4eb6fbe2ae13fd8

環境構築

Macでのffmpegのインストール(時間がかかる)

brew install ffmpeg

※こんなエラーが出たので、

Error: Permission denied @ dir_s_mkdir - /usr/local/Frameworks

ディレクトリを作成し、権限与えて、もう一度インストール! 成功!

sudo mkdir /usr/local/Frameworks  
sudo chown $(whoami):admin /usr/local/Frameworks

Winでのffmpegのインストール(パスを通したりするのが、めんどくさい)

↓参照
https://fukatsu.tech/windows-ffmpeg

fluent-ffmpegをインストール

npm install fluent-ffmpeg

fluented-ffmpegの使い方

難しいことをしないなら、 ffmpeg(入力ファイル).output(出力ファイル)で完了なので、結構簡単。

      const filePath = `${__dirname}/../static/MovieFiles/${id}/`

      ffmpeg(`${filePath}movie.mp4`)
        .output(`${filePath}movie.avi`)
        .on('end', () => {
          console.log('Processing finished !')

          // ここに処理完了後の処理記述
        })
        .screenshots({ // これはサムネイル作成の記述
          count: 1,
          folder: filePath,
          filename: 'thumbnail.jpg',
          size: '150x150'
        })

nodemailer envelope設定サンプル

$
0
0

テスト環境

  • node.js v12
  • nodemailer v6.3

公式ドキュメント

サンプルコード

send-mail.js
varMailer=require('nodemailer')//// ローカルsmtpサーバ//constsmtp=Mailer.createTransport({host:'localhost',port:25})constmessage={// メッセージヘッダとかの設定// => メール受け取る側から見える情報from:'from@example.com',to:['to@example.com'],cc:['cc@example.com'],bcc:['bcc@example.com'],subject:'HELLO! nodemailer!!',text:'this is a test mail',html:'<p>this is a test mail</p>',// envelope: SMTPサーバー用の設定//  FROM: (バウンスメールが届くアドレス)//    envelope.from//  と//  RCPT TO: (実際に送信する宛先)//    envelope.to, envelope.cc, envelope.bcc//   最終的には RCPT TO: へまとめられるので、//   実はどれかひとつに(例えば envelope.to) に//   全部まとめて書いてもいい// envelopeは "省略可能"// 省略した場合は以下のように自動付与されると思っていいenvelope:{from:'from@example.com',to:['to@example.com'],// RCPT TO: に突っ込まれるcc:['cc@example.com'],// RCPT TO: に突っ込まれるbcc:['bcc@example.com'],// RCPT TO: に突っ込まれる}// to:, cc: と bcc: はまとめてしまってもいいので以下だけでもOK//  to: ['to@example.com','cc@example.com','bcc@example.com']}smtp.sendMail(message)

メッセージヘッダのfromとバウンスメールの受け取りアドレスを変えたい場合

例えば、MAILER-DAEMONが返ってきてしまった該当メールアドレスは無効化したいので、バウンスメール用のメールアドレスを用意して監視したい時などが利用場面です。

この場合は、envelopeを明示的に設定する必要あります。

envelopeを明示的に設定する場合、message.to, message.cc, message.bccに宛先を書くだけでは、メールは届かないので注意。
envelope.to, envelope.cc, envelope.bcc に宛先を書く必要がある。

constmessage={from:'from@example.com',to:['to@example.com'],cc:['cc@example.com'],//  bcc: ['bcc@example.com'],// どうせ受取人には見えない箇所なので// envelope内にだけ、書いてしまってもよいsubject:'HELLO! nodemailer!!',text:'bounce-mails are sent to for-bounce@example.com ',html:'<p>bounce-mails are sent to for-bounce@example.com</p>',envelope:{from:'for-bounce@example.com',to:['to@example.com','cc@example.com','bcc@example.com']}}

Node.js + Expressの環境構築をしてみた

$
0
0

1.はじめに

先日Node.js + Expressの環境を構築する機会がありました。せっかくなので、学んだことをOUTPUTしたいと思ってまとめることにしました。

1-1.Node.jsとExpress

1-2.PCの環境

  • Windows10 Version 1909
  • Node.js v12.13.1
  • npm v6.12.1

2.環境構築

2-1.Node.jsのインストール

まず、最初にNode.jsをインストールします。
▼Node.jsリンク
https://nodejs.org/ja/

Node.jsには、偶数系統と奇数系統があります。偶数系統がLTS(Long Term Support)版となるので、特に必要がない場合は、偶数系統のインストーラをダウンロードしてインストールすれば良いと思います。

インストールが完了したら、cmdを開いて次のコマンドを実行してください。Node.jsのバージョンを確認することができます。

node -v

2-2.Expressのインストール

node.jsがインストールできたら、次にExpress-generatorを利用してアプリケーションのひな型を生成します。

1.アプリケーションを作成したいディレクトリに移動
cd [アプリケーションを作成したいディレクトリ]
2.express-generatorのインストール
npm install -g express-generator
3.アプリケーションの生成
express [生成したいアプリケーション名]

上記コマンドを実行すると、カレントディレクトリ配下にアプリケーションのひな型が生成されます。
次のコマンドを実行すると、ファイルまで含めて生成された内容を確認できます。

tree /f
実行結果
└─api_app
    │  app.js :アプリケーション本体、最初に呼び出される。
    │  package.json :アプリケーションの環境設定 
    │
    ├─bin
    │      www :アプリケーションのエンドポイント
    │
    ├─public :フロントエンドで利用する画像やjs, cssを保管する場所
    │  ├─images
    │  ├─javascripts
    │  └─stylesheets
    │          style.css
    │
    ├─routes :ルーティングを行っている
    │      index.js
    │      users.js
    │
    └─views :jadeファイル
            error.jade
            index.jade
            layout.jade

2-3.express-generatorでアプリケーションのひな型を生成

node.jsがインストールできたら、次にExpress-generatorを利用してアプリケーションのひな型を生成します。

1.アプリケーションを作成したいディレクトリに移動
cd [アプリケーションを作成したいディレクトリ]
2.express-generatorのインストール
npm install -g express-generator
3.アプリケーションの生成
express api_app

api_appの部分は生成したいアプリケーション名を指定してください。
上記コマンドを実行すると、カレントディレクトリ配下にアプリケーションのひな型が生成されます。
次のコマンドを実行すると、カレントディレクトリ配下のファイルが確認できるので、生成された内容を確認します。

tree /f
実行結果
└─api_app
    │  app.js :アプリケーション本体、最初に呼び出される。
    │  package.json :アプリケーションの環境設定 
    │
    ├─bin
    │      www :アプリケーションのエンドポイント
    │
    ├─public :フロントエンドで利用する画像やjs, cssを保管する場所
    │  ├─images
    │  ├─javascripts
    │  └─stylesheets
    │          style.css
    │
    ├─routes :ルーティングを行っている
    │      index.js
    │      users.js
    │
    └─views :jadeファイル
            error.jade
            index.jade
            layout.jade

2-4.画面表示

アプリケーションのひな型が作成できたら、作成したアプリケーションを起動してみます。
まず、作成したアプリケーションにディレクトリを移動してから、npm installでpackage.jsonに記載されたパッケージがインストールされます。

1.install
cd api_app
npm install

npm installができたら、ブラウザからhttp://localhost:3000/にアクセスしてください。

2.アプリケーションの起動
npm start

正しくアプリケーションが起動できていると、次のような画面が表示されます。
image.png

アプリケーションを終了したい場合は、cmd上で「ctrl + C」を実行します。「バッチ ジョブを終了しますか (Y/N)?」と求めてきますので、yを選択すれば抜けることができます。

3.所感

とりあえず環境構築をすることろまではできました。次はAPI構築あたりの内容を書きたいです。

参考リンク

https://qiita.com/nkjm/items/723990c518acfee6e473
https://qiita.com/maitake9116/items/7825d90c09f3e2f87dea

【Node.js】FetchでフォームデータをPOSTする

$
0
0

Node.jsアプリケーションなどでFechを用いてファイルなどのフォームデータをPOSTしてみる

FetchAPIのデフォルトのコンテンツタイプヘッダは Content-Type': 'application/jsonになっています

一方、HTML等のFormを用いてPOSTしたときのコンテンツタイプヘッダは Content-Type': 'multipart/form-dataです

コンテンツタイプヘッダを指定してPOSTするのでは駄目

コンテンツタイプヘッダを Content-Type': 'multipart/form-dataと指定してfetchしてみてもデータは送信できません。

multipart形式ではバイナリデータを転送できるため、サーバー側がフィールドデータがどこで終わり、次のフィールドデータがどこから始まるかを知る為に、ブラウザ側でboundaryというものを設定します。

そのため、コンテンツタイプヘッダをオーバーライドするだけではboundaryの設定が正常に出来ません。

解決策

コンテンツタイプヘッダをオーバーライドするだけでは上記のような問題が発生してしまうので
明示的にコンテンツタイプヘッダを明示的に削除してあげる必要があります。

index.js
constfileInput=document.querySelector('#your-file-input');constformData=newFormData();formData.append('file',fileInput.files[0]);// 送信用データを設定constoptions={method:'POST',body:formData,headers:{'Content-Type':'multipart/form-data',},};// ここで明示的に消してあげるdeleteoptions.headers['Content-Type'];// 設定したデータをPOSTfetch('your-upload-url',options);

参考記事

この記事に助けられました。感謝してもしきれない。
Uploading files using 'fetch' and 'FormData'

create-nuxt-appでエラーが出る

$
0
0

起こった問題

以下の設定で create-nuxt-appした時に

% yarn create nuxt-app aiue

create-nuxt-app v2.14.0
✨  Generating Nuxt.js project in aiue
? Project name aiue
? Project description My impeccable Nuxt.js project
? Author name mur71mur
? Choose the package manager Yarn
? Choose UI framework Bulma
? Choose custom server framework Express
? Choose Nuxt.js modules Axios, Progressive Web App (PWA) Support
? Choose linting tools ESLint, Prettier
? Choose test framework Jest
? Choose rendering mode Single Page App
? Choose development tools (Press <space> to select, <a> to toggle all, <i> to invert selection)
throw new SAOError(`Failed to install ${packageName} in ${cwd}`)

というエラーが出た。
この時のnodeのversionは

% node -v
v10.10.0

調査

設定をいじってたらeslintがある時にこのエラーが出てることが判明したので

% yarn add -D eslint

eslintだけをinstallしてみると

eslint@6.8.0: The engine "node" is incompatible with this module. Expected version "^8.10.0 || ^10.13.0 || >=11.10.1". Got "10.10.0"

nodeのversionがダメと言われる。

解決策

とりあえずエラー文に従って

% node -v
v12.6.0

にするとeslintを設定しても create-nuxt-appできる。


ActionView::Template::Error (Autoprefixer doesn’t support Node v0.10.48. Update it.):

$
0
0

RailsアプリをEC2へデプロイする過程で遭遇したエラーです。調べるとnode.jsを入れ直せとのことなので、

$ sudo yum remove nodes

これで削除して

ActionView::Template::Error (No such file or directory - node):

エラーメッセージが変わりました。新しく入れ直します。

$ curl --silent --location https://rpm.nodesource.com/setup_6.x | sudo bash -
$ sudo yum install -y nodejs

インストール完了です。

gem mini_racer

stackoverflowではmini_racerをインストールするように書かれていたものもありました。自分はこれでは解決しませんでした。

お気に入りのテレビ番組の有無を答えてくれるAlexaスキルを作ってみた

$
0
0

はじめに

日曜日の夜に日本テレビ系列で放送されている「世界の果てまでイッテQ!」見てますか? 面白いですよね。
娘もこの番組大好きで、週末になると毎日「今日イッテQある?」と聞いてきます。

だいたい毎週日曜日にはあるのですが、時々特番とかで放送なかったりで、その時の娘のガッカリ感ときたら…。

それはさておき、毎週末聞いてくるので、大好きなアレクサが答えてくれたら娘も喜ぶんじゃないかな、と思って、「今日イッテQある?」と聞いたら答えてくれるアレクサスキルを作ってみました。

要件

以下のようなものを目標にしてみました。

  • 「アレクサ、今日イッテQある?」と聞いたら
    • WEB上にある番組表から「イッテQ」というキーワードで検索。
    • 今日見つかったら「HH:MM〜HH:MMに世界の果てまでイッテQ…があります」と答える。
    • 今日はないけど見つかったら「MM/DDのHH:MMにあるようです」と答える。
    • 見つからなかったら「ありません」と答える。

実装方針

  • スキルの呼び出し名を「今日イッテQある」にする。
    • こうすると「アレクサ、今日イッテQあるを開いて」で起動する設定になりますが、「アレクサ、今日イッテQある?」でも起動できたので…。
    • たぶんスキル名にもよるのだと思いますが、もしこれで起動できなかった場合は、定型アクションを使うつもりでした。
  • いつもPythonの人なので、今回は自分自身の新たな取組としてNode.jsで書いてみる。
    • ほぼ初めてのNode.jsなので、お見苦しい点はお許しくださいませ。
  • 今回はLambda上で実装するする。
    • Alexa-hostedスキルでもできるのかもしれないですが、初めてNode.jsでアレクサスキルを作るということをやる上で、慣れない環境でハマるのもイヤだったので。

実装内容

Alexa Developer Console

※いくつかキャプチャを貼っていますが、作成済みのスキルの編集画面ですので、作成手順に沿っているわけではありません。

呼び出し名

方針に書いたように「今日イッテQある」にしました。
「呼び出し名は2名詞以上である必要があります。」と赤字でエラーっぽく書かれていますが、これで動いています。
※保存したらQが小文字になりました

Alexa Developer Console 呼び出し名

インテント

今回はスキル呼び出されたらそのまま回答して終了するスキルにするので、インテント用意しなくてもいいのかな…と思っていたのですが、何も設定していない状態だと、ビルドエラーが出てしまいます。

Alexa Developer Console ビルドエラー

何かしらサンプル発話を登録すればいい、ということなので、今回はビルトインインテントのAMAZON.StopIntentにサンプル発話を設定することで、ビルドが通るようになります。

Alexa Developer Console インテント

エンドポイント

ここは普通にLambdaを使ったAlexaスキル一般通り、LambdaのARNを指定してます。

AWS Lambda

Lambda側は以下方針で実装しました。

  • ASK ADK for Node.jsを使用。
  • 番組を調べるためのWebサービスとしてYahoo!テレビを使用させていただく。
    • 検索するのに使い勝手がよかったので…
  • スクレイピングするためのHTMLパースにはCheerioを使用。

ということでソースは以下の通りです。コメント入れているので何やっているかはわかるかと思います。

app.js
constAlexa=require('ask-sdk-core')constAxios=require('axios')constCheerio=require('cheerio')constMoment=require('moment-timezone')constMoji=require('@eai/moji')Moment.tz.setDefault('Asia/Tokyo')// 最後のa=10が札幌を示しているconstUrl='https://tv.yahoo.co.jp/search/?q=%E3%82%A4%E3%83%83%E3%83%86Q&a=10'constTitle='世界の果てまでイッテQ!'// スキル起動ハンドラconstLaunchRequestHandler={canHandle(handlerInput){// スキル起動時に反応するreturnhandlerInput.requestEnvelope.request.type==='LaunchRequest'},asynchandle(handlerInput){constresponse=awaitAxios.get(Url)const$=Cheerio.load(response.data)constprogramInfos=$('.programlist li').map((index,elm)=>{constleft=$('div.leftarea',elm)constright=$('div.rightarea',elm)constdateString=$('p:first-of-type > em',left).text()consttimeString=$('p:nth-of-type(2) > em',left).text()consttitleString=$('p:first-of-type > a',right).text()return{date:dateString,time:timeString,// 番組表の文字列、全角半角の混ざり方が不規則なので、英数は半角、カナは全角に揃えるtitle:Moji(titleString).convert('ZEtoHE').convert('HKtoZK').toString()}}).get().filter(x=>x.title.indexOf(Title)===0)// 特番とかだと違う番組が引っかかることがあるので、番組名先頭に「世界の果てまでイッテQ!」// と書かれているものを対象番組として扱うことにする// 今日あるかどうかの判断を行うconsttimestamp=Moment(handlerInput.requestEnvelope.request.timestamp)constdateString=timestamp.format('M/D')constfiltered=programInfos.filter(x=>x.date===dateString)letspeechTextif(filtered.length>0){// 今日ある場合は、番組詳細まで返すconstsubStr=filtered.map(x=>{consttimeString=x.time.replace('','から')constresult=timeString+''+x.title+''returnresult}).join('')speechText='今日は'+subStr+'あります。'}elseif(programInfos.length>0){// 今日はないけど、明日以降見つかったら、日付と時刻を返す。constsubStr=programInfos.map(x=>{constresult=x.date.replace('/','')+''+x.time.replace('','から')returnresult}).join('と、')speechText='今日はイッテQはありませんが、'+subStr+'にあるようです。'}else{// ないspeechText='今日はイッテQはありません。'}returnhandlerInput.responseBuilder// 最後は全角で返さないとうまく読んでもらえない。.speak(Moji(speechText).convert('HEtoZE').toString()).getResponse()}}exports.handler=Alexa.SkillBuilders.custom().addRequestHandlers(LaunchRequestHandler).lambda()

ビルド、デプロイはAWS SAMを使いました。
特に特筆する内容はないですが、以下のようなテンプレートを使いました。

template.yaml
AWSTemplateFormatVersion:'2010-09-09'Transform:AWS::Serverless-2016-10-31Description:>alexa itteq今日イッテQがあるか答えるAlexaスキルGlobals:Function:Timeout:30Resources:AlexaItteqFunction:Type:AWS::Serverless::FunctionProperties:CodeUri:src/Handler:app.handlerRuntime:nodejs12.xEvents:Alexa:Type:AlexaSkill

あとは、デザイナー画面の「Alexa Skills Kit」でスキルIDをセット。
スキルIDはAlexa Developers Consoleで確認可能。

作ってみての所感など…

今回作ったスキルは期待通り娘にも使ってもらえてよかった〜と感じです。

ただ、スキルを呼び出した後、返答が返ってくるまで少しタイムラグがあるのが気になりますね。
娘には「イッテQある?って聞かれてからアレクサは一所懸命調べたり考えたりしているんだよ〜」って説明して納得してくれていますが、やはりUX的には気になるところ…

番組表取得自体はデイリーとかで回してDynamoDBなりS3なりに保存しておいて、Alexaからの要求が来たときはDynamoDBなりS3なりを参照にする方がいいのかなぁ…
いずれにしてもX-RAYを仕掛けて、番組表取得で遅くなっているのか、その後の処理で遅くなっているのかなどを見極めたいと思っています。

javascript(node.js)のrequest.on()を解説

$
0
0

reqest.on(イベント名, 関数);

イベント名
→ dataイベント
クライアントからデータを受け取ると発生するイベントです。

→ endイベント
データの受け取りが完了すると発生するイベントです。

Node.jsでSQLServerにWindows認証で接続する(msnodesqlv8)

$
0
0

Node.jsでSQLServerにWindows認証で接続する

Node.jsでSQLServerに接続するパッケージとしてmssqlがありますが
何故かSQLServer認証で接続できないことがあります…
(私はPC変えて同じように設定したつもりが接続できず…備忘のため)

その場合にはmsnodesqlv8を使うとWindows認証で接続できます。

SQLServer認証を行う場合の接続情報
{
    "user": "(ユーザー名)",
    "password": "(パスワード)",
    "server": "localhost(またはサーバー名)",
    "database":"(DB名)",
    "options": {
        "encrypt": true
    }
}
Windows認証する場合の接続情報
{
    "server": "(サーバー名)",
    "database":"(DB名)",
    "options": {
        "trustedConnection": true
    }
}

あとはmsnodesqlv8のサンプルでは
const sql = require("msnodesqlv8");
となっていますが、それで接続ができなかった場合、
const sql = require('mssql/msnodesqlv8');
とすれば接続できます。

huskyを使ってgit hookを楽に扱う

$
0
0

前提

  • Node.js限定です
  • prettier, eslintは導入済みとする
  • gitコマンドを使わないと走らないので注意
    SorceTreeでcommitしたら動きました

やること

pre-commitでprettier --write,eslint --fix,jestを走らせる。

方法

huskyを入れてpackage.jsonにちょろっと書いて終わり。便利。

huskyとlint-stagedをインストール

~$ npm i -D husky lint-staged

package.json編集

nameやversionと同階層に以下を追加。対象コードが格納されてるディレクトリは環境に合わせて修正。

"husky":{"hooks":{"pre-commit":"lint-staged; jest"}},"lint-staged":{"*.{js,jsx}":["prettier --write './src/**/*.js'","prettier --write './__tests__/**/*.js'","eslint --fix './src/**/*.js'","eslint --fix './__tests__/**/*.js'"]}

おわり

後は適当に編集してgit add -Aしてgit commitすればlint-stagedに書いた内容が実行されてからjestが実行されます。
sh書かなくても良いのは楽ですね。ReactやVue.js環境でももちろん動きます。
VSCode環境ならprettierもeslintもAutoSaveで走らせればあまり必要はない気もしますが。

Viewing all 8833 articles
Browse latest View live