20210306のNode.jsに関する記事は6件です。

Node.jsのモジュールを使ってHTML, CSS, JavaScriptを軽量化・難読化する手順

はじめに

Windows環境で、Node.jsのモジュールを使って以下を行う手順をまとめます。

  • HTML, CSSの軽量化(minify)
  • JavaScriptの難読化(uglify)

使用モジュール

  • html-minifier → HTMLファイルの軽量化モジュール
  • clean-css-cli → CSSファイルの軽量化モジュール
  • uglify-es → JavaScriptファイルの難読化モジュール

準備:モジュールのインストール

  1. Node.jsを取得しインストールする。→ https://nodejs.org/ja/

  2. Node.js command promptを起動する。

  3. 以下のコマンドを実行する。(2行目のプロキシ設定は必要な場合のみ実行)

$ npm -g config set registry http://registry.npmjs.org/
$ npm -g config set proxy http://xxx.xxx.xxx:8080
$ npm install -g html-minifier
$ npm install -g clean-css-cli
$ npm install -g uglify-es

使用方法

Node.js command promptから、以下のコマンドを実行する。

HTMLの軽量化

$ html-minifier --collapse-whitespace --remove-comments --remove-optional-tags --remove-redundant-attributes --remove-script-type-attributes --remove-tag-whitespace --use-short-doctype original.html -o original.min.html

CSSの軽量化

$ cleancss -o original.min.css original.css

JavaScriptの難読化

$ uglifyjs original.js -c --compress --mangle --output original.min.js

関連記事

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

Node.jsを使ってHTML, CSS, JavaScriptを軽量化・難読化する手順

はじめに

Windows環境で、Node.jsのモジュールを使って以下を行う手順をまとめます。

  • HTML, CSSの軽量化(minify)
  • JavaScriptの難読化(uglify)

使用モジュール

  • html-minifier → HTMLファイルの軽量化モジュール
  • clean-css-cli → CSSファイルの軽量化モジュール
  • uglify-es → JavaScriptファイルの難読化モジュール

準備:モジュールのインストール

  1. Node.jsを取得しインストールする。→ https://nodejs.org/ja/

  2. Node.js command promptを起動する。

  3. 以下のコマンドを実行する。(2行目のプロキシ設定は必要な場合のみ実行)

$ npm -g config set registry http://registry.npmjs.org/
$ npm -g config set proxy http://xxx.xxx.xxx:8080
$ npm install -g html-minifier
$ npm install -g clean-css-cli
$ npm install -g uglify-es

使用方法

Node.js command promptから、以下のコマンドを実行する。

HTMLの軽量化

$ html-minifier --collapse-whitespace --remove-comments --remove-optional-tags --remove-redundant-attributes --remove-script-type-attributes --remove-tag-whitespace --use-short-doctype original.html -o original.min.html

CSSの軽量化

$ cleancss -o original.min.css original.css

JavaScriptの難読化

$ uglifyjs original.js -c --compress --mangle --output original.min.js

関連記事

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

DockerコンテナでNode.jsを実行してみた

前の記事に引き続き、今回はコンテナでNode.jsのアプリケーションを動かし、ブラウザから開いてみることに挑戦してみました。

スクリーンショット 2021-03-06 13.44.31.png

実装は以下の手順で行いました。

  1. Node.jsアプリの作成
  2. Dockerfileの作成
  3. Dockerfileのビルド
  4. コンテナの起動
  5. ブラウザとアプリの接続

Node.jsアプリの作成

localhost:8080を開いたときにHi thereがブラウザに表示されることを目指します。

package.jsonindex.jsの中身は以下のようにします。

package.json
{
  "dependencies": {
    "express": "*"
  },
  "scripts": {
    "start": "node index.js"
  }
}
index.js
const express = require('express');

const app = express();

app.get('/', (req, res) => {
  res.send('Hi there');
});

app.listen(8080, () => {
  console.log('Listening on port 8080');
});

Dockerfileの作成

Dockerイメージをビルドしたとき、ファイルシステムにアプリに必要なプログラム(dependencies)をインストールし、メタ情報にアプリの起動コマンド(npm start)を導入することを目指します。

前の記事でredisをコンテナで立ち上げたときのように、試しにalpineのベースイメージを使ってDockerfileを作成してみます。

FROM alpine

RUN npm install

CMD ["npm", "start"]

これをビルドすると、RUN npm installの部分でこけます。
なぜかというと、alpineイメージは軽量であるがゆえに、nodenpmもプリインストールされていないからです。

そのため、ベースイメージにはnodenpmがプリインストールされているnodeイメージなどを選択する必要があります。ただ、nodeイメージにはnpmやnode以外にもテキストエディタツールなどの余計なプログラムもプリインストールされているので、軽量なalpineにnpmnodeがプリインストールされたnode:alpinenode:slimなどの最適化されたベースイメージを使うのがベストプラクティスです。

ベースイメージをnode:alpineに変えて再度ビルドしてみます。

FROM node:alpine

RUN npm install

CMD ["npm", "start"]

このビルドもこけます。
なぜなら、node:alpineのファイルシステムにpackage.jsonが含まれておらず、インストールするプログラムが不明だからです。もしたまたまハードドライブにpackage.jsonが含まれていたとしても、コンテナに割り当てられたハードドライブのセグメントにファイルがあるわけではないので、npm installは実行できません。

ここでDockerfile内に、RUNの前にファイルコピーするための記述COPYを加えます。
COPY ./ ./とすることで、ローカルのカレントディレクトリのファイル(package.json, index.js)をコンテナ内のファイルシステムにコピーすることができます。

FROM node:alpine

WORKDIR /usr/app

COPY ./ ./
RUN npm install

CMD ["npm", "start"]

*WORKDIR /usr/appという記述がありますが、これはファイルのコピー先(ワーキングディレクトリ)を指定しています。詳細は後述します。

これでようやくビルドが成功します。

(base) [9:42:15] → docker build -t suzuki0430/simpleweb:latest .                                                                               ~/Programs/docker/simpleweb
Sending build context to Docker daemon  4.096kB
Step 1/5 : FROM node:alpine
 ---> b3dce3e0529f
Step 2/5 : WORKDIR /usr/app
 ---> Using cache
 ---> d995d6f0fd23
Step 3/5 : COPY ./ ./
 ---> 8b999fe7dc6e
Step 4/5 : RUN npm install
 ---> Running in 52b539c857e3

added 50 packages, and audited 50 packages in 3s

found 0 vulnerabilities
npm notice
npm notice New minor version of npm available! 7.0.8 -> 7.6.1
npm notice Changelog: <https://github.com/npm/cli/releases/tag/v7.6.1>
npm notice Run `npm install -g npm@7.6.1` to update!
npm notice
Removing intermediate container 52b539c857e3
 ---> 5f7e4d45df44
Step 5/5 : CMD ["npm", "start"]
 ---> Running in e8085a051d01
Removing intermediate container e8085a051d01
 ---> e76e6a91dc2b
Successfully built e76e6a91dc2b
Successfully tagged suzuki0430/simpleweb:latest

コンテナの作成・起動を行います。

(base) [9:43:11] → docker run suzuki0430/simpleweb                                                                                             ~/Programs/docker/simpleweb

> start
> node index.js

Listening on port 8080

コンテナの起動も正常にできたみたいなのでこれで成功!といきたいところなのですが、ブラウザからアプリが開けません...えっ?
スクリーンショット 2021-03-06 10.26.21.png

ポートマッピング

アプリが開けなかったのは、コンテナのポート8080とローカルホストのポート8080が接続されていなかったためです。
ブラウザからlocalhost:8080にアクセスする際、localhost(ローカルPC)のポートに接続しようとします。ただ、今回はコンテナの中でNode.jsのアプリケーションを実行しているため、コンテナのポートと接続する必要があります。
スクリーンショット 2021-03-06 14.30.41.png

ローカルPCとコンテナのポートを紐付けることをポートマッピングと呼びます。
ポートマッピングを実行するためにはdocker run -p 8080:8080 [image id]コマンドを実行します。コンテナの作成・起動とポートマッピングを同時に実行してくれます。

これで開けるようになりました!
スクリーンショット 2021-03-06 10.43.55.png

キャッシュの利用

アプリは開けるようになったのですが、気になる部分が1つあります。それは今のDockerfileの内容だと、ファイルを更新してイメージをビルドする際にnpm installが必ず実行されてしまうことです。最終的にビルドは完了するので問題がないといったらないのですが、ビルドの待ち時間はできるだけ避けたいものです...

そこでキャッシュの利用を考えます。

DockerfileをRUN npm installの前にpackage.jsonのみをコピーするように書き換えます。

FROM node:alpine

WORKDIR /usr/app

COPY ./package.json ./
RUN npm install
COPY ./ ./

CMD ["npm", "start"]

すると、package.jsonの中身が同じであれば、RUN npm installまでの手順をキャッシュによってスキップすることができるようになります。

Step 3/6 : COPY ./package.json ./
 ---> Using cache
 ---> 1e7f34ded131
Step 4/6 : RUN npm install
 ---> Using cache
 ---> 8f0ae8a2f7f6

ワーキングディレクトリの指定

Dockerfile内にWORKDIR /usr/appという記述がありますが、ここではRUN, CMD, ENTRYPOINT, COPY, ADD, docker run, execで実行するコンテナプロセスのワーキングディレクトリを指定しています。

WORKDIR /と指定することももちろんできるのですが、ルートディレクトリにはいろんなファイルやフォルダが含まれているので、ファイル名が同じだったりすると干渉が起こってしまいます。そのため、コンテナプロセス用のディレクトリを指定してあげる必要があります。

コンテナ起動時にシェルを開くと、確かにワーキングディレクトリが/usr/appとなっています。

(base) [11:06:07] → docker run -it suzuki0430/simpleweb sh                                                                                     ~/Programs/docker/simpleweb
/usr/app #

おわりに

Node.jsをコンテナで動かすことができるようになりました。次はDocker-composeについて学習します。

参考資料

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

React初心者へ ReactとNode.js?フロントなのにサーバーサイド?

React初心者へ

Reactの復習をし始めたので、私も初心者ですが、React初心者向けに記事を書いてみました。
Reactの学習を始めてしばらくするとNode.jsに出会うと思いますが、フロントエンド開発なのになぜサーバーサイドの話が出てくるのかと疑問を頂いていませんか?
私もはじめはそう思っていました。Node.jsについてググって色々調べると「サーバーサイドのJavaSctipt」という間違った認識を得てしまいました。

Node.jsはJavaScriptの実行環境のこと

「サーバーサイドのJavaSctipt」という認識のとおり、サーバーサイドで動く、少し書き方の違うJavaScriptなのかと思っていませんか?私はそうでした。
JavaScriptは通常ブラウザでしか動かないのですが、PCでも動くようにするためのソフトウェアがNode.jsなのです。

詳しくはこちらの記事がおすすめです。

ReactはNode.jsなしでも動きます

htmlのscriptタグで
https://unpkg.com/react@17.0.1/umd/react.development.js
https://unpkg.com/react-dom@17.0.1/umd/react-dom.development.js
を読み込み、ReactDOM,renderメソッドを使用すれば動きます。

なぜReact開発にNode.jsなのか

Reactでの開発時にサーバーサイドのJavaScript環境として知られるNode.jsを使う理由は、

①アプリケーション開発時のパッケージ管理の手間を省くため
②webpackやbabelなどの便利ツールを使用するため。

などがあります。

①アプリケーション開発時のパッケージ管理の手間を省くため

Reactでアプリケーション開発を行っていると、様々なパッケージを使う必要があるが、それらのパッケージ同士は相互に依存関係にあります。
例えば、「パッケージAはパッケージBのver X.X.X、パーッケージCのver X.X.Xがないと正常に動作しない。」というような状況が各パッケージ毎にあります。アプリケーションの開発者はこれらのパッケージのバージョンを適切に管理する必要があるのですが、ある程度のアプリになるとそのパッケージを手動で管理するのは非常に困難です。

Node.js環境で開発すると、パッケージを管理するためのnpmやyarnというツールを使用することでき、CLIからコマンドによりパッケージのインストールや依存関係の調整などが簡単に行うことができるのです。

②webpackやbabelなどの便利ツールを使用するため。

JavaScriptファイル、CSSファイルなどをバンドルするwebpack、最新のJavaScriptで書かれたコードを古いブラウザでも認識できる形にコンパイルするbabelなど、フロントエンド開発に欠かせないツールもNode.js環境があるために使用できています。CreateReactAppを利用しReact開発を始めた初心者は、あまり意識しない部分かもしれませんが、これもNode.jsの恩恵なのです。

終わりに

React界隈では名著の呼び声高い「りあクト!」を参考に勉強しました。作中で業務未経験には少しハードルが高いというニュアンスで書かれており、たしかにそうでしたが、おすすめです!
https://oukayuka.booth.pm/

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

【Node.js】json-server導入【Mock API】

概要

APIのモック用にjson-serverを導入したので主な処理をざっくりとまとめた

json-serverについて

簡単にモックAPIを作成できるnodeのライブラリ
主にテスト作成時に使われるもの

導入

$ yarn add json-server

または

$ npm install –save-dev json-server

実際に使ってみる

次の内容のmock.jsonを作成する

{
  "test": {
     "id": "mock_id",
     "text": "mock json desu"
  }
}

ターミナルで次のコマンドを実行

$ json-server mock.json

リクエストメソッドGET、エンドポイントhttp://localhost:3000/testを叩くと次の内容のレスポンスを取得できる

{
   "id": "mock_id",
   "text": "mock json desu"
}

解説

mock.jsonの第一階層のキー名がそのままエンドポイントになる
例えば次のようにmock.jsonを作成すればエンドポイントが/test/sampleのAPIのモックを作れる

{
  "test": {
     "id": "mock_id_1",
     "text": "mock json test"
  },
  "sample": {
     "id": "mock_id_2",
     "text": "mock json sample"
  }
}

リクエストメソッドは全てGETになる(仕様)
portの指定がなければ3000が割り振られる

オプションについて

-m {{ jsファイルのパス }}

APIモックが叩かれたらデータを取得する前に指定したjsファイルを実行してくれる
GET以外のリクエストメソッドのAPIのモックを作成したい時やトークンでの認証をする時などに使う

mock.json

{
  "test": {
     "id": "mock_id_1",
     "text": "mock json test"
  },
  "test_patch": {}
}

次の内容のmiddleware.jsを作成

module.exports = async function (req, _res, next) {
  // リクエストメソッドが PATCH の場合、リクエストURLに _patch をつけ、リクエストメソッドを GET に直す
  if (req.method === 'PATCH') {
    req.method = 'GET'
    req.url += '_patch'
  }
  next()
}

ターミナルで次のコマンドを実行

$ json-server mock.json -m middleware.js

リクエストメソッドPATCHhttp://localhost:3000/testを叩くと次のレスポンスを取得する

{}

--routes {{ jsonファイルのパス }}

エンドポイントが/test/sampleのような形になる場合やエンドポイントにクエリパラメータが含まれる場合に使う

mock.json

{
  "mock_1": {
     "id": "mock_id_1",
     "text": "mock json test"
  }
}

次の内容のroutes.jsonを作成

{
  "/test/sample": "/mock_1"
}

ターミナルで次のコマンドを実行

$ json-server mock.json --routes routes.json

http://localhost:3000/test/sampleを叩くと次のレスポンスを取得する

{
   "id": "mock_id_1",
   "text": "mock json test"
}

--host {{ host名 }}, -p {{ port番号 }}

ホスト名とポート番号を指定できる

おまけ

モックの数が増えるとmock.jsonの中身が煩雑になってくると思います
それの対策として他のファイルでjsonを作成して立ち上げ時にmock.jsonにまとめるという形にしました

次の内容のjsファイルを用意

const fs = require('fs')
const path = require('path')

const root = path.resolve('./', 'mocks')

const api = fs.readdirSync(root).reduce((api, file) => {
  // ファイル名を取得
  const endpoint = path.basename(file, path.extname(file))
  // ファイル名をキー名にする
  api[endpoint] = JSON.parse(fs.readFileSync(root + '/' + file, 'utf-8'))
  return api
}, {})

// 作成したjsonをmock.jsonに書き込む
fs.writeFile('./mock.json', JSON.stringify(api), err => {
  if (err) throw err
})

mocksフォルダを作成し、その中にファイル名がパスになるjsonファイルを作成する
エンドポイントごとにファイルを分けられるのでmock.jsonだけの状態よりはかなり見やすくなります
最後にサンプル用に作成したリポジトリを置いておきます

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

「Alexa、出勤!」で快適なリモートワークを

完成したAlexa

 こんな感じで会話をしながら、最終的にslackに投稿してくれるAlexa Skillを実装しました。

リモートワークの悩み

 きっとQiitaを見てる大半の人はエンジニア、そうでなくとも何かしらIT関係のお仕事をしている方が多数かと思います。コロナの影響で一気にリモート化が進んだIT業界、自らも気づけばフルリモート生活が長らく続いています。
 『出勤する時間が無くなった』、『無駄な会議が無くなって業務時間の短縮に繋がった』など、個人的にリモートワークに対してはポジティブな印象を抱いているのですが、中には「家事と仕事が同時に襲ってくる」「子供の世話で手が離せなくてストレスを感じてしまう」など、必ずしも良いことばかりでは無いという方も多いように見受けられます。そんな中、「家事とかしながらslackに簡単なメッセージ投稿できたら楽じゃね?」と思い、今回Alexaからslackに投稿できるスキルを実装しました。決して「これでベッドにいながら話しかけるだけで出勤!!」とかのために実装したのでは無いので悪しからず!

仕様

 下記のシーケンス図は正常系の処理になります。

system.png

(補足)
1. Skillの呼び出し名は「スラック」とする。「Alexa、スラック」や「Alexa、スラック起動して」などどと話しかければ、スキルが起動する。
2. 起動後に「Slackを起動しました。どの様に投稿しますか?」と聞き返す。ユーザーが投稿内容をつぶやいた後、「Slackに◯◯」と投稿してもよろしいですか?」と聞き返す。
4. 2の後、「はい、イエス、オッケー」などをユーザーが発話するとslackへの投稿を行う。
5. 2の後、「だめ、いや、ノー」などをユーザーが発話するともう一度「どの様に投稿しますか?」と聞く。
6. 2の後、「はい」や「いいえ」に関連するワード以外(例:キツネ)を発話すると「キツネと投稿しますよろしいですか?」と聞く。
7. 無事、Slackへの投稿が終了した場合、「Slackに◯◯と投稿しました。」と発話する。
8. 投稿するワークスペースは1つだけ。またchannnelも1つだけとする。
9. 何らかの原因で投稿が完了しなかった場合、その旨をユーザーに伝える。

Slack API

 SlackAPIを使い、投稿をポストできるように準備します。この方の記事の通り進めていけば問題なくできました。このアプリをslackのチャンネルに追加することで、投稿することが確認できました。

curl -X POST 'https://slack.com/api/chat.postMessage' \
-d 'token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-d 'channel=#general' \
-d 'text=Alexa Talk Appです。投稿してみたよ。'

curl -X POST 'https://slack.com/api/chat.postMessage' \
-d 'token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-d 'channel=#general' \
-d 'text=これはさっきと違ってslackAPIを利用することで僕の代わりにアプリが僕のアカウントで話してる'

上記のシェルスクリプトを実行して以下のように投稿できれば成功です。
スクリーンショット 2021-02-27 0.58.59.png

 slackに投稿する方法をググった際、これより先にwebhookを使う方法が出てきました。そちらの方法だと追加したアプリ自身が投稿することは簡単に出来たのですが、私自身のアカウントを使用して投稿したい場合、この方が簡単そうなので、今回はこちらの方法で実装していくことにしました。

Alexa Skill

 Alexa SkillからLambdaにきちんと投稿内容を飛ばせるようにするために簡単な設定を行います。Alexaにはインテントシノニムスロットを使って、幾つもの会話パターンを事前登録する機能があります。例えば以下のようにスロットを設定するとAlexaは{}部分に入るワードをリクエストjsonの中に組み込んで出力します。

{post}って投稿して
{post}ってお願い
{post}でよろしく

ただ毎回、毎回「って投稿して」って言うのも煩わしいので、今回は下記の通り3つのインテントスロットとスロットタイプを設定しました。

screencapture-developer-amazon-alexa-console-ask-build-custom-amzn1-ask-skill-0aee8890-1b58-4b2f-9872-2134294651ec-development-ja-JP-intents-PostToSlackIntent-2021-03-05-01_18_16.png

post_slot.png

reply_no_slot.png

reply_yes_slot.png

これで、この中のどれかの発言をした場合、Alexa側で指定されたスロットとしてlambdaにリクエストを飛ばしてくれます。ただ実際問題、どのスロットに該当しないワードを発話したい場合の方が殆どだと思います。 ((例)今日は休みます。)
 その場合、Alexa側で自動的にどれかのスロットに分類してリクエストを飛ばしてくるのですが、labda側で強制的にpost_slotに値をswapすることで、より自然なコミュニケーションになる様に工夫しています。

Lambda

 まず関数を適切なロールをアタッチして上で作成します。次にLambda側のトリガーに先ほど作成したAlexaSkill側のSkillIDを登録し、次にAlexa側にエンドポイントとしてLambdaのARNを登録します。設定が終わりましたら、以下のレポジトリ [GitHub] をローカルにクローンして、必要なモジュールをインストールしzipで圧縮後、先ほど作成したlambdaにソースコードをアップロードします。

# クローンしたディレクトリに移動後、初期化&必要なモジュールをインストール
$ npm install
$ npm install --save ask-sdk-core
$ npm install --save ask-sdk-model
$ npm install --save request

# 圧縮後lambdaにアップロード
$ zip -r {ファイル名} index.js node_modules

 尚、コード内にトークンを直書きするのも色々危ないので、lambda側でSLACK_ENDPOINTTOKENCHANNELの三つを環境変数として予め登録しています。また、AlexaSkillの方もインテントやエンドポイントの設定が終わった後にきちんとデプロイしないと、正しく動作しません。

あとがき

 「こんなの作ってもどうせ使わない」とか思う人も多いと思います。実際僕もそうでした(笑)ただ意外に使い出してみると結構手放せなくなるのがスマートスピーカーの良いところ。これは使ってみないと分かりません。ぜひ皆さんもAlexaいじってみてください(スマホからもアプリとしてインストールできます。)

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