- 投稿日:2021-03-06T16:17:11+09:00
Node.jsのモジュールを使ってHTML, CSS, JavaScriptを軽量化・難読化する手順
はじめに
Windows環境で、Node.jsのモジュールを使って以下を行う手順をまとめます。
- HTML, CSSの軽量化(minify)
- JavaScriptの難読化(uglify)
使用モジュール
- html-minifier → HTMLファイルの軽量化モジュール
- clean-css-cli → CSSファイルの軽量化モジュール
- uglify-es → JavaScriptファイルの難読化モジュール
準備:モジュールのインストール
Node.jsを取得しインストールする。→ https://nodejs.org/ja/
Node.js command promptを起動する。
以下のコマンドを実行する。(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.htmlCSSの軽量化
$ cleancss -o original.min.css original.cssJavaScriptの難読化
$ uglifyjs original.js -c --compress --mangle --output original.min.js関連記事
- 投稿日:2021-03-06T16:17:11+09:00
Node.jsを使ってHTML, CSS, JavaScriptを軽量化・難読化する手順
はじめに
Windows環境で、Node.jsのモジュールを使って以下を行う手順をまとめます。
- HTML, CSSの軽量化(minify)
- JavaScriptの難読化(uglify)
使用モジュール
- html-minifier → HTMLファイルの軽量化モジュール
- clean-css-cli → CSSファイルの軽量化モジュール
- uglify-es → JavaScriptファイルの難読化モジュール
準備:モジュールのインストール
Node.jsを取得しインストールする。→ https://nodejs.org/ja/
Node.js command promptを起動する。
以下のコマンドを実行する。(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.htmlCSSの軽量化
$ cleancss -o original.min.css original.cssJavaScriptの難読化
$ uglifyjs original.js -c --compress --mangle --output original.min.js関連記事
- 投稿日:2021-03-06T14:43:09+09:00
DockerコンテナでNode.jsを実行してみた
前の記事に引き続き、今回はコンテナでNode.jsのアプリケーションを動かし、ブラウザから開いてみることに挑戦してみました。
実装は以下の手順で行いました。
- Node.jsアプリの作成
- Dockerfileの作成
- Dockerfileのビルド
- コンテナの起動
- ブラウザとアプリの接続
Node.jsアプリの作成
localhost:8080
を開いたときにHi there
がブラウザに表示されることを目指します。
package.json
とindex.js
の中身は以下のようにします。package.json{ "dependencies": { "express": "*" }, "scripts": { "start": "node index.js" } }index.jsconst 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イメージは軽量であるがゆえに、node
もnpm
もプリインストールされていないからです。そのため、ベースイメージには
node
やnpm
がプリインストールされているnodeイメージなどを選択する必要があります。ただ、nodeイメージにはnpmやnode以外にもテキストエディタツールなどの余計なプログラムもプリインストールされているので、軽量なalpineにnpm
とnode
がプリインストールされたnode:alpine
やnode: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コンテナの起動も正常にできたみたいなのでこれで成功!といきたいところなのですが、ブラウザからアプリが開けません...えっ?
ポートマッピング
アプリが開けなかったのは、コンテナのポート8080とローカルホストのポート8080が接続されていなかったためです。
ブラウザからlocalhost:8080
にアクセスする際、localhost(ローカルPC)のポートに接続しようとします。ただ、今回はコンテナの中でNode.jsのアプリケーションを実行しているため、コンテナのポートと接続する必要があります。
ローカルPCとコンテナのポートを紐付けることをポートマッピングと呼びます。
ポートマッピングを実行するためにはdocker run -p 8080:8080 [image id]
コマンドを実行します。コンテナの作成・起動とポートマッピングを同時に実行してくれます。キャッシュの利用
アプリは開けるようになったのですが、気になる部分が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について学習します。
参考資料
- 投稿日:2021-03-06T14:23:37+09:00
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/
- 投稿日:2021-03-06T00:16:44+09:00
【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リクエストメソッド
PATCH
、http://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
だけの状態よりはかなり見やすくなります
最後にサンプル用に作成したリポジトリを置いておきます
- 投稿日:2021-03-06T00:14:34+09:00
「Alexa、出勤!」で快適なリモートワークを
完成したAlexa
こんな感じで会話をしながら、最終的にslackに投稿してくれるAlexa Skillを実装しました。
Alexaからslackに投稿できるスキル作ったhttps://t.co/uvWrFhfqLl
— Takayoshi Makabe (@Takayoshi_ma) March 5, 2021リモートワークの悩み
きっとQiitaを見てる大半の人はエンジニア、そうでなくとも何かしらIT関係のお仕事をしている方が多数かと思います。コロナの影響で一気にリモート化が進んだIT業界、自らも気づけばフルリモート生活が長らく続いています。
『出勤する時間が無くなった』、『無駄な会議が無くなって業務時間の短縮に繋がった』など、個人的にリモートワークに対してはポジティブな印象を抱いているのですが、中には「家事と仕事が同時に襲ってくる」、「子供の世話で手が離せなくてストレスを感じてしまう」など、必ずしも良いことばかりでは無いという方も多いように見受けられます。そんな中、「家事とかしながらslackに簡単なメッセージ投稿できたら楽じゃね?」と思い、今回Alexaからslackに投稿できるスキルを実装しました。決して「これでベッドにいながら話しかけるだけで出勤!!」とかのために実装したのでは無いので悪しからず!仕様
下記のシーケンス図は正常系の処理になります。
(補足)
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を利用することで僕の代わりにアプリが僕のアカウントで話してる'上記のシェルスクリプトを実行して以下のように投稿できれば成功です。
slackに投稿する方法をググった際、これより先にwebhookを使う方法が出てきました。そちらの方法だと追加したアプリ自身が投稿することは簡単に出来たのですが、私自身のアカウントを使用して投稿したい場合、この方が簡単そうなので、今回はこちらの方法で実装していくことにしました。
Alexa Skill
Alexa SkillからLambdaにきちんと投稿内容を飛ばせるようにするために簡単な設定を行います。Alexaにはインテントやシノニム、スロットを使って、幾つもの会話パターンを事前登録する機能があります。例えば以下のようにスロットを設定するとAlexaは{}部分に入るワードをリクエストjsonの中に組み込んで出力します。
{post}って投稿して {post}ってお願い {post}でよろしくただ毎回、毎回「って投稿して」って言うのも煩わしいので、今回は下記の通り3つのインテントスロットとスロットタイプを設定しました。
これで、この中のどれかの発言をした場合、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_ENDPOINT
、TOKEN
、CHANNEL
の三つを環境変数として予め登録しています。また、AlexaSkillの方もインテントやエンドポイントの設定が終わった後にきちんとデプロイしないと、正しく動作しません。あとがき
「こんなの作ってもどうせ使わない」とか思う人も多いと思います。実際僕もそうでした(笑)ただ意外に使い出してみると結構手放せなくなるのがスマートスピーカーの良いところ。これは使ってみないと分かりません。ぜひ皆さんもAlexaいじってみてください(スマホからもアプリとしてインストールできます。)