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

簡単レシート印刷 receiptline を導入してみた

街のお店で iPad のレジをよく見かけるようになりましたね。
一般的にタブレット POS と呼ばれています。

おかげで?レシートプリンターがネットオークションやフリマアプリに出品されるようになりました。
業務用ってワクワクしませんか?個人でも利用できる業務用スーパーも人気がありますよね。

ネットには Raspberry Pi でレシートプリンターの制御にチャレンジしたブログもあって楽しそうです。
レシートプリンターの落札を試みつつ、レシート印刷にトライしてみようと思います。

レシートプリンターで印刷するには

レシートプリンターで印刷する手段はいろいろあるので、独断で整理してみました。

  • デスクトップアプリ向け
    • Windows プリンタードライバー
    • Linux や Mac の CUPS ドライバー
  • スマートフォン・タブレットアプリ向け
    • iOS 用 SDK ライブラリ
    • Android 用 SDK ライブラリ
  • コンソールとエスケープシーケンスが好きな人向け
    • StarPRNT コマンド
    • ESC/POS コマンド
  • 玄人向け
    • OPOS (Win32, .NET)
    • JavaPOS
  • オープンソース
    • GitHub に多数
    • Python, JavaScript, Java, PHP, Ruby, Go, ...

メーカーさんが提供しているものは、ドキュメントもサポートも充実しています。
ここで記事にする意味があるのは、オープンソース一択と言えると思います。

多種多様なオープンソースの中に、日本発のプロジェクトもありました。
https://github.com/receiptline/receiptline

JavaScript / Node.js の変換ライブラリです。
テキストを入力すると、SVG 画像やレシートプリンターのコマンドを出力します。
アスキーアート的に文字を並べると清書してくれるイメージですね。

おまけにプレビューできる開発ツールが付いています。
プレビューに対応する印刷手段は意外に少ないかもしれません。
これならレシートプリンターを持っていなくても試すことができます。

receiptline をセットアップ

開発する人

npm でインストール・実行して、http://localhost:10080/ を開きます。
https://www.npmjs.com/package/receiptline

$ npm i receiptline
$ cd node_modules/receiptline
$ npm start

一般の人

GitHub からダウンロード・展開して、designer/index.html を開きます。
https://github.com/receiptline/receiptline

hello, world!

開発ツールを使ってみましょう。

01.png

左側の黒い編集エリアに文字を入力してみます。
編集エリアの文字の大きさは Zoom スライダーで適当に調節。

ReceiptLine
hello, world!

入力すると、右側の白いレシート用紙にプレビューが表示されます。
文字列はレシート用紙の中央に配置されました。

02.png

レシート用紙の幅は Width スライダーで変更することができます。
単位はインチ・ミリではなく文字数 (桁数) となっています。

03.png

財布の中に入っていたレシートの多くは、1 行あたり漢字 16 文字 (32 桁) でした。
ところが、文字数が違うレシートや、幅広のレシートも・・・

混沌のレシート世界

昔の明和電機社長ブログから引用。
“レシートの印刷の大混乱ぶり、どうにかならんものか・・・”
https://www.maywadenki.com/blog/2011/05/17/post-bbf8/

これは今でも変わっていないと思います。
果たして混沌のレシート世界に秩序をもたらすことができるのか?

次回は文字装飾を試してみようと思います。

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

JavaScriptで+++は許されない+ ++は許される

+++,---とは

これらは一つの演算子ではなく、それぞれ+と++または++と+の組み合わせ、それの-番です。
わかりやすくいえば一つずつ増やして足していくということですね。

var a=0;
var b=13;
console.log(a+ ++b) // 14
a--;
console.log(a++ +b) // 13

これがスペースを開けずに+++にするとエラーが出ます。もちろん理由は解析できないからです。
ちなみに++-や--+は使えます。

なんか書いてたらごっちゃになってました。私が書きたかったことはこちらになります。

var b=13;
console.log(1+++b) // Uncaught SyntaxError: Invalid left-hand side expression in postfix operation
console.log(b+++1) // 14
console.log(1+ ++b) // 15
console.log(++b+1) // 15

つまり、+++は++と+という解釈になるということですね。なのでインクリメントをする際はスペースを開けるか変数を左に持っていく必要があります。

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

Node.jsとMongoDBを連携

今回はnode.jsとMongoDBの連携方法について簡単に解説していきます。

MongoDBの特徴

まず初めにMongoDBの特徴について解説します。

MongoDBの特徴として,以下のようなものが挙げられます。

(1)スキーマレスであるドキュメント指向データベースであること
・データはスキーマレスなドキュメントで格納され,任意のフィールドを好きなときに追加できる
・KVSでは苦手なValueを検索の条件としたり,ソート・集計を実現できる

(2)スケーラビリティに関する機能を標準機能として備えていること
・レプリケーション機能,オートフェールオーバー機能を備えている
・レンジパーティション機能,オートバランシング機能を備えている

(3)RDBと比較してRead/Writeの性能が高い
・トランザクション・リレーションを制限した結果,KVSに近いパフォーマンスを出せる

(4)開発のしやすさ
・どのような環境でもパフォーマンスが出るように,ネイティブソケットプロトコルを使用したドライバを主要なプログラミング言語で開発元が提供している
・RESTインターフェイスを標準で備えており,Webで広く普及しているJSONを使用してデータ送受信ができる

以上のような特徴があります。

MongoDBのインストール

それでは実際にMongoDBをインストールしていきましょう。

今回はHomebrewを使ってインストールしていきます。
Homebrewがインストールされていない場合はインストールしておきましょう。

以下のコマンドでインストールしていきます。
brew tap mongodb/brew

続いて、以下のコマンドでソフトウェアのパッケージをインストールします。
brew install mongodb-community

これでインストールは完了です。

実際に起動できるか確認してみましょう。

起動
brew services start mongodb-community

停止
brew services stop mongodb-community

これで問題なければOKです。

詳しくはこちらの公式を確認しましょう。

Node.jsとの接続

それでは実際にNode.jsからMongoDBに接続してみましょう。
まず、Sample/index.jsを作成してください。

次に、以下のコマンドでpackage.jsonを作成します。
npm init

次に、以下のコマンドでMongoDBのパッケージをインストールします。
npm install mongodb --save

これで準備はOKです。
それでは、コードを書いていきます。

index.js
var MongoClinet = require('mongodb').MongoClient;//MongoClient取得

var url = 'mongodb://localhost:27017/'; //今回はlocalhostなのでこの表記

MongoClinet.connect(url, (error, client) => {
  var db = client.db('sample');//どのDBを使用するか
  client.close();//操作を行った後に切断
});

異常が最低限必要なコードになります。
これでMongoDBの中のsampleというDBを操作する準備ができました。

しかしこのままでは接続できているのかよくわかりません。
なので実際に何か指示を書いてみましょう。

index.js
var MongoClinet = require('mongodb').MongoClient;

var url = 'mongodb://localhost:27017/';

MongoClinet.connect(url, (error, client) => {
  var db = client.db('sample');
  db.createCollection('test', (error, collection) => {
    client.close();
  });
});

上記のコードはsampleというDBに対してtestというcollectionを作成するという指示です。

それでは実行してみましょう。
node index.js

※実行前にローカル上でMongoDBが起動していることを確認しましょう
(起動していないと"TypeError: Cannot read property 'db' of undefined"というエラーが出ます)

次に実行結果の確認をします。

ターミナル上でMongoDBに接続し、確認します。
[手順]
1.mongo でMongoに接続
2.show dbsでDBのリストを確認
3.use sample でsampleというDBにアクセス
4.show collectionで中身を確認

"test"というcollectionが作成されていれば成功です。
これでNode.jsをMongoDBの接続し、collectionの作成に成功しました。

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

Expressのルーティング

これは何?

この記事はNode.jsのフレームワークのexpressのルーティングの自分がよく使う物を公式から抜粋したメモです。

基本的なルーティング

app.METHOD(PATH, HANDLER)

例:

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.post('/', (req, res) => {
  res.send('Got a POST request');
});

app.put('/target', (req, res) => {
  res.send('Got a PUT request at /target');
});

app.delete('/target', (req, res) => {
  res.send('Got a DELETE request at /target');
});

ルート・パス

正規表現などで引っかかっているパスにアクセスすることができる。(リクエストを実行できるエンドポイントを定義することができる)

例:

app.get('/random.text', (req, res) => {
  res.send('random.text')
})

app.get('/ab*cd', (req, res) => {
  res.send('ab*cd')
})

app.get(/a/, (req, res) => {
    res.send('(Regular expression) path with "a"')
})

app.get(/.*fly$/, (req, res) => {
  res.send('(Regular expression) /.*fly$/')
})

ルート・パラメータ

パスからパラメータ("key":"value")を取得ができる

app.get('/key1/:value1/key2/:value2', (req, res) => {
  res.send(req.params)
})

例:

ルート・パス: /flights/:from-:to
リクエストURL: http://localhost:3000/flights/LAX-SFO
req.params: { "from": "LAX", "to": "SFO" }

参考資料:

Express公式

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

そろそろlockファイルを理解するための最初のページ【composer.lock/package-lock.json】

.lockファイルって邪魔だよね。って思っている人いたら校舎裏来てください。優しく解説します。

こんにちは! @ykhirao です。最近ジョインさせていただいた案件で composer.lock のバージョンが本番が一番新しくて、ローカルが一番古い素敵な状況を発見しました :relaxed:

本番環境でSSHして composer update かけたんだなあーー。そっかーーー、バグ起きたらどないすんねん、。。。。。。

というのが私の感想で、実際にnpmパッケージを使ってバグを再現しながら
ゆっくり解説していこうと思います。どうぞ最後までよろしくお願いします。!!!

このQiitaを呼んで得ること

  • あーー、ほんとだ。バグが入る可能性があるんだ!
  • lockファイルはちゃんとコミットするね!

というお気持ちになれると思います。

このQiitaで解説しないこと

  • 詳しい依存関係の解消法
  • packageの公開の仕方
  • むずかしいはなし

です!

さて時系列を見てみよう!

こんな事故が起こる可能性がありますよって話をします。

時系列 OSSのmypackage.js ローカル 本番サーバー
1日目 v1.0.0公開 動いている 動いている
2日目 ローカルでmypackage.jsをinstall
動作確認OK、明後日本番に適応させる
3日目 v1.0.1公開 バグあり
4日目 本番サーバーで新しいコードを反映、install。本番が動かなくなってしまった。ぴえん
もちろんソースコードはローカルと同じだし、ローカルで動いていたのになんで…?:flushed:
5日目 v1.0.2公開 バグ修正された
6日目 v1.0.2を適応ローカル確認OK
今度はlockファイルを本番にアップロードする予定!
7日目 package-lock.jsonを使ってinstallする!今度は動いた!

npmでパッケージを作りながら説明する

OSSっぽい動作をするpackageフォルダと、ローカル環境と本番環境っぽいフォルダを作る。

yk@yk ~ % cd qiita 
yk@yk qiita % mkdir package
yk@yk qiita % mkdir local
yk@yk qiita % mkdir production
yk@yk qiita % ll
total 0
drwxr-xr-x   5 yk  staff   160  7 11 00:34 .
drwxr-xr-x+ 83 yk  staff  2656  7 11 00:33 ..
drwxr-xr-x   2 yk  staff    64  7 11 00:34 local
drwxr-xr-x   2 yk  staff    64  7 11 00:34 package
drwxr-xr-x   2 yk  staff    64  7 11 00:34 production
yk@yk qiita % cd package 
yk@yk package % npm init -y
Wrote to /Users/yk/qiita/package/package.json:

{
  "name": "package",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}


yk@yk package % vim package.json
yk@yk package % vim index.js
yk@yk package % npm publish --access=public
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN package@1.0.0 No description
npm WARN package@1.0.0 No repository field.

up to date in 0.429s
found 0 vulnerabilities

/Users/yk/.nodebrew/node/v13.8.0/lib/node_modules/package -> /Users/yk/qiita/package

yk@yk package % cat index.js 
const text = "sample"

module.exports = text;

index.jsにただただ "sample" という文字列を返す動作を記述して、パッケージとして認識させる。
@y_hirao/mypackage というパッケージをnpmに公開した。

localフォルダでいろいろゴリゴリしてみる。

yk@yk local % npm init -y
Wrote to /Users/yk/qiita/local/package.json:

{
  "name": "local",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@y_hirao/mypackage": "^1.0.0"
  },
  "devDependencies": {},
  "description": ""
}


yk@yk local % cat index.js 
const text = require("@y_hirao/mypackage");
console.log(text)

yk@yk local % node index.js 
sample

sampleという文字列が返却されました。!!!!!!!!!

このときpackage.jsonを見ると ^ キャレット指定なのでバージョンアップは 1.系 は守られるけど残りはすべてアップデートされます。

  "dependencies": {
    "@y_hirao/mypackage": "^1.0.0"
  },

さてパッケージの方を更新します。 v1.0.2 にしましょう!

yk@yk package % cat package.json 
{
  "name": "@y_hirao/mypackage",
  "version": "1.0.2",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

yk@yk package % cat index.js    
const text = "sample2"
throw 'エラーを出したい気分';

module.exports = text;
yk@yk package % npm publish   

このパッケージをそのまま使うとthrowされます。

さてローカルでinstallしてみましょう!

yk@yk local % npm install
npm WARN local@1.0.0 No description
npm WARN local@1.0.0 No repository field.

audited 1 package in 0.411s
found 0 vulnerabilities

yk@yk

あれ、エラーが起きませんね。
これは 一度ダウンロードしたパッケージはlockファイルというものでバージョン指定されているので、新しく勝手にバージョンがあがったりしないのです。

さてローカルから本番環境に package.json と index.js をコピーしてnpm installして動かしてみましょう!

yk@yk production % cp ../local/package.json package.json
yk@yk production % cp ../local/index.js index.js        
yk@yk production % npm i
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN local@1.0.0 No description
npm WARN local@1.0.0 No repository field.

added 1 package and audited 1 package in 2.811s
found 0 vulnerabilities

yk@yk production % node index.js 

/Users/yk/qiita/production/node_modules/@y_hirao/mypackage/index.js:2
throw 'エラーを出したい気分';
^
エラーを出したい気分
(Use `node --trace-uncaught ...` to show where the exception was thrown)

さて、、、本番環境でinstallを走らせるとエラーがおきました。。。。

npm install したときに package-lock.json がないと package.json を使って ^1.0.0 が指定されているので 1.系で一番新しいもの つまり今回だとバグが混入している v1.0.2 がインストールされたことになります。

lockファイルを見てみましょう。

yk@yk production % cat package-lock.json 
{
  "name": "local",
  "version": "1.0.0",
  "lockfileVersion": 1,
  "requires": true,
  "dependencies": {
    "@y_hirao/mypackage": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/@y_hirao/mypackage/-/mypackage-1.0.2.tgz",
      "integrity": "sha512-W2RoQsC1FVnHxximVJMovEvfl/3WNI95EjGxPbMlmyuDZ+0SImS76dOII/0AiP4cVVjXZUbFzaLs9h6l8TrrFQ=="
    }
  }
}

まさしく v1.0.2 が指定されていますね!localだともちろん最初に npm install したときに最新だった @y_hirao/mypackagev1.0.0 が使われています。

yk@yk local % cat package-lock.json 
{
  "name": "local",
  "version": "1.0.0",
  "lockfileVersion": 1,
  "requires": true,
  "dependencies": {
    "@y_hirao/mypackage": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/@y_hirao/mypackage/-/mypackage-1.0.0.tgz",
      "integrity": "sha512-auQ5grIpWd0IRkMR3rn6xRjIhGZqBu/Q/g1lDkS5AWakAysrZ3iQAIRngbgBGBAFlPZxQ/LCVYdAW+3VLxeSEw=="
    }
  }
}

更にインストールされているフォルダを確認しても

yk@yk production % cat node_modules/@y_hirao/mypackage/index.js
const text = "sample2"
throw 'エラーを出したい気分';

module.exports = text;
yk@yk production % 

どう見てもエラーが起きそうです。

package-lock.jsonをlocalからコピーしてきましょう。

yk@yk production % cp ../local/package-lock.json package-lock.json
yk@yk production % npm i
npm WARN local@1.0.0 No description
npm WARN local@1.0.0 No repository field.

updated 1 package and audited 1 package in 0.45s
found 0 vulnerabilities

yk@yk production % cat node_modules/@y_hirao/mypackage/index.js
const text = "sample"

module.exports = text;
yk@yk production % node index.js 
sample
yk@yk production % 

lockファイルを持ってきてインストールするだけで、エラーが起きなくなりました! :clap::clap::clap::clap::clap:

まとめ

本番環境で lockファイルごと更新する composer update とかlockファイルの存在しない状態での npm install とか、そんなことはやめましょう。ってことを主張したいです!!!!!

ローカルでしっかり確認してlockファイルを作り、それを本番にアップロードして、lockファイルの状態で依存パッケージをインストールしちゃってください。。 :pray:

インストールする時期によって最新のバージョンが使われるので、もしそのバージョンにバグがあるのなら本番死んじゃいますよ。。

終わりに

新しい会社に入って色々根本的に変えたいところがあるので、最近はdevopsの領域をごりごり触らせていただいてます。環境構築、開発フローの策定とかもろもろやらせてもらっているのでかなり楽しいです :muscle:

読んでいただきありがとうございました。lockファイル入門したい方、事故りそうな不安があるかたは同僚と一緒に「弊社のパッケージ依存関係の運用どうする…?」と一度話し合ってみてください。

ありがとうございました。

.

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

[JavaScript] express() で "express is not a function" ついでに TS の "export =" と "import = require()"

Expressを読み込んだ際に express is not a function と出たので原因と解決策を共有します。
あとついでに export = と import = require() についてです。

環境

import側はJavaScript、トランスパイルとかは一切なし。
node: v14.1.0

package.json
{
  ...
  "type": "module",
  "dependencies": {
    "express": "^4.17.1",
    ...
  },
  ...
}

再現VTR

index.js
import * as express from "express";
const app = express();
node ./index.js

実行すると

const app = express();
            ^
TypeError: express is not a function

エラー発生。
因みに、USAGEに従っていた。:thinking: 1

@types/express/index.d.ts
/* =================== USAGE ===================

    import * as express from "express";
    var app = express();

 =============================================== */

原因

CommonJSとESModulesdでの返却される値に違いがあった。

import * as express from "express";
console.log(typeof express); // => object
const express = require("express");
console.log(typeof express); // => function
import
default: [Function: createApplication] { ... }
require
[Function: createApplication] { ... }

つまり、返却値がdefault exportとなっているため参照エラーを起こしていた。

対応策

こうする。

import express from "express";
const app = express();

または、

import * as express from "express";
const app = express.default();

そもそもトランスパイルもせずに使うなら、CommonJSモジュールならCommonJSのインポート (const express = require("express");) で読み込むのがベターっていうツッコミは覚悟してます!

以降おまけ

export =

名前は「エクスポート代入」。
Expressの型定義ファイルを覗くとこうなっている。

@types/express/index.d.ts
...
/**
 * Creates an Express application. The express() function is a top-level function exported by the express module.
 */
declare function e(): core.Express;
...
export = e;

CommonJSとAMDを考慮せずにエクスポートできる便利機能。
言い換えればこれは、CommonJSまたはAMDのモジュールだよ。っていう印。

import = require()

名前は「インポート代入」。
エクスポート代入(export =)を使用してエクスポートされたモジュールをインポートする際に使われていたらしい。
今ではあえて使う理由はなさそう。

インポート代入、インポート代入の使用例

// export側
function hoge() {
  return 'hoge';
}
const fuga = 'fuga';
export = {
  hoge,
  fuga
};

// import側
import hogefuga = require('./export');
console.log(hogefuga); // => { hoge: [Function: hoge], fuga: 'fuga' }

感想

地味に時間を溶かしたため記事にしてやったぜ。。
何かご指摘等あればコメントいただけると幸いです。

参考

export = and import = require()

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