20190701のNode.jsに関する記事は8件です。

″ャ」レ文字に変換するライブラリをイ乍っτゐナニ

イ士亊㊥暇ナニ″っナニヵゝら ″ャ」レ文字変才奐ラィ┐″ラ└|をイ乍っτ、 npm τ″公開ιτゐιナニ :sparkles:

イ乍っナニも@

https://www.npmjs.com/package/galmoji

イ吏レヽ方

const galmoji = require('galmoji')

galmoji('おじさんギャル文字ライブラリ作ったヨ?(^з<)?')
// ぉι″、ナω≠″ャ」レ文字ラィ┐″ラ└|イ乍っナニ∋?(^з<)?

ゐωナょもイ吏っτね!

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

ひとまずのsassコンパイル用gulpfile.js設定

gulp導入しました。
引き続きgulpです。

gulpfile.js設定

gulp4だと3系の記事を参照していたらエラー吐きまくったので、バージョンは気をつけましょう。

追加したモジュール

  • gulp-sass
  • gulp-plumber
  • gulp-notify

それぞれインストールしてください。

sassコンパイル用

npm install gulp-sass --save-dev


エラー時に監視を止めない

npm install gulp-plumber --save-dev


エラーコードのポップアップ表示

npm install gulp-notify --save-dev


それらを反映した設定ファイル

gulpfile.js
var gulp = require("gulp");
var sass = require("gulp-sass");
var plumber = require('gulp-plumber');
var notify = require('gulp-notify');

//sassコンパイル
gulp.task("sass",function(done){
    gulp.src("sass/*.scss")
    .pipe(plumber({errorHandler: notify.onError('<%= error.message %>')}))
    .pipe(sass({outputStyle: 'expanded'}))
    .pipe(gulp.dest("./css"));
    done();
});

//動作設定
gulp.task("default", gulp.series('sass', function(done){
    gulp.watch("sass/*.scss", gulp.series('sass'));
    done();
}));


これを使用するプロジェクトフォルダに配置。
該当のフォルダにcdで移動後、gulpで開始します。

$ gulp

終了するときは「ctrl + c」です。

さらにbrowser-sync加える

ファイルを更新すると同時にブラウザも更新してくれます。
複数のブラウザを開いている状態で、ページ遷移、スクロールなどを同期してくれます。

npm install browser-sync --save-dev
gulpfile.js
var gulp = require("gulp");
var sass = require("gulp-sass");
var plumber = require('gulp-plumber');
var notify = require('gulp-notify');
var browserSync =require('browser-sync');

//sass
gulp.task("sass",function(done){
    gulp.src("sass/*.scss")
    .pipe(plumber({errorHandler: notify.onError('<%= error.message %>')}))
    .pipe(sass({outputStyle: 'expanded'}))
    .pipe(gulp.dest("./css"));
    done();
});


//ブラウザ同期
gulp.task('browser-sync', function(done) {
    browserSync({
        proxy: "http://hogehoge" //MAMPなどで設定したバーチャルホスト
    });
    done();
});

//ブラウザリロード
gulp.task('bs-reload', function (done) {
    browserSync.reload();
    done();
});


//動作設定
gulp.task('default', gulp.series('browser-sync', function (done) {
    gulp.watch("sass/*.scss", gulp.series('sass'));

    gulp.watch("./*.html",      gulp.series('bs-reload'));
    gulp.watch("./**/*.html",   gulp.series('bs-reload'));
    gulp.watch("./css/*.css",   gulp.series('bs-reload'));
    gulp.watch("./js/*.js",     gulp.series('bs-reload'));
    done();
}));

MAMPで設定しなくてもbrowser-syncでローカル環境は作ってくれますが、PHP環境などは対応していないので、やはり動的サイトではMAMPを入れたほうが良さそうです。

MAMPについてはこちら
MAMPのインストール&初期設定+αをしてみる

完全な静的サイトだったら、browser-syncの部分を下記に書き換えるとMAMPなしでローカル環境を作ってくれます。

gulpfile.js
//ブラウザ同期
gulp.task('browser-sync', function(done) {
    browserSync({
        server: {
            baseDir: "/",
            index: "index.html"
        }
    });
    done();
});

公式サイトのオプション一覧

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

gulpインストールと一括管理用のフォルダ構成

gulp導入しました。
とりあえず、インストール用のメモ。
導入自体はNodeとnpm入れてれば簡単にできます。

グローバルインストールやらローカルインストールやらなんのこっちゃって感じだったのですが、
(グローバルにインストールしたら、ローカルはいらないのかと思ったら、そうでもないようで...)
管理も面倒だし、ひとまずはローカルだけでいいやという結論です。

事前準備

  • Node.js
  • npm (Node.jsのパッケージ管理)

フォルダ構成の準備

ローカルインストールだと、フォルダごと、プロジェクトごとにgulpをいれなきゃいけないのが面倒だとおもうので、gulpはひとつで、gulpfile.js(gulpの設定ファイル)のみ、プロジェクトごとの管理にします。

準備段階の構成例

/親フォルダ/
  └ /プロジェクト1/
    └ index.html
  └ /プロジェクト2/
    └ index.html
これを準備してください。

最終的な構成目標

/親フォルダ/
  └ /プロジェクト1/
    └ index.html
    └ gulpfile.js (gulpの設定ファイル)
    └ node_modules (node_modulesのエイリアス)
  └ /プロジェクト2/
    └ index.html
    └ gulpfile.js (gulpの設定ファイル)
    └ node_modules (node_modulesのエイリアス)
  └ /node_modules/ (モジュール管理フォルダ)
  └ package.json (Node.jsのpackage管理ファイル)

package.json作成

まずはcdで親フォルダまで移動して、下記のコマンドを入れます。

$ npm init

色々聞かれますが、全てenter(return)で大丈夫です。
これでpackage.jsonが作成されます。

gulpのインストール

ローカルインストール(--save-dev--save

$ npm install gulp --save-dev

--saveでインストールすると、webサイトに使用するデータと見なされるので、
--save-devで、開発用のデータですよ、と分類してあげてるみたいです。

ちなみにグローバルインストール

$ npm install -g gulp

これで/node_modules/が生成されます。
この中にモジュールがインストールされます。

/node_modules/のエイリアス作成

いわゆるショートカットです。右クリックから作成して、それぞれのプロジェクト内に配置します。
このとき、名前は全て「node_modules」にしてください。

エイリアスを作成すると、きちんと参照先のnode_modulesを読んでくれるので、
gulpの管理がひとつで済みます。

現在のフォルダ構成
/親フォルダ/
  └ /プロジェクト1/
    └ index.html
    └ node_modules (node_modulesのエイリアス)
  └ /プロジェクト2/
    └ index.html
    └ node_modules (node_modulesのエイリアス)
  └ /node_modules/ (モジュール管理フォルダ)
  └ package.json (Node.jsのpackage管理ファイル)

gulpfile.jsの作成

それぞれのプロジェクトに合わせて、設定ファイルを作ります。

/親フォルダ/
  └ /プロジェクト1/
    └ index.html
    └ gulpfile.js (gulpの設定ファイル) ←これです
    └ node_modules (node_modulesのエイリアス)
  └ /プロジェクト2/
    └ index.html
    └ gulpfile.js (gulpの設定ファイル)
    └ node_modules (node_modulesのエイリアス)
  └ /node_modules/ (モジュール管理フォルダ)
  └ package.json (Node.jsのpackage管理ファイル)

gulpfile.jsについては、それについてだけの記事がいいので、ちょっと分けます。

gulpfile.jsの記事書きました。

ひとまずのsassコンパイル用gulpfile.js設定

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

ElectronとC++開発環境

screen

19/07/01 Qiitaに画像ファイルがアップロードしにくい(やたら時間がかかってる)ので、あとでアップロードします。

今回のコンセプト

  • C++部分はElectronと連動しながらVisual Studio 2017でデバッグする。(C++11に対応していたら別バージョンでも使えるらしい)
  • node.jsはnodist仮想環境を使う(node.jsのバージョンが合うなら他の方法でも可能)
  • ビルド時にpython2.7使うのでAnacondaの仮想環境を使う(python2.7が動けば他の方法でも可)
  • node.jsパッケージはプロジェクトディレクトリのnode_modulesに保存して、そこから使う。
  • electron-rebuildは使わずnode-gypを使う。
  • Electronは5.0.5(新しいバージョンでやってみたいだけ)
  • 作りやすく、やり直しやすい環境構築を目指す。

開発環境

  • Windows 10 (64bit)
  • Visual Studio 2017
  • nodist : node.js環境作成
  • Anaconda : 一部python2.7バージョンを使うため

C++で開発する2種類の方法

native addon

node-gypを使ってC++をビルド。こちらを使う。

ffi

npm install ffiでインストールする方法。
この方法は、かなり制限(WinではElectronがバージョン3(nodeのバージョンのため)までしか対応してないとか、エラー地獄にあったりとか)があるので今回は使用しない。

nodistの設定

今回はElectron5.0.5を使うのでnode.js12以上が必要です。
とりあえず以下を実行して使いたいバージョンを用意。
Electronに必要な対応するnode.jsのバージョンはRelease noteに書いてあります。

rem 使用可能なnodeバージョン一覧
nodist dist
rem 使いやすそうなnode.jsのバージョンを選択してダウンロード
nodist + 12.4.0
rem ダウンロード済みの中で使用したいバージョンを指定
nodist use 12.4.0
rem 恒久的に今後同じバージョンを指定する場合はglobalで設定する
nodist global 12.4.0

Anacondaの設定

node-gypelectron-rebuildとかのライブラリでpython2.7を使うのでAnacondaにインストール

rem py27という名前で作成
conda create -n py27 python=2.7

プロジェクトの作成

[undefined]()

普通にフォルダ作ってるだけです。

rem 例としてexampleという名前
mkdir examples
cd examples

プロジェクト作成

package.json作成

rem conda でpython27に変更
activate py27
rem nodistでnode.jsのバージョンを指定
nodist use 12.4.0
rem node初期化
rem 対話型で内容を設定
npm init

Electronとnode-gypをインストール

rem プロジェクトに保存してそこから実行する予定
npm install --save-dev electron@5.0.5
npm install --save-dev node-gyp@5.0.1

なんかエラー出たときは、package-lock.jsonを削除するとうまくいくかも

ファイルを用意

Hello Worldします。

node/test/addons/hello-world at master · nodejs/node · GitHub

スクリプトはこちらを参考にしました。

node-gypまたはnanを使ってnative addonを作る方法 - DJ lemon-Sour's diary (prod.hisasann)

HTML

ファイル名はindex.html

index.html
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>Example</title></head>
<body>
<div id='test'></div>
<button onclick="testFunc()">test button</button>
<script>
    function testFunc(){
        var remote = require('electron').remote;
        var testC = require('./build/Debug/testFunction');
        document.getElementById('test').innerText = "hello " + testC.hello();
    }
</script>
</body>
</html>

Electron用JS

ファイル名はindex.js

index.js
"use strict";
const electron = require("electron");
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
let mainWindow;

// 閉じたときのイベント
app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

// 初期化後
app.on('ready', function() {
  mainWindow = new BrowserWindow({
      width: 800, height: 600,
      webPreferences: {
          // Electron5以降ではこれがFalseになっていて、index.html側でrequireが使えないのでTrueにする(後述)
        nodeIntegration: true
  }
  });
  mainWindow.loadURL('file://' + __dirname + '/index.html');
  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});

注意

今回は簡単に説明したいのでnodeIntegrationという値をtrueにしてますが、セキュリティ的に宜しく無いらしいので、適当に変更してください。

Electron Webviewのセキュリティで注意すべきこと - Qiita

package.json

package.jsonは先の初期化時に生成されているはずですが、"main": "index.js",となっていない場合(index.jsがメインファイルでない場合)は、そのように直しておく。

binding.gyp

node-gypが使用するビルド用の設定ファイル。
ファイル名はbinding.gypで固定

binding.gyp
{
  "targets": [
    {
      "target_name": "testFunction",
      "sources": [
        "test.cc"
      ]
    },
  ]
}

test.cc

test.cc
#include <node.h>
#include <v8.h>

void Method(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  v8::HandleScope scope(isolate);
  args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, "world"));
}

void init(v8::Local<v8::Object> exports) {
  NODE_SET_METHOD(exports, "hello", Method);
}

NODE_MODULE(binding, init);

ビルド

ファイルができたらビルドしてみる。

Using Native Node Modules | Electron

electron-rebuildを使う方法もあるが、環境によってはうまく使いたいnode-gypのバージョンで使えなかったのでnode-gypでビルドする。

rem conda でpython27に変更
activate py27
rem nodistでnode.jsのバージョンを指定
nodist use 12.4.0
rem プロジェクトディレクトリに保存したnode_modules内のnode-gypを使ってビルド
.\node_modules\.bin\node-gyp.cmd rebuild --target=5.0.5 --arch=x64 --msvs_version=2017 --dist-url=https://electronjs.org/headers --debug

引数は以下

引数 内容
--target 5.0.5 Electronのバージョン
--arch=x64 x64 32bitか64bitか
--msvs_version 2017 Visual Studioのバージョン
--dist-url https://electronjs.org/headers この引数を加えることでElectronのビルドであることをnode-gypに伝える
--debug デバッグでビルド

引数一覧

実行

以下で実行。
ウィンドウが表示されて、ボタンを押したらHelloWorldが表示されればOK

.\node_modules\.bin\electron .

デバッグ

Visual Studio でデバッグしたいのでデバッグ用のプロジェクトを新たに作成します。

Visual Studio 2017で新しく「空のプロジェクト」を作成します。

対象のファイルを追加

プロジェクト名を右クリック->追加->既存の項目(G)...を選択して、デバッグの対象にしたいC++ファイルtest.ccを選択して追加。

追加されたファイルを右クリックしてプロパティを開く。

構成プロパティ->全般->ビルドから除外

を「はい」に設定。

デバッグ用のコマンドを設定

プロジェクトのプロパティ->構成プロパティ->デバッグ->コマンド

$(ProjectDir)..\..\node_modules\.bin\electron.cmd

同じく、コマンド引数

$(ProjectDir)..\..\.

に設定。

実行

設定後、普通にデバッグ->デバッグの開始を選択か、「ローカル Windows デバッガー」ボタンをクリック

アタッチ

デバッグ->プロセスにアタッチを選択して、electronという項目を探して、「タイトル」が空白のものを選択してアタッチする。(2個項目があるが、恐らくUIDが後の方だと思うが、シフトキーを押しながら複数選択のほうが確実かも)

ソリューションエクスプローラーのtestFunction/test.ccMethod関数のどこかにブレークポイントを設定して、Electron上のボタンを押すと、そのブレークポイントで停止します。これでデバッグができるようになりました。

アタッチについて

デバッグ実行ごとに上記アタッチの作業が必要になる。
node_modules\electron\dist\electron.exeをデバッグ時に自動的にアタッチできればもう少し楽できるかも。

その他設定

絶対ではないけど、やっておくと便利程度

デバッグ時にビルドも

今回のデバッグの設定はビルドをしていない。
ビルドもしておきたい場合は以下のようなバッチファイルをbuild.cmdという名前で用意して、

cd %~dp0
call activate py27
call nodist use 12.4.0
node_modules\.bin\node-gyp.cmd rebuild --target=5.0.5 --arch=x64 --msvs_version=2017 --dist-url=https://electronjs.org/headers --debug

ビルド前コマンドに以下のような内容を書いておけばビルドもされる。

..\..\build.cmd

説明

Electronとnode.jsとNODE_MODULE_VERSIONについて

Electronの指定をしないで普通のnode.jsでnode-gypを使ってビルドすると、NODE_MODULE_VERSIONが違う旨のエラーが表示される。
NODE_MODULE_VERSIONはABI(アプリケーションバイナリインタフェース)のバージョン番号で、普通のnode.jsとelectronと違うものが振られており、たとえ同じnode.jsとnpmのバージョンを使用してnode-gypでビルドしても上手く動作してくれません。(どこかにコレではないリストでElectronも含めたNODE_MODULE_VERSION一覧表があったはずだがURLを忘れた)

Electron から native module を使うときの NODE_MODULE_VERSION のエラー - 理系学生日記

参考

Using Native Node Modules | Electron

リリース一覧 | Node.js

Electron から native module を使うときの NODE_MODULE_VERSION のエラー - 理系学生日記

その他参考

Electronアプリを公開するまでにやったことノウハウまとめ - Qiita

とはいえ

デバッグ毎にアタッチするのはめんどくさいので、C++側はCLIとかで別途デバッグして、UI部分との結合用に使う程度が良いかも。

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

# Node.jsとTypeScriptによる高速かつ軽量なWebシステム構築1 ~ 地獄の門前 ~

Node.jsとTypeScriptによる高速かつ軽量なWebシステム構築1 ~ 地獄の門前 ~

1.はじめに

 ツリー型情報掲載システム(Node.js+TypeScript版)
 ソースコード

 Node.jsとTypeScriptで上記のものを作ったので、このあたりの開発に関する話をしていきます。今回は導入部分です。

output_1.gif

2.Node.jsによる完全包囲

 Node.jsはJavaScriptを好きな場所で走らせることが出来るフレームワークとして、様々な場所で使われている。

  • VSCodeのようなデスクトップアプリとそのプラグイン
  • 開発ツールと制御用スクリプト
  • バックエンドサービス
  • 色々なツール類

 VSCodeにはかなりお世話になっている。初期バージョンの頃はあんまり使えないという認識だったのだが、その後の進化は凄まじいものがあった。Node.jsを使えばそんなデスクトップアプリから、ちょっとしたコマンドまで色々なものが開発可能だ。もちろんWebアプリを作るときのバックエンドのプログラムを作ることも出来る。そして、そういったプログラムを作るときの開発環境も一通りNode.jsで作られている。既にNode.jsからは逃げられない世界が構築されているのだ。

 Node.jsで何に使うのと聞かれたら、「作れるものが多すぎて、一概には答えられない」という、質問した人間が不満にしか思わないような回答になってしまうのである。

3.異世界転移のJavaScriptと自らを縛るTypeScript

 JavaScriptはクセの強い言語だ。書きたい処理を書くのは簡単なのだが、実は仕様が複雑で、なんだかよく分からないけれど動いているから大丈夫なのだろうというプログラムを書いてしまいがちである。コールバックされたときに今持っているthisが何のインスタンスを示すのか、外側のブロックから拾ってきた変数のデータがいつのものなのか、気を抜いてうっかりしていると命を取られかねない。

 受け取った変数のパラメータの取り方は本当に正しいのか、オブジェクトの中身がどうなっているのか、うろ覚えのプロパティ名前が本当に合っているのか、実は一瞬たりとも気を休められない。しかし本当に恐ろしいのは、実は間違っているのに何事も無かったかのように動くことにある。好き勝手に色々書いていたら、いつの間にかそこが異世界と化しているのだ。

 この危険を回避するにはJavaScript単体の使用をやめ、TypeScriptで自らを拘束する以外に方法が無い。自らの意思で手かせを付け、足に鉄球と鎖を巻き付けるのだ。身動きがとれない苦しみと引き換えに、突然の異世界転移は防ぐことが出来る。異世界で無双するのは「なろう」だけで十分である。

4.PHPからNode.jsへの移植作業とその理由

 以前はバックエンドをPHPで作っていたのだが、それをNode.jsに移植することにした。理由は単純で、現行のほとんどの処理をTypeScript化したかったからだ。TypeScriptならバックエンドとフロントエンドを同じ言語で書くことが出来る。それによってデータ構造の記述が両方で使い回せるのだ。これは非常に大きなアドバンテージである。二度手間を防げる上に、移植に伴うミスも発生しなくなる。これでデータのやりとりがぐっと楽になるのだ。

 ただしPHPからNode.jsへの移行には重大な注意点がある。速度はPHPの方が圧倒的に速いことだ。初期化処理とか色々込みのPHPプログラムが、準備万端で待ち受けしているNode.jsのプログラムと互角以上にやり合うのだ。色々と実験を繰り返しみたが、PHP7系統の速度がおかしいぐらいに速い。

 ということでNode.jsでプログラムを組む場合は、速度的な優位を期待してはいけない。細かい処理でPHPと互角、重い処理ほどPHPの方が優位性を増していく。ただし大量のアクセスをさばく際のメモリ消費量に関してはNode.jsの方が優れているので、貧弱なリソース下で動かすなら考慮に入れるべきだろう。

5.Node.jsの特徴

向いてない作業

 Node.jsの特徴は、細かい処理を大量に捌くことだ。たとえば受付のオペレータのように、用件を聞いたら対象の部署へ内線を回すという作業などが該当する。間違っても重い荷物を持たせてはいけない。Node.jsは荷物を持った瞬間に腰痛を発症し、手痛い損害賠償を請求されることになるだろう。

 重い処理とはなんなのか。画像加工とか機械学習とか動画編集とかはもちろんこれに該当する。そういうWebサービスを作るなら、別の言語で作ったプロセスにいったん投げた方が幸せになれる。

 そしてもっと一般的に行われている中でやってはいけない仕事、それはDOMを組み合わせてHTMLデータを作成する作業だ。ぶっちゃけこれをやらせるなら、PHPとかに処理を任せた方がよい。その方がよっぽど高速だ。

 HTMLデータを生成する作業を主体とするのなら、はっきりいってNode.jsという選択は愚策といってよい。踵を返して他の言語の門を叩いて欲しい。Node.jsで開発しても、面倒なだけでちっとも作業は効率化しない。

向いてる作業

 Node.jsに向いている作業は最初に書いた通り、受付オペレータである。Webシステムならば、クライアントからの要求を聞き、それをDBに投げ、結果が返って来たらクライアントにデータを送り返すのだ。できるだけ内容に関知しないことが理想だ。しかしこれだけは最低限処理しないといけないというのがある。クライアントが誰なのか、問い合わせが正当なものなのかの確認だ。つまり向いている作業とは、WebAPIを構築する部分である。

 ではHTMLは誰が作るのという疑問を抱くかもしれない。初期ページ以外はフロントエンド側で動的に生成すれば良いのだ。バックエンド側は生成に必要なデータを返してやるだけで良い。場合によってはサーバサイドレンダリングが必要なこともあるかもしれない。しかしそれを主体とするシステムに導入するのは考え直した方が良いだろう。

まとめ

  • 軽量の処理ならNode.js
  • Webサービスを作る上で重い処理ほどPHPの方が速くなるし、さらに重い処理はネイティブ言語系に投げた方が良い
  • 大量アクセス時の省メモリの動作はNode.jsが有利
  • 金をかけても問題なく、GB単位でメモリが用意できる環境なら、省メモリがあまりアドバンテージにならない
  • 本気の同時一万アクセスとかは、普通に組んでたら無理なので夢は見ないこと

6.非同期地獄と入門と門前

 Node.jsはシングルスレッドかつ非同期を前提に動作する。非同期は必要なデータが返ってくるまでラグのある処理をタスクプールに積んでいく。ファイルの入出力からDBアクセスまで、その場で欲しいデータをことごとくその場でもらうことが出来ない。データ受け取り後に必要となる処理を切り分けて、ひたすらプールにため込んでいくのだ。これが非同期地獄というやつだ。ただしこの非同期地獄はPromise/async/awaitによって、一応は抜け出すことが出来る。ただし非同期処理にPromiseを返してこないライブラリを扱う場合は、そのまま使うかPromise化するかという面倒な作業が待っている。

 この非同期処理に慣れることや、自分が必要とするライブラリのPromise化が終わったら、ようやく開発の門の前に立った状態となる。そう、門前に立っただけである。つまり、まだ入門すらしていないのだ。

 ちなみにシングルスレッドだと、複数CPUがあっても、そのリソースを活用できないという認識はしなくて大丈夫だ。プロセスを増やせばリソースは使い切れるし、それを簡単に行う仕組みも用意されている。どのみちスクリプト系の言語はマルチスレッド対応言語でも、変数などの排他制御の問題で性能が頭打ちになる。そうなると結局マルチプロセスしか選択肢が残らない。マルチスレッドで性能を追求したければ、ネイティブ系の言語か、Javaを使った方が幸せになれるだろう。

まとめ

  • 非同期処理は、使用するライブラリを全てPromise化してからが始まり
  • とにかく慣れるまでが辛い
  • シングルスレッドでもマルチプロセスにすればCPU資源を生かすことは出来る
  • 非同期処理の同期をとらずに気軽に大量のループで回すと不幸が訪れる
  • ガチで性能を追求するなら別の言語へ

7.TypeScriptと流星

 非同期処理による問題も解決し、いよいよ入門を果たしても、所詮は門を通り抜けたに過ぎない。そこからTypeScriptという地獄が始まる。フロントエンドとバッグエンドを同じ言語で書けるという利点を生かすため、以前に別言語で作った資産を移植する作業をしなければならない。つまり、以前作った資産が多い人間ほど、重い荷物を背負うのだ。

 私の場合、ブラウザ上でウインドウシステムを実現するというフロントエンドフレームワークという資産があった。これを移植しなければならないのだ。荷物があまりに重すぎたので、単純移植を諦め、ほとんどの部分を作り直した。

 フロントエンドで書いていたJavaScriptのTypeScriptへの移植は、同じ系統の言語だからすぐに出来るだろうとか安易に考えてはいけない。コンパイルした瞬間、流星のごときエラーメッセージによって、自分の甘さをとことん教えられるのだ。ここで必要なのは、エラーの数に心を折られない精神力だ。

 こんなに型でカタカタしなくてもいいだろうにと思って、一つ一つ修正していくと、実は馬鹿をやっていた記述をいくつも発見することになる。そう、ここでたまたま動いていたコードを見つけることになるのだ。さらに段階的にstrictを有効にして、チェックを厳しくしていく必要がある。最終的にeslintを導入してanyすら禁止すれば、ようやく入門を完了した状態となる。anyが一個でも残っていたら、入門から脱したとは言えない。

 PHPからTypeScriptの移植は文法が似ているおかげもあって、非同期への対処が終わっていれば、意外にあっさり出来る。JavaScriptで食らったペガ○ス流星拳に比べれば衝撃の度合いは低い。

まとめ

  • JavaScriptから移行するのは、それなりの覚悟が必要
  • TypeScriptの型の仕様を本気で突き詰めると、実はシャレにならないほど複雑
  • TypeScriptの言語仕様はこうしている間にも増え続け、気がつくと背後に知らないキーワードが立っている
  • anyを自分のソースコードから完全に除去しないかぎり、素のJavaScriptの呪縛からは抜け出せない
  • エラー流星拳に対して、身を守るためにクロスを纏うことは出来ないが苦労はするだろう
    というかクロスって肝心な場所を守ってない気がする

8.必要となる知識

 今回の開発で必要となった知識をざっと挙げてみたいと思う。

  • HTML/CSS
  • JavaScriptの文法と特性
  • ブラウザでJavaScriptを動かすためのDOMを操作や、イベント
  • Ajaxや人を殺さない方のJSON
  • TypeScriptの文法と特性
  • Node.jsの基本的な使い方とランタイムライブラリ
  • WebPackなどの開発ツールやプラグイン、必要なpolyfill
  • npmで呼び出す、大海の中に投げ出された中から掴み取るモジュール
  • DBとSQLとそれを操作するモジュール

 なんだかんだでWebPackが鬼門だ。情報はたくさんあるのだが、内容が新旧入り交じり、プラグインも混沌としている。自分が必要としているものがなんなのか、最適解を見つけるまで試行錯誤することになるだろう。この辺りの話もこの後の記事でしていきたい。

9.次回の予定

 次回はバックエンドとフロントエンドで導入した開発手法の話になる予定output_1.gif

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

Qiitaの記事をランダムに読めるAPI / サービス に機能追加してみた

数日前に公開された上記のサービスがとても素晴らしく、
このサービスを通じて普段はなかなか出会うことのない類の記事とたくさん出会うことができました!

きっかけ

しかし個人的に一点問題が。元記事の筆者の方も指摘なさっているとおり、スパム記事の割合がなかなか高い
ざっくりとした体感、10分の1くらいの確率でスパムをツモってしまう印象です。ちょっと残念。

そこで元のサービスに一部機能を追加し、引き当てる記事をある程度スクリーニングできるようにしました。
(元々のバイアスなしに謎の知識(?)を仕入れることができます。という意図から少し逸れてしまいますが…)

モノ

スクリーンショット 2019-07-01 0.45.38.png

赤枠の箇所が追加部分になります。

https://random-qiita-api-c2498.firebaseapp.com/
Webサービス版のリンクは↑こちら。追加した機能は大きくふたつです。

1. 特定数以上のいいねを獲得している記事のみを取得対象にする

そのままですね。獲得いいね数を1以上にするだけでもスパム記事との遭遇率はだいぶ下がります。
いっぽうでいいね数を上げすぎると既知の記事との遭遇率が上がるので、上限値は100としています。

2. 指定したタグを含む記事のみを取得対象にする

全取得対象の10000記事のうち100以上の記事に付されているタグを対象に、タグ指定で取得します。
1. のいいね数での絞り込みと組み合わせて使用することももちろん可能です。

エンドポイント例

いいね数が5以上、タグにPythonを含む記事のみを取得する場合の例です。
ご覧の通り、いずれもクエリストリングに入力値を渡してスクリーニングに使用しています。
リクエストからクエリストリングを抜き出している箇所は以下。

exports.get = functions.https.onRequest((request, response) => {
  cors(request, response, () => {
    const likes_min = request.query.likes_min;
    const tag = request.query.target_tag;

またそれぞれの条件を指定した状態のブックマークレットをワンクリックで作成できるようにしました。
元記事と同じ引用となってしまいますが、ブックマークレットの登録方法を参照のこと。

使ってみて

個人的にはだいぶストレスが減りました。
いいね数を適度に高く設定するとやはり良記事との遭遇率も上がり、良い感じです。
まだ動かしはじめたばかりなので、不具合などありましたらご指摘いただけるとありがたいです。

ところでアーキテクチャなどは元々のものをまるっきり流用しているのですが、
この機能追加だけで数時間かかってしまいました。。。
元記事の方の4時間で実装というのは脱帽です。すごい。

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

vueプロジェクトの`npm run build`がエラーになる

vue cli で作成したプロジェクトのbuildができない

2019/06/30 12時頃、vue createで作成したプロジェクトのnpm run buildコマンドができなくなった。

以下のようなエラーが発生。

$ npm run build

⠙  Building for production...Starting type checking and linting service...
Using 1 worker with 2048MB memory limit
⠸  Building for production...Unhandled rejection Error: original.line and original.column are not numbers -- you probably meant to omit the original mapping entirely and only map the generated position. If so, pass null for the original mapping instead of an object with empty or null values.
    at SourceMapGenerator_validateMapping [as _validateMapping] (/Users/user_name/spring-sec-sample-app/src/main/resources/client-app/node_modules/webpack-sources/node_modules/source-map/lib/source-map-generator.js:276:15)
...

エラーをみる限り、source mapの作成時にコケている?よう。

暫定対応1

そもそもビルド時に、source mapを作成しないようにする。

vueプロジェクトの設定は、vue.config.jsに書き込めば、vueがそのファイルを自動的に検知して読み込んでくれる。

デフォルトでは作成されないので、存在しない場合は自分で作成する。
階層はプロジェクトディレクトリのルートに配置する。

$ vi vue.config.js
./vue.config.js
module.exports = {
    // other config
    productionSourceMap: false
}

これでひとまず、エラーは回避できる。

暫定対応2

node modules の依存関係を自分で定義する。

package.json
{
  "dependencies": {
    "core-js": "^2.6.5",
    "vue": "^2.6.10",
    "vue-class-component": "^7.0.2",
    "vue-property-decorator": "^8.1.0",
    "vue-router": "^3.0.3",
    "terser": "4.0.0"  // 追加
  },
}

上記のように、terserのバージョンを4.0.0に指定する。

原因

vueプロジェクトはsource map作成時、内部的に依存しているterserというライブラリを利用している。
そのterserがv4.0.1を2019/06/30にリリースした模様。

https://www.npmjs.com/package/terser

そのv4.0.1でバグが紛れ込んだそうです。

issueが上がっていました。
https://github.com/terser-js/terser/issues/380

クライアントってモジュールの依存関係が複雑すぎて、こういう小さな変化がエラーを生み出すし、サーバに比べて極めて大変。。
依存する全てのモジュール理解している人とかいるのかな、、難しい。

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

readme-md-generatorを使ってリッチなREADME.mdをお手軽に作ってみませんか?

今回は簡単にREADME.mdを作成できる、readme-md-generatorを紹介させていただきます。

githubはこちらです。良いと思った方は:star2:をつけると良いと思います。

readme-md-generatorとは

CLIで動かせる、美しいREADME.mdを生成するためのライブラリです。

package.jsonとgitの設定をデフォルトとしてREADME.mdを作成するようです。

使ってみました

基本的な使い方

このように対話式にREADME.mdの内容を設定できます

※↓のは全部Enterとしてるので、デフォルト値がそのままREADME.mdに書き込まれます。(または、npx readme-md-generator -yとしてもと全てデフォルト値としてくれます。)

Jx0YgBCnfG.gif

自動でmarkdownファイルが出来上がりました。

Screen Shot 2019-06-30 at 20.00.57.png


良いpackage.jsonの例としてはこのような感じになるようです。

※ちょっと前にこちらの投稿で書いたコードのpackage.jsonを再作成してみました。
https://qiita.com/okumurakengo/items/aecd060ce64c99a646c8

package.json
{
  "name": "react-hooks-todos",
  "version": "1.0.0",
  "description": "ReactのHooksを使ってReduxのTodoリストをReduxなしに書き換えたサンプル(TypeScript使用)",
  "main": "webpack.config.js",
  "scripts": {
    "start": "webpack-dev-server"
  },
  "homepage": "https://github.com/okumurakengo/react-hooks-todos#readme",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/okumurakengo/react-hooks-todos.git"
  },
  "author": "okumurakengo",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/okumurakengo/react-hooks-todos/issues"
  },
  "engines": {
    "npm": ">=5.5.0",
    "node": ">=9.3.0"
  }
}
bash
npx readme-md-generator -y

少し書き換えたりとかしましたが、こんな感じにREADME.md生成してくれました、すごいですね:grinning:
ライブラリの信用度も上がりそうです。

github.com_okumurakengo_react-hooks-todos (1).png

ejsのテンプレートを使用できる

npx readme-md-generator -p path/to/my/own/template.md

.mdファイルにejsで記述し、それをテンプレートとして使うことができます。

テンプレートの例はこちら:https://github.com/kefranabg/readme-md-generator/tree/master/templates


読んでいただいてありがとうございました。m(_ _)m

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