- 投稿日:2020-09-11T23:43:42+09:00
Firefox上apex:actionFuncionを呼出時の注意事項
業務上に実現したいことは以下となります。
一覧にファイルリストがあって、行毎にダウンロードボタンがあります。
そのボタンをボタンを押下したら、あるオブジェクトの更新を行い、更新完了したら、ファイルをダウンロードする
上記の処理は非同期で行うことです。以下の実装だと、chrome上に問題なく処理されます。
①オブジェクトが正しく更新されます。
②サーバ側の処理が処理完了したら、画面の非同期更新エリアがリフレッシュされます。
③ファイルが正しくダウンロードされます。
Firefox上③のみ有効、①②が効かない。ファイルダウンロード1.v<a onclick="fileDownload(id)" /> <apex:actionFunction name="testAction" action="testAction" reRender="testArea"> <apex:param name="testId" assignTo="{!testId}" /> </apex:actionFunction> <script> function fileDownload(id) { // 他の業務処理を行う testAction(id); loaction.href="ファイルパス" + id; } </script>以下のように変更すると、Firefox上に①②も効かないが、ボタンを連続的に押下する場合、①が効きます。
ファイルダウンロード2.v<a onclick="fileDownload(id)" /> <apex:actionFunction name="testAction" action="testAction" reRender="testArea"> <apex:param name="testId" assignTo="{!testId}" /> </apex:actionFunction> <script> function fileDownload(id) { // 他の業務処理を行う Function('return this')()['testAction'](id); loaction.href="ファイルパス" + id; } </script>以下のように変更すると、ChromeもFirefoxも①②③正しく処理されます。
ファイルダウンロード3.v<a onclick="fileDownload(id)" /> <apex:actionFunction name="testAction" action="testAction" oncomplete="doDownload()" reRender="testArea"> <apex:param name="testId" assignTo="{!testId}" /> </apex:actionFunction> <script> var testId = null; function fileDownload(id) { // 他の業務処理を行う Function('return this')()['testAction'](id); testId = id; } function doDownload() { loaction.href="ファイルパス" + testId; } </script>まとめ(原因分析)
1、Salesforce非同期処理(apex:actionFunction)のName属性は通常意味のJSの関数だと理解していますので、
JSから直接呼出して問題がないかと思います。おそらくChrome上もその通りに解析されるから、問題なく処理される。
だがFirefox上にJS関数を経由し、Salesforce非同期処理(apex:actionFunction)を直接呼出すのは効かない。
原因がわからないが、Functionを利用してラッピングしたら、問題なく利用されます。
2、Firefox上に「loaction.href」を利用すると、「redirect」が変わってしまうから、非同期処理完了後の画面リフレッシュが効かなくなるかと思います。なので、ダウロード処理はoncompleteに移動すれば解決します。
※上記の分析は自分の考えだけですが、全部正しいわけではないが、上記のようにやっておけば、問題が解決できます!
もし本当の原因がわかる方はいらっしゃいましたら、是非教えて頂きたいです。
- 投稿日:2020-09-11T22:28:30+09:00
【JavaScript】超基礎的なメソッドの紹介 その1
JavaScriptで行うDOM(Document Object Model、要はHTML等のマークアップ言語にアクセス・編集しやすい標準的に仕組み)の操作において、基礎的なメソッドを学んだため、備忘として記します。
1 HTML要素の取得(すべてはこれから始まる)
getElementByIdメソッド、getElementsByTagNameメソッド<h1 id = "heading1">朝の献立</h1> <h1 id = "heading2">昼の献立</h1> const select = getElementById(`heading1`); //「heading1」のidを持つHTML要素を取得し、定数selectに代入。 console.log(select); //「<h1 id = "heading1">朝の献立</h1>」をコンソールに出力。 const selects = getElementsByTagName(`h1`); //<h1>要素すべてを「配列の様に」取得(getElement"s"ByTagNameである点に注意) console.log(selects[0]); //<h1>要素のうち1つ目をコンソールに出力。※文字列「朝の献立」を出力するわけではない点に注意。 console.log(selects[2]); //<h1>要素の3つ目は、undefined(定義されていない)とエラー。2 テキストデータの取得
textContentメソッド(ついでにfor文を用いた応用)<h1 id = "heading1">朝の献立</h1> <h1 id = "heading2">昼の献立</h1> <h1 id = "heading3">夜の献立</h1> const selects = getElementsByTagName(`h1`); //<h1>要素すべてを「配列の様に」取得(getElement"s"ByTagNameである点に注意) console.log(selects[0].textContent); //「朝の献立」とコンソールに出力。 for (let i = 0; i > selects.length; i++) { console.log(selects[i].textContent); } //「朝の献立」「昼の献立」「夜の献立」とコンソールに出力。※for文の条件式の注意点としては、.lengthでselects要素の数を取得している。とりあえずここまで。
その1と書いたので、続けたいと思います。
- 投稿日:2020-09-11T22:26:39+09:00
Electronをバージョンアップしたらjsのネイティブモジュールが読み込めなくなった話
Electron9にバージョンアップしたところ、
途中でアプリの画面が動かなくなってしまう(windowになにも表示がされない)障害が発生しました。原因
- Electron9から、appallowrendererprocessreuseのパラメーターがデフォルトで true になってた
- これによって2回目に読み込まれた時に、jsのネイティブモジュールが読み込めなくなっていた
appallowrendererprocessreuse とは
(公式サイトより) Boolean値。trueのときは、レンダラープロセスが確実に再起動されるように、Electronが設定しているオーバーライドを無効にする。このプロパティは、レンダラープロセスで使用できるネイティブモジュールに影響する
とのこと。名前からして再利用しようとしてうまくモジュールを読み込めてない、というような状況。対策(暫定対応)
- ページの初期化処理とかをしている部分で
app.allowRendererProcessReuse = false;
- これまでと変わらないように動かせた
今後
issue によると
- Electron 6 で app.allowRendererProcessReuse オプションを追加
- コンテキスト非対応のネイティブモジュールについて、Electron 7で最初の非推奨警告ランドを用意する
- Electron 9 でapp.allowRendererProcessReuseのデフォルト値がtrueに
- Electron 10でapp.allowRendererProcessReuseを変更する機能を廃止予定
- Electron 11でapp.allowRendererProcessReuseを変更する機能を削除
今後Electron11では完全にfalseに変更できなくなるので、別の対応が必要
- 現在調査中
- 投稿日:2020-09-11T22:07:08+09:00
RPGツクールMZでイベントコマンド「スクリプト」からプラグインコマンドを呼び出す方法
副題「あるいは、RPGツクールMZのプラグインコマンド周りをざっと調べてみた」
【目次】
- 前置き
- 結論
- 読み解き
- MVのプラグインコマンド振り返り
- MZでの変更部分とそれへの対応
- MVとMZで、スクリプトからのプラグインコマンド呼び出し方法が異なる理由
前置き
自身はあまり実感したことがないのですが、MVの頃から
「プラグインコマンドをスクリプトから呼び出したい」
という需要がぼちぼちあるようです。
また、MZの売りの一つが
「プラグイン周りの機能強化 > プラグインコマンドの刷新」
なわけですが、その辺を全然さわれてなかったので、学習がてら調査と整理をしてみました。結論
まず結論。
MZでは以下の記述でイベントコマンド「スクリプト」からプラグインコマンドを呼び出せます。const args = {/* ここにプラグインコマンドのパラメータを記述 */}; PluginManager.callCommand(this,(プラグイン名) , (コマンド名), args);argsというオブジェクトにプラグインコマンドのパラメータをプロパティとして記述し、それをPluginManagerのcallCommandメソッドにプラグイン名、コマンド名と共に渡します。
例)
プラグイン名「test.js」のコマンド名「Test」をイベントコマンドスクリプトから呼び出す例です。
「test.js」は与えられた引数をconsole.logに出力するだけのプラグインであり、
パラメータ名は「testKey」としています。
きちんと呼び出しできてますね。方法だけ知りたい、という人はここまでです。
上のスクリプトをコピペしてこのページはそっ閉じしましょう。読み解き
上記が何をしているのか、そしてMVからどう変わったのかを自身の備忘録も兼ねて以下に記します。
なお、ざっくりとしたイメージを掴むことを最優先とし、「Game_Interpreter」や
「PluginManager」の細かい挙動や仕組みは省略している点をご了承ください。MVのプラグインコマンド振り返り
まずはMVの振り返りです。
MVにおいてイベントコマンド「スクリプト」からのプラグインコマンド呼び出しは、
いくつか方法はありますが、以下のコードがシンプルです。var args = [/* ここにプラグインコマンドのパラメータを記述 */]; this.pluginCommand(command, args);※argsは配列
イベントコマンド全般(「スクリプト」「プラグインコマンド」含む)は「Game_Interpreter」というクラスによって呼び出しが行われます。
たとえば「文章の表示」ならば「Game_Interpreter.prototype.command101」
「選択肢の表示」ならば「Game_Interpreter.prototype.command102」というように、
「command + コマンド番号」の形でメソッド名が与えられています。
(※参考:トリアコンタンさま RPGツクールMV プラグインコマンド集 リファレンス)そして今回のお題であるプラグインコマンドについては「356番」が与えられています。
以下がMVコアスクリプトの「command356」のコードです。rpg_objects.js// Plugin Command Game_Interpreter.prototype.command356 = function() { var args = this._params[0].split(" "); var command = args.shift(); this.pluginCommand(command, args); return true; };詳細は端折りますが、command356が呼び出されると、コマンド名とコマンドパラメータを取得し、
それを「this.pluginCommand」に引数として渡して処理を投げます。
この「this.pluginCommand」が核心部分です。では、次に処理を投げられた「pluginCommand」について見てみましょう。
rpg_objects.jsGame_Interpreter.prototype.pluginCommand = function(command, args) { // to be overridden by plugins };おおっとぉ、中身が空だ!!
コメントを直訳すると「プラグインでオーバーライドされます」ですね。
そう、MVにおいてはコマンドのチェックと実行開始はプラグイン側に委ねられていたのです。一般的には以下のような要領で、各自でプラグインコマンドのコマンド名と引数を取得し、
switchで自身のコマンド名に該当するかを分岐し、実行を行っていました。プラグイン側の記述const _game_interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand; Game_Interpreter.prototype.pluginCommand = function(command, args) { _game_interpreter_pluginCommand.call(this, command, args); switch (command) { case 'CommandName1': /* CommandName1の処理 */ break; case 'CommandName2': /* CommandName2の処理 */ break; /* 以下、プラグインコマンドの分だけ分岐 */ }; };簡単に流れを追うと、まずは他のプラグインと処理が競合しないようにエイリアスとしてそれまでの「pluginCommand」の定義を保存し、
改めて「pluginCommand」をオーバーライドしています。
その中で先ほどエイリアスを付けて保存しておいた関数を呼び出して他のプラグイン側の処理を実行、
続けてswitchにより自身のプラグインのコマンドをチェックし、該当するならばそれぞれの処理を行う、という流れです。
繰り返しとなりますが、MVではプラグインコマンドのチェックと実行開始はプラグイン側に委ねられていたのです。【MVのプラグインコマンドのフローを整理】
プラグインコマンドが実行されると
>「Game_Interpreter.command356」が呼ばれる
>「Game_Interpreter.command356」から「Game_Interpreter.pluginCommand」が呼ばれる
>ただし「Game_Interpreter.pluginCommand」は各自プラグイン側で記述MZでの変更部分とそれへの対応
MZでは、公式サイトでもアピールされているように、プラグインコマンド周りが刷新されました。
エディター上での入力のし易さ、プラグイン実行側でのデータの取り扱い易さ、いずれも大きく向上しています。MZでは、「PluginManager」という静的クラスの「registerCommand」メソッドがプラグインコマンドとその実行内容を事前に受け取り、「PluginManager」内に保持してくれるようになっています。
rmmz_objects.jsPluginManager.registerCommand = function(pluginName, commandName, func) { const key = pluginName + ":" + commandName; this._commands[key] = func; };「PluginManager.registerCommand」は第一引数にプラグイン名、第二引数にコマンド名、そして第三引数に「コマンド実行時に実行したい関数」を受け取ります。
するとPluginManagerの「_commands」プロパティに「プラグイン名とコマンド名を連結した物」をkeyとして、第三引数の関数が保存されます。このメソッドをプラグイン側で呼び出してコマンド名や実行関数を登録しておけば、後はプラグインコマンドが実行された時点で保存されていた関数が呼び出されます。
(※「PluginManager.registerCommand」の記述例は公式の「プラグイン講座 > プラグインを作ってみる」内の「プラグインコマンドの定義」に詳しく解説されていますので、そちらも合わせて読んでおきましょう。)次にプラグインコマンドが実行された際の流れを見ていきます。
プラグインコマンド実行の基本的な仕組みはMZもMVと同様で、Game_Interpreterクラスの「command + コマンド番号」メソッドで実行されます。
(※参考:トリアコンタンさま RPGツクールMZ スクリプトリファレンス)ただし、MZではプラグインコマンド実行時は「Game_Interpreter.command357」が呼び出されます。
ここポイント。「356」でなく「357」です。rmmz_objects.jsGame_Interpreter.prototype.command357 = function(params) { PluginManager.callCommand(this, params[0], params[1], params[3]); return true; };これはほぼ、「PluginManager.callCommand」を呼び出すだけのメソッドです。
この「PluginManager.callCommand」が核心部分であり、冒頭の結論です。
MVでいう「Game_Interpreter.pluginCommand」に相当すると言って差し支えないでしょう。rmmz_managers.jsPluginManager.callCommand = function(self, pluginName, commandName, args) { const key = pluginName + ":" + commandName; const func = this._commands[key]; if (typeof func === "function") { func.bind(self)(args); } };先ほどの「PluginManager.registerCommand」と対になる処理ですね。
「PluginManager.registerCommand」で受け取っていた関数を、今度は呼び出しています。つまり、MVだとプラグイン側で記述していたコマンドのチェックや実行開始の処理は、MZだとコアスクリプトで初めから用意されており、プラグイン側の記述は不要です。素晴らしい。
(※注:アノテーション除く)【MZのプラグインコマンドのフローを整理】
プラグインコマンドが実行されると
>「Game_Interpreter.command357」が呼ばれる
>「Game_Interpreter.command357」から「PluginManager.callCommand」が呼ばれるMVとMZで、スクリプトからのプラグインコマンド呼び出し方法が異なる理由
なお、MVでプラグインコマンドを受け取っていた「command356」は、MVとの互換性維持のためかMZにもそのまま残してあります。
rmmz_objects.js// Plugin Command MV (deprecated) Game_Interpreter.prototype.command356 = function(params) { const args = params[0].split(" "); const command = args.shift(); this.pluginCommand(command, args); return true; }; Game_Interpreter.prototype.pluginCommand = function() { // deprecated };ただし、コメントにもあるように「deprecated(非推奨)」となっていますし、実際にMZでイベントコマンド「スクリプト」から「pluginCommand」を呼び出しても何も起こりません。
何故か?
それは、何度も繰り返してきましたがプラグインコマンドのチェックと実行を担う「pluginCommand」は空だからです。
MZにおいて、イベントコマンド「スクリプト」から「this.pluginCommand」を呼び出したとしても、プラグイン側がpluginCommandメソッドの中身を記述していなければ、空の関数が呼び出されただけで何も実行されずに終わります
言い換えると、プラグインコマンドを使用するプラグインをMVとMZの両対応とするには
MZ向けの「PluginManager.registerCommand」による記述と、
MV向けの「Game_Interpreter.pluginCommand」による記述の
両方に備えておく必要がある、
ということです。プラグインコマンドを使用するプラグインをMV、MZ両対応にするのは若干メンドーですね。
(その辺を共用化するプラグインを作れば需要があるかな?)
以上、イベントコマンド「スクリプト」からプラグインコマンドを呼び出す、という観点を取っ掛かりとして、
MZのプラグインコマンド処理を追ってみました。忌憚ないツッコミ待ちだぁ! щ(゚Д゚щ) バッチコーイ
- 投稿日:2020-09-11T20:44:12+09:00
[MockDate]テストの時に日付を固定化する方法[JavaScript]
背景
Jestでテストを書いている時に日付の固定化をしたかったのですが、
今まで以下のような感じで、Date.new
をmock化していましたが、書くのがめんどくさいなって思ってました。
https://qiita.com/bearII/items/d8a3bc0e83b14b36e64e結論
以下のパッケージが良さげでした。
https://www.npmjs.com/package/mockdate以下のように1行でモック化できてテストファイルがスッキリします。
before内でモック化し、after内でモックを解除するだけです。
momentもモックできているのが確認できます。import MockDate from 'mockdate' import moment from 'moment' describe('mock date', () => { beforeEach(() => { MockDate.set('2000-11-22') }) afterEach(() => { MockDate.reset() }) it('new Dateがmock化されていることを確認', () => { expect(new Date().getFullYear()).toBe(2000) expect(new Date().getMonth()).toBe(10) expect(new Date().getDate()).toBe(22) }) it('momentがmock化されていることを確認', () => { expect(moment().format('YYYY-MM-DD')).toBe('2000-11-22') }) })
- 投稿日:2020-09-11T20:25:49+09:00
javascript関数ドリル 初級編takeRight関数の実相のアウトプット
takeRight関数の課題内容
↓
https://js-drills.com/blog/takeright/take関数の取り組む前の状態
takeの逆なので簡単だと思っていた
take関数に取り組んだ後の状態
- (1 + i)ここの部分の理解が少し追いつかなかったです。
tail関数の実装コード(答えを見る前)
実行できなかった
tail関数の実装コード(答えを見た後)
function takeRight(array, n = 1) { if(n === 0) { return []; } if(n > array.length) { return [...array]; } const takenArray = []; for(let i = 0; i < n; i++) { // array [1, 2, 3] // 1 + i => 1, 2, 3 // array.length => // 3 - (1 + 0) = 2, // 3 - (1 + 1) = 1 // 3 - (1 + 2) = 0 const indexFromRight = array.length - (1 + i) takenArray.unshift( array[indexFromRight] ); } return takenArray; } console.log( takeRight([1, 2, 3]) ); // => [3] console.log( takeRight([1, 2, 3], 2) ); // => [2, 3] console.log( takeRight([1, 2, 3], 5) ); // => [1, 2, 3] console.log( takeRight([1, 2, 3], 0) ) ; // => []
- 投稿日:2020-09-11T20:15:31+09:00
javascript関数ドリル 初級編take関数の実相のアウトプット
take関数の課題内容
↓
take関数の取り組む前の状態
大体作る前からどうすればいいかわかっていた
take関数に取り組んだ後の状態
自力でできた
tail関数の実装コード(答えを見る前)
function take(array, n = 1) { if(n === 0) { return []; } if(n > array.length) { return [...array]; } const takenValues = []; for(let i = 0; i < n; i++) { takenValues.push( array[i] ); } return takenValues; }tail関数の実装コード(答えを見た後)
function take(array, n = 1) { if(n === 0) { return []; } if(n > array.length) { return [...array]; } const takenValues = []; for(let i = 0; i < n; i++) { takenValues.push( array[i] ); } return takenValues; } console.log( take([1, 2, 3]) ); // => [1] console.log( take([1, 2, 3], 2) ); // => [1, 2] console.log( take([1, 2, 3], 5) ); // => [1, 2, 3] console.log( take([1, 2, 3], 0) ); // => []
- 投稿日:2020-09-11T20:09:22+09:00
javascript関数ドリル 初級編tail関数の実相のアウトプット
tail関数の課題内容
↓
https://js-drills.com/blog/tail/tail関数の取り組む前の状態
大体どういう風に組み立てればいいのかわかっていた
tail関数に取り組んだ後の状態
自力でできた
tail関数の実装コード(答えを見る前)
function tail(array) { const tailArray = []; for(let i = 1; i < array.length; i++) { tailArray.push( array[i] ); } return tailArray; }tail関数の実装コード(答えを見た後)
function tail(array) { const tailArray = []; for(let i = 1; i < array.length; i++) { tailArray.push( array[i] ); } return tailArray; } console.log( tail([1, 2, 3]) ); // => [2, 3]
- 投稿日:2020-09-11T20:04:35+09:00
javascript関数ドリル 初級編slice関数の実相のアウトプット
slice関数の課題内容
↓
https://js-drills.com/blog/slice/slice関数の取り組む前の状態
大体どういう風に組み立てればいいのかわかっていた
slice関数に取り組んだ後の状態
自力でできた
slice関数の実装コード(答えを見る前)
function slice(array, start = 0, end = array.length) { const slicedArray = []; for(let i = start; i < end; i++) { slicedArray.push( array[i] ); } return slicedArray; }slice関数の実装コード(答えを見た後)
function slice(array, start = 0, end = array.length) { const slicedArray = []; for(let i = start; i < end; i++) { slicedArray.push( array[i] ); } return slicedArray; } const numbers = [10, 20, 30, 40, 50]; const slicedNumbers = slice(numbers, 1, 4); console.log( slicedNumbers ); // => [20, 30, 40] console.log( numbers ); // => [10, 20, 30, 40, 50]
- 投稿日:2020-09-11T19:51:19+09:00
LambdaでDynamoDBに複数レコードの書き込みをする(Python、JavaScript)
はじめに
DynamoDBに複数レコードを書き込み(更新)する必要があったので、実装してみた結果と注意的なものを書き留めたいと思い記事を投稿した
またPythonとNode.jsの両方での実装を載せようと思います前提
テーブル
今回書き込みをするテーブルは以下を想定
テーブル名:Users
カラムと型(スキーマ自体に型はありませんが、登録するデータの型として便宜上決めておきます)は以下の通り
- id(primary key):Number
- name:String
- address:String
- friends: List[Map]
friendはid, name, addressのキーを持つMapの一覧を想定
今回は複雑めな型(Userテーブルのfriendのような型)であっても、書き込みができることも示しておきたいことの一つなので、そもそもテーブルの設計がベストであるかは一旦無視でいきますLambdaの準備
今回はLambda上で動くコードを掲載するので、Lambdaは各自で準備ができていることを前提とします
記事の流れ
全体のコード例 → 軽い解説
の手順で書いていき、最後に共通する補足事項を載せるPythonでの実装
import boto3 from boto3.dynamodb.conditions import Key def update_users(table, users_friends): with table.batch_writer() as batch: for n in range(3): batch.put_item( Item={ "id": n + 1, "name": "user" + str(n + 1), "address": "address" + str(n + 1), "friends": users_friends[n] } ) def lambda_handler(event, context): try: dynamoDB = boto3.resource("dynamodb") table = dynamoDB.Table("Users") user1_friends = [ { "id": 2, "name": "user2", "address": "address2" }, { "id": 3, "name": "user3", "address": "address3" } ] user2_friends = [ { "id": 1, "name": "user1", "address": "address1" }, { "id": 3, "name": "user3", "address": "address3" } ] user3_friends = [ { "id": 1, "name": "user1", "address": "address1" }, { "id": 2, "name": "user2", "address": "address2" } ] users_friends = [user1_friends, user2_friends, user3_friends] update_users(table, users_friends) return event["message"] # 返すものは適当 except Exception as e: print(e)軽く解説
コードの書き方云々や書き込むデータ自体については本質ではないので、スルーしてもらって大丈夫です
大事なのはupdate_users
関数の中身で、DynamoDBのモデルのインスタンスに生えているbatch_write
メソッドを使っているということ
すなわち、複数書き込みをしたいときは以下のブロック内でPUT
をするwith table.batch_write() as batch: # ...略また、
PUT
する際には例でいうとbatch.put_item
を呼び出してやる
こいつのItem
という名前の引数に書き込みの内容を記述していく
そしてもう一点注目したいのが、List[Map]という型であっても問題なく書き込むことができるという点
基本的にどんな型でも指定したキーの値としてちゃんとDBに書き込めるので、要するにItem
には更新したい辞書をそのまま渡してあげれば問題ない
最後にちょっとした補足として、batch_write
のブロック内でfor
文を回しているが、当然batch.put_item
をベタで複数回書いていってもよいので、もしfor
文では書けないときはベタでやればいい
また、一度にできる書き込める上限は25件までと言われているが、どうやら25件以上の場合は再送してくれたりよしなにやってくれているらしいので、件数を気にせずコードを書いていけるっぽいNode.jsでの実装
const AWS = require("aws-sdk"); const dynamoDB = new AWS.DynamoDB.DocumentClient({ region: "ap-northeast-1" }); const tableName = "Users"; exports.handler = (event, context) => { const user1Friends = [ { id: 2, name: "user2", address: "address2" }, { id: 3, name: "user3", address: "address3" } ]; const user2Friends = [ { id: 1, name: "user1", address: "address1" }, { id: 3, name: "user3", address: "address3" } ]; const user3Friends = [ { id: 1, name: "user1", address: "address1" }, { id: 2, name: "user2", address: "address2" } ]; const usersFriends = [user1Friends, user2Friends, user3Friends] const params = { RequestItems: { [tableName]: usersFriends.map((e, i) => ({ PutRequest: { Item: { id: i + 1, name: `user${i + 1}`, address: `address${i + 1}`, friends: e } } })) } }; // callbackは適当 dynamoDB.batchWrite(params, (e, data) => { if (e) { context.fail(e); } else { context.succeed(data); } }); };軽い解説
Pythonでの解説で述べたようにコードやデータの値そのものに関してはスルー
ここで大事なのはAWS.DynamoDB.DocumentClient
にあるbatchWrite
というプロパティ(関数)
こいつの引数は結構癖があるのでClass: AWS.DynamoDB.DocumentClient — AWS SDK for JavaScriptを参照してください
Node.jsでの複数書き込みについて調べたときによく出てくるのはbatchWriteItem
だったのですが、現在(2020年9月時点)のLambdaで用意されている最新のNode.jsの実行環境だとどうやらないっぽいので、動かず意外と手こずる
batchWriteItem
との大きな違いはItem
のオブジェクトがDynamoDB特有の型付きのオブジェクト(name: { "S": "user" }
みたいなやつ)である必要がなくなっている点
要するに書き込みたい値を気にせずそのままJSONにしてItem
の値として渡せば問題なく動く
そのため、当然Map[List]という複雑な型であってもそのまま渡せば書き込み可能です全体の補足
バッチ処理で更新(update)をしたいときは
PUT
を使うしかない
理由は単純でUPDATE
がないからで、仕方ないので地道にPUT
で記述していく必要がある
またバッチ処理内ではDELETE
をすることができるので、今回はフォーカスしませんでしたが、一応あるということだけ言っておきます・・・おわりに
いかがでしたでしょうか
複数操作についてはコードと1, 2行程度の解説がある記事はちょこちょこ見かけますが、書き込みに特化して解説されているのはあまり見かけず(あっても複雑な型でもできるのか不明であったり、そもそも実行時エラーになってしまう)、多少やってて手こずったので、備忘の意味も兼ねて書き残してみました
若干ニッチな分野かもしれないですが、少しでも役に立てて貰えれば幸いです参考
Amazon DynamoDB — Boto3 Docs 1.14.56 documentation
Class: AWS.DynamoDB.DocumentClient — AWS SDK for JavaScript
- 投稿日:2020-09-11T19:50:25+09:00
javascript関数ドリル 初級編nth関数の実相のアウトプット
nth関数の課題内容
↓
https://js-drills.com/blog/nth/nth関数の取り組む前の状態
参考演算子が使えるんじゃないかと考えていた
nth関数に取り組んだ後の状態
どちらのやり方でもできるように理解できた
nth関数の実装コード(答えを見る前)
function nth(array, n = 0) { return n >= 0 ? array[n] : array[array.length + n]; } const array = ['a', 'b', 'c', 'd'];nth関数の実装コード(答えを見た後)
function nth(array, n = 0) { return n >= 0 ? array[n] : array[array.length + n]; } const array = ['a', 'b', 'c', 'd']; console.log( nth(array, 1) ); // => 'b' console.log( nth(array, -2) ); // => 'c';
- 投稿日:2020-09-11T19:39:49+09:00
javascript関数ドリル 初級編lastOf関数の実相のアウトプット
lastOf関数の課題内容
↓
https://js-drills.com/blog/lastindexof/lastOf関数の取り組む前の状態
for分をどうすればいいのか悩んだ
lastOf関数に取り組んだ後の状態
let i = fromIndex; 0 <= i; i--
このように±を逆にできることを知れた。lastOf関数の実装コード(答えを見る前)
実行できませんでした
last関数の実装コード(答えを見た後)
function lastIndexOf(array, value, fromIndex = array.length - 1) { for(let i = fromIndex; 0 <= i; i--) { if(array[i] === value) { return i; } } return -1; } console.log( lastIndexOf([1, 2, 1, 2], 2) ); // => 3 // Search from the `fromIndex`. console.log( lastIndexOf([1, 2, 1, 2], 2, 2) ); // => 1
- 投稿日:2020-09-11T19:28:11+09:00
Vue.jsでHeadタグ内のタイトルとメタタグを設定する
課題
SPAでもページごとにタイトルやメタタグを設定したい。
SPAだし、メタタグはいらないけど、ページタイトルは変更したいかなぁって感じ。Nuxt.jsは、title設定があるけど、同じような感じでVueでも設定したい。
TL;DR
vue-head
Headプロパティでタイトルを含めて、Headに設定できることを操作できる感じ。
934スターあるし、プロジェクトにスポンサーもついているし鉄板ぽいhttps://github.com/ktquez/vue-head
vue-page-title
タイトル変更に特化した感じ。
Nuxt.jsのように、titleプロパティを設定して使えたり、Vue-routerのメタタグにTitleを設定することで反映される。
107スターなので、少しマニアックっぽい。https://github.com/vinicius73/vue-page-title
追記
githubで検索していたら、
vue-headful
というのもあった。https://github.com/troxler/vue-headful
vue-head
と機能は同じだけど、記述の仕方がコンポーネントとして記述するので、少し違和感が。。。。ただし、219スターなので、それなりに人気があるのかな?
参考文献
- vue.jsでheadの要素を設定する時はvue-headが便利!
- Vue-headの紹介記事
- 【Vue.js】titleタグやmetaタグ(description)を書き換える方法【vue-rouetr】
- 手法をまとめてくださっている。
- vue.js router を 使い 動的に title や meta タグを変更
- vue-page-titleで実装されている方法と似ている。アイデア元が一緒かも?
- Vue + vue-router で動的にページタイトルを変更する方法
- vue-page-titleで実装されている方法と似ている。アイデア元が一緒かも?
- Updating Page Title & Metadata with Vue.js & vue-router
- Vue-routerのナビゲーションのフックを使って操作する方法
- 投稿日:2020-09-11T19:20:12+09:00
javascript関数ドリル 初級編last関数の実相のアウトプット
last関数の課題内容
↓
https://js-drills.com/blog/last/last関数の取り組む前の状態
なんとなく行けそうだった
last関数に取り組んだ後の状態
index番号を忘れていて-1をつけ忘れていた
last関数の実装コード(答えを見る前)
function last(array) { return array[array.length - 1]; } console.log( last([1, 2, 3]) );last関数の実装コード(答えを見た後)
function last(array) { return array[array.length - 1]; } console.log( last([1, 2, 3]) ); // => 3
- 投稿日:2020-09-11T18:53:12+09:00
JavascriptでEnumをシンプルに作成
仕様
- 以下のようなオブジェクトリテラルを定義してEnumを作成する。
- このオブジェクトリテラルにIDをラベルに変換するメソッドを設定するcreate関数を作成。
def.jsconst def = { OPTION_A: [1, "オプションA"], OPTION_B: [2, "オプションB"] };利用方法
- create関数(後段で定義)により仕様を満たすオブジェクトリテラルを作成。
- 利用は以下のようになる。
use.js//create関数により仕様を満たすオブジェクトリテラルを作成 const enum = create(def); console.dir(enum.label(1)); //「オプションA」と表示。 console.dir(enum.OPTION_A) //「1」と表示オブジェクトリテラルにIDをラベルに変換するメソッドを設定するcreate関数
- 定義は以下の通り。
creator.jsconst create = (resource) => { //オプションキー、ID、ラベルを格納したオブジェクトリテラルを作成 const optionSet = {}; const labels = {}; for (const [option, idLabel] of Object.entries(resource)) { const id = idLabel[0]; const label = idLabel[1]; optionSet[option] = id; labels[id] = label; } //IDからラベルを取得する関数を作成 const getLabel = (labels, id) => { return labels[id]; }; //オブジェクトリテラルに、IDをラベルに変換する関数を設定 //bindで冒頭で作ったラベルオブジェクトを設定 optionSet.label = getLabel.bind(null, labels); return optionSet; }bindを使って、オブジェクトリテラルに値を保持したメソッドを設定
- bindを使うことで、「this」を使うようなオブジェクトリテラルを作ることができる。
- 投稿日:2020-09-11T18:35:58+09:00
様々な日本語文章を、目線移動を無くし早く読めるオープンソースツール(Riot Shield)を公開しました
TL;DR
https://ampcpmgp.github.io/riot-shield/
概要
tdual さんのツイートを見て、目線移動無く文を読むと早く読めるということを知り、開発に至りました。
日々読んでいる記事や論文など、今より早く読めると QoL が上がるため、ワクワク感を持って取り組みました。利用モジュール
形態素解析
形態素解析には kuromoji.js を使いました。多くの文章でより良い結果が得られて使いやすかったです。(結構前に作られたツールなのに凄い・・)
区切りの良いところで表示するために if 文を多用して力業で解決しています。感じ良く表示されるという曖昧な答えの中で、コーディングするのはだいぶ苦労しました。ビューライブラリ
ビューライブラリには Svelte を採用しました。非常にサクサク開発出来て、書いていてとても楽しかったです。コーディングにおいて楽しさは正義。本当に素晴らしいライブラリだと思います。
UIデザイン
UIデザインにはニューモーフィズムを採用しました。 Nuemorphism UI をベースに利用し、不足分は Neumorphism.io で補いました。最初に出会ったときにコレだ!っと思っていて、何かで形にしたいと考えていました。出来上がってからも見栄えには非常に満足です。
ただ、 Nuemorphism UI 自体の css が 500kb 近くあってそれなりに重いこと、モーダルを実装するためだけに bootstrap, jquery, popper.js の依存が必要になったことで、もう少し軽量なライブラリがあったら良かったなと思いました。余裕が出来たら実装してみたいです。その他ツール
他には自作モック作成ツールの am-mocktimes を利用したり、ユニットテストには ava を利用したりしています。利用モジュールの一覧は package.json よりご覧ください。自分はどれも便利だと感じています。
使ってみて
文章によっては一部表示が長くなったり、逆に短すぎたりすることもありますが、10記事ほど試し読みした感じでは、恩恵を十分に受けれているように感じました。これからも色々記事を読んでみて、気になったところは微調整していこうと思います。
何か要望などありましたら issue から連絡貰えると出来る限り対応しようと思います。
ブラウザ上で同じことがツールがあったらコメントで教えていただけると幸いです。(自分のググり力では見つけることが出来ませんでした)
ソースコード
- 投稿日:2020-09-11T18:35:58+09:00
様々な日本語文章を、目線移動無く早く読めるオープンソースツール(Riot Shield)を公開しました
TL;DR
https://ampcpmgp.github.io/riot-shield/
概要
tdual さんのツイートを見て、目線移動無く文を読むと早く読めるということを知り、開発に至りました。
日々読んでいる記事や論文など、今より早く読めると QoL が上がるため、ワクワク感を持って取り組みました。利用モジュール
形態素解析
形態素解析には kuromoji.js を使いました。多くの文章でより良い結果が得られて使いやすかったです。(結構前に作られたツールなのに凄い・・)
区切りの良いところで表示するために if 文を多用して力業で解決しています。感じ良く表示されるという曖昧な答えの中で、コーディングするのはだいぶ苦労しました。ビューライブラリ
ビューライブラリには Svelte を採用しました。非常にサクサク開発出来て、書いていてとても楽しかったです。コーディングにおいて楽しさは正義。本当に素晴らしいライブラリだと思います。
UIデザイン
UIデザインにはニューモーフィズムを採用しました。 Nuemorphism UI をベースに利用し、不足分は Neumorphism.io で補いました。最初に出会ったときにコレだ!っと思っていて、何かで形にしたいと考えていました。出来上がってからも見栄えには非常に満足です。
ただ、 Nuemorphism UI 自体の css が 500kb 近くあってそれなりに重いこと、モーダルを実装するためだけに bootstrap, jquery, popper.js の依存が必要になったことで、もう少し軽量なライブラリがあったら良かったなと思いました。余裕が出来たら実装してみたいです。その他ツール
他には自作モック作成ツールの am-mocktimes を利用したり、ユニットテストには ava を利用したりしています。利用モジュールの一覧は package.json よりご覧ください。自分はどれも便利だと感じています。
使ってみて
文章によっては一部表示が長くなったり、逆に短すぎたりすることもありますが、10記事ほど試し読みした感じでは、恩恵を十分に受けれているように感じました。これからも色々記事を読んでみて、気になったところは微調整していこうと思います。
何か要望などありましたら issue から連絡貰えると出来る限り対応しようと思います。
ブラウザ上で同じことがツールがあったらコメントで教えていただけると幸いです。(自分のググり力では見つけることが出来ませんでした)
ソースコード
- 投稿日:2020-09-11T18:33:17+09:00
OuDia形式ファイルのパース
OuDia形式とは
鉄道やバスの時刻表を記述するファイルフォーマット。主にOuDia系のソフトウェアで使用されている。
構文
OuDia形式のファイルは文字列で記述されているので、テキストエディタ等で開くことができる。
OuDia形式のファイルは以下の特徴を持つ。
- ドット
.
から次のドット.
までを1階層とした、階層構造になっている。- ドット
.
による階層構造のほかに、key=value
形式でプロパティが定義できる。- プロパティ(
=
の左側)は複数回登場することがある。
構文の一例
oudiaの構文例FileType=OuDia.1.02 Rosen. Rosenmei=〇〇線 Eki. Ekimei=A Ekijikokukeisiki=Jikokukeisiki_NoboriChaku Ekikibo=Ekikibo_Ippan . Eki. Ekimei=B Ekijikokukeisiki=Jikokukeisiki_Hatsu Ekikibo=Ekikibo_Ippan . Ressyasyubetsu. Syubetsumei=普通 JikokuhyouMojiColor=00000000 . Dia. DiaName=diaName Kudari. Ressya. Houkou=Kudari Syubetsu=0 EkiJikoku=1,1;001,1;010/ . . Nobori. Ressya. Houkou=Nobori Syubetsu=0 EkiJikoku=1;001/,2,1;300/300 . . . . DispProp. JikokuhyouFont=PointTextHeight=9;Facename=MS ゴシック JikokuhyouFont=PointTextHeight=9;Facename=MS ゴシック;Bold=1 JikokuhyouFont=PointTextHeight=9;Facename=MS ゴシック;Itaric=1 JikokuhyouFont=PointTextHeight=9;Facename=MS ゴシック;Bold=1;Itaric=1 . FileTypeAppComment=OuDia Ver. 1.02.05これだけだと分かりにくいので、インデントを付けて見やすくしてみる。
oudiaの構文例FileType=OuDia.1.02 Rosen. ├ Rosenmei=〇〇線 ├ Eki. │ ├ Ekimei=A │ ├ Ekijikokukeisiki=Jikokukeisiki_NoboriChaku │ ├ Ekikibo=Ekikibo_Ippan ├ . ├ Eki. │ ├ Ekimei=B │ ├ Ekijikokukeisiki=Jikokukeisiki_Hatsu │ ├ Ekikibo=Ekikibo_Ippan ├ . ├ Ressyasyubetsu. │ ├ Syubetsumei=普通 │ ├ JikokuhyouMojiColor=00000000 ├ . ├ Dia. │ ├ DiaName=diaName │ ├ Kudari. │ │ ├ Ressya. │ │ │ ├ Houkou=Kudari │ │ │ ├ Syubetsu=0 │ │ │ ├ EkiJikoku=1,1;001,1;010/ │ │ ├ . │ ├ . │ ├ Nobori. │ │ ├ Ressya. │ │ │ ├ Houkou=Nobori │ │ │ ├ Syubetsu=0 │ │ │ ├ EkiJikoku=1;001/,2,1;300/300 │ │ ├ . │ ├ . ├ . . DispProp. ├ JikokuhyouFont=PointTextHeight=9;Facename=MS ゴシック ├ JikokuhyouFont=PointTextHeight=9;Facename=MS ゴシック;Bold=1 ├ JikokuhyouFont=PointTextHeight=9;Facename=MS ゴシック;Itaric=1 ├ JikokuhyouFont=PointTextHeight=9;Facename=MS ゴシック;Bold=1;Itaric=1 . FileTypeAppComment=OuDia Ver. 1.02.05OuDia形式のパース/文字列化
OuDia形式のデータはただのテキストなので、そのままだとプログラムで扱いにくい。
JSON.parse/stringifyよろしく、OuDia.parse/stringifyを自作して、ObjectとArrayの組み合わせに変換してみる。方針
- 基本はObject入れ子
- 同じプロパティ名が複数回登場する可能性があるので、値は配列で保持する。
key=value
形式のプロパティはkeyの先頭に$$
を追加して、.
の階層名と区別する実装
const OuDia = { parse (text) { let current = {} for (const lineRaw of text.split(/\r\n|\n/)) { const line = lineRaw.trim() if (line==='') { continue } else if (line==='.') { const parent = current.parent delete current.parent current = parent } else if (line.endsWith('.')) { const type = line.slice(0, -1) const newCurrent = {parent: current} if (!current[type]) {current[type] = []} current[type].push(newCurrent) current = newCurrent } else if (line.includes('=')) { let [key, ...value] = line.split('=') key = `$$${key}` value = value.join('=') if (value.includes('=')) { value = Object.fromEntries(value.split(';').map(v=>v.split('=').map(v=>v.trim()))) } if (!current[key]) {current[key] = []} current[key].push(value) } } return current }, stringify (obj, isReturnText=true) { const isObject = obj => Object.getPrototypeOf(JSON.parse(JSON.stringify(obj)))===Object.prototype let result = [] for (const [key, values] of Object.entries(obj)) { for (let value of values) { if (value==null) {continue} if (key.startsWith('$$')) { if (isObject(value)) { value = Object.entries(value).map(v=>v.join('=')).join(';') } result.push(`${key.slice(2)}=${value}`) } else { result.push(`${key}.`, ...this.stringify(value, false), '.') } } } if (isReturnText) { return result.join('\n') } else { return result } } }コメント書いてません、すいません。
使用例
const oudData = OuDia.parse(oudText) //=> {$$FileType: ["OuDiaSecond.1.09"], $$FileTypeAppComment: ["OuDiaSecondV2 Ver. 2.04.04"], DispProp: [{…}], Rosen: [{…}]} const oudText = OuDia.stringify(oudData) //=> FileType=OuDiaSecond.1.09\nRosen.\nRosenmei=... console.log(oudData.Rosen[0].$$Rosenmei[0]) //=> 〇〇線上で書いたように値が配列で保持されているので、\$\$Rosenmei[0]みたいに毎回[0]で取りに行かなきゃいけない。\$\$\$始まりだったら\$\$の0番目を取得、みたいなルールをProxyで作ってもいいけど、そこまでするほどでもないかな…
stringifyのところで、ObjectなのかStringなのか判定する必要があったのだけど、ググっても微妙なのしか見つからなかったので、
isObject
関数を自作した。const isObject = obj => Object.getPrototypeOf(JSON.parse(JSON.stringify(obj)))===Object.prototype自作クラスとかが渡された時の挙動が不安だったので、一旦JSONを経由することで簡易的に型チェックしている。
- 投稿日:2020-09-11T18:24:47+09:00
【JavaScript関数ドリル】 初級編join関数の実装
join関数の課題内容
「課題内容」「解説動画」「解答例」を確認したい場合は、以下リンク先のページを参照。 ↓
https://js-drills.com/blog/initial/join関数 に取り組む前の状態
joinメソット自体はどのようなもの知っていた
join関数に取り組んだ後の状態
swiftメソットが配列のはじめを消すことが分かった
join関数の実装コード(答えを見る前)
自力で実装できませんでした。
join関数の実装コード(答えを見た後)
function join(array, separator = ',') { const copiedArray = [...array]; let joinedString = copiedArray.shift(); for(let i = 0; i < copiedArray.length; i++) { joinedString += separator + copiedArray[i]; } return joinedString; } console.log( join(['a', 'b', 'c'], '---') ); // => 'a~b~c'
- 投稿日:2020-09-11T18:22:50+09:00
【技術選定】React.js vs Vue.jsを真剣に評価してみた
目次
1. 対象読者
2. 目的
3. 技術選定の考え方
4. 評価基準
5. 結論
6. 比較評価
7. テックリード/エンジニア募集中!1. 対象読者
React.jsとVue.jsどちらを採用するか?
を悩んでいるフロントエンドのアーキテクトや開発者向けです。2. 目的
適切な技術選定の手助けとなれればと思います。
3. 技術選定の考え方
技術は要件を満たすための手段です。
そのため、技術選定では、求められる要件をまず明確にするべきです。
そして、要件を最も満たす技術を採用するべきです。4. 評価基準
上記の考え方に基づき、よくある要件ごとにReact.js vs Vue.jsを比較評価しました。
- 多角的&客観的に評価するよう心掛けました。
- 主観的な評価の場合、個人見解である旨を明記しました。
【よくある要件をどう網羅したか】
要件は、機能要件/非機能要件に分けられます。
- 機能要件は、多種多様なので網羅困難です。よくありそうな要件(個人見解)のみにしました。
- 非機能要件はIPAの非機能要求グレードを参考に網羅しました。
5. 結論
- 可用性を細かく気にする場合、Vue.jsの方が未解決バグ数は少ないです。(可用性の詳細)
- テーブルの行入れ替えが多いシステムの場合、Vue.jsを選択した方が良いです。(性能の詳細)
- 海外の開発者が必要な場合、React.jsを選択した方が「やや良い」です。(開発者確保の詳細)
- 学習コストを重視する場合、React.jsを選択した方が良いです。(学習コストの詳細)
- それ以外の場合、どちらを選択しても良いです。
【比較表】
評価項目 React Vue 可用性 ○※1 ○ 保守性 ○ ○ セキュリティ ○ ○ 性能 ○※2 ○※2 開発者の確保しやすさ ○ ○ 学習コスト ○ △ 優れたUIの提供しやすさ ○ ○ 開発者が楽しい ○※3 ○※3 ※1 ただし、未解決バグ数がReact.jsの方が多いです。(可用性の詳細)
※2 大きな問題はありませんが、それぞれに得意/不得意があります。(性能の詳細)
※3 個人見解です。上記結論に至った詳細は、以下の通りです。
6. 比較評価
6.1 可用性
安定して継続的に本番稼動できる品質か?という観点で評価しました。
【結論】
引き分けです。未解決バグ数を気にされる場合は、Vue.jsの勝利です。
【理由】
どちらも本番運用実績が十分にある&十分な頻度で改修されているからです。
未解決バグ数はReact.jsの方が数字的には多いです。
個人見解としては気にするほどの差異ではありませんが、気にされる場合はVue.jsの勝利です。
詳細は以下の通りです。【本番運用実績】
どちらも十分な実績があります。
- React.js:Facebook,Uber,Tesla等
- Vue.js:Google, Apple, Nintendo, Gitlab等
【未解決バグ数】
React.jsの方がやや多いです。
GitのIssuesの「bug」タグの数を見ると以下です。(2020/09時点)※本来ならバグ率で比較したかったですが、規模が分からないので断念しました。
※バグ毎の重要度も異なりますので、バグ数はあくまでも参考値という扱いですね。【改修頻度】
どちらもすごい頻度で改修されています。
GitのReleasesから2019年のリリース回数を数えると以下です。6.2 保守性
【結論】
引き分けです。
【理由】
どちらもコンポーネント単位で開発できるため、保守性を確保しやすいからです。
もちろん技術選定以前に、保守性を確保した設計ができていることが大事です。6.3 セキュリティ
【結論】
引き分けです。
【理由】
以下の通り、セキュリティ対策内容に差異が無いためです。
主にフロントエンド側のセキュリティ対策を対象に調査しました。
どちらもXSS対策が組み込まれています。
具体的には以下の通りです。6.3.1 XSS(クロスサイトスクリプティング)
【XSSとは】
Webアプリに罠リンク等を表示できてしまう脆弱性のことです。
悪意のあるユーザが悪意のあるスクリプトやHTMLを入力したとき、
対策されていないWebアプリだと、罠リンク等が表示されてしまいます。罠リンクをクリックしたユーザは、例えばログインセッション情報を盗まれ、不正ログイン(なりすまし)されてしまったり、様々な被害を受けます。
詳細は、「3分でわかるXSSとCSRFの違い」が分かりやすいと思います。
【React.jsのXSS対策】
対策されています。自動でサニタイズ(エスケープ)してくれます。
公式 | JSX はインジェクション攻撃を防ぐ
デフォルトでは、React DOM は JSX に埋め込まれた値をレンダリングされる前にエスケープします。このため、自分のアプリケーションで明示的に書かれたものではないあらゆるコードは、注入できないことが保証されます。レンダーの前に全てが文字列に変換されます。これは XSS (cross-site-scripting) 攻撃の防止に役立ちます。
dangerouslySetInnerHTML
を使用する場合はサニタイズされませんので、脆弱性につながるリスクがあります。スクリプトに該当する文字列をサニタイズする等の対策が必要です。公式 | dangerouslySetInnerHTML
dangerouslySetInnerHTML は、ブラウザ DOM における innerHTML の React での代替です。一般に、コードから HTML を設定することは、誤ってあなたのユーザをクロスサイトスクリプティング (XSS) 攻撃に晒してしまいやすいため、危険です。※GoogleデベロッパーエキスパートでAuth0アンバサダー/エキスパートであるPhilippe De Ryck氏がReact.jsのXSS対策の記事を書いており、参考になります。
Preventing XSS in React※サニタイズとは、ユーザ入力値に含まれるHTML/JavaScript特殊文字をエスケープすることで、HTML/JavaScriptとして解釈されないようにすることです。
【Vue.jsのXSS対策】
対策されています。自動でサニタイズ(エスケープ)してくれます。
公式 | セキュリティ
テンプレートを使用する場合も、描画関数を使用する場合も、コンテンツは自動的にエスケープ処理されます。ただし、
v-html
やdomPropsInnerHTML
を使用する場合はサニタイズされませんので、脆弱性につながるリスクがあります。スクリプトに該当する文字列をサニタイズする等の対策が必要です。SSR(サーバサイドレンダリング)に乗せると、脆弱性につながる場合があります。こちらのサイトが参考になります。
6.3.2 XSS以外
【評価】
React.jsとVue.jsどちらも対策の仕組みはありません。
基本的にフロントエンドではなくバックエンドやミドルウェアで対策するものだからでしょう。【補足】
とはいえ例えば、CSRF対策のトークンをリクエストヘッダに埋め込む等の実装は必要ですね。
サーバで発行したCSRFトークンを、リクエスト毎にヘッダに設定するイメージです。
React.js or Vue.js問わず、Axios等で実装すると思いますが、
Vue.jsならこの記事、React.jsならこの記事が、参考になるかもしれません。6.4 性能
【結論】
引き分けです。
【理由】
一部で得意/不得意の差があるものの、処理時間/メモリ使用量ともに互角です。
詳細は以下の通りです。【処理時間】
ベンチマークサイトによると、それぞれに得意/不得意があります。
※react-v16.4.1、vue-v2.5.16の「keyed」を比較しました。
- React.jsは、テーブルの行入れ替えがVue.jsよりも遅いです。
- Vue.jsは、テーブル行の部分更新がReact.jsよりも遅いです。
- それ以外の処理時間は、どちらも互角です。
以下は、ベンチマークサイトの結果から作成した表です。
【メモリ使用量】
ベンチマークサイトによると、どちらも互角です。
※react-v16.4.1、vue-v2.5.16の「keyed」を比較しました。6.5 開発者の確保しやすさ
【結論】
国内は引き分け、海外は僅差でReact.jsの勝利です。
【理由】
どちらも人気(≒開発者が多い)だからです。
Googleトレンドでは海外だとReact.jsの方が多いです。
具体的には、以下の通りです。【人気度】
React.jsとVue.jsともに、人気度/要望度がトップです。
【GitのStar数】
どちらも同等の人気があります。
【Googleトレンド】
React.jsとVue.jsのGoogleトレンドは、国内は引き分け、海外はReact.jsの勝利です。
※国内はこちら↓
※海外はこちら↓
6.6 学習コスト
【結論】
定量評価だとReact.jsの勝利、定性評価だとVue.jsの勝利(個人見解)です。
客観的に見れば、定量評価を優先してReact.jsの勝利です。【理由】
定量評価だと、Vue.jsの方が覚える量が物理的に多いからです。
具体的には以下の通りです。6.6.1 定量評価:React.jsの勝利
【評価】
JSX記法より、Vue.js構文の方が覚える量が物理的に多いです。
それ以外のstateやRouter等の学習量は、React.jsとVue.jsでほぼ差異はありません。
詳細は以下の通りです。【React.jsで学習が必要なこと】
主に以下の学習が必要です。
- JSX記法
- state/Redux
- Router/hook等
【Vue.jsで学習が必要なこと】
主に以下の学習が必要です。
- Vue.js構文(各種ディレクティブ/computed/watch/method等)
- state/Vuex
- Router等
6.6.2 定性評価:Vue.jsの勝利(個人見解)
【評価】
Vue.jsの方が学習しやすいです。個人見解です。
【理由】
個人見解ですが、見慣れないJSX記法より、HTMLっぽく読めるVue.jsの方が、抵抗感無く学習できたからです。
※慣れてしまった今はJSX記法への抵抗感は無いですが、当初は抵抗感があったという意味です。6.7 優れたUIの提供しやすさ
【結論】
引き分けです。
【理由】
以下の通り、「優れたUI」を実装するコストに差異が無いためです。
【優れたUIの定義】
この記事では、ユーザーが考えずに操作できるUIを「優れたUI」と定義します。
※参考:Steve Krug著「Don't Make Me Think」優れたUIの具体例は以下です。
・どれがクリックできる要素か?が明確であること。
・説明がシンプル&明確であること。(自己満足な宣伝文句が無い)【評価観点】
まず、設計工程で「優れたUI」が設計されている必要があります。
その前提で、React.jsとVue.jsのどちらが実装コストが少ないか?で評価します。【評価】
実装コストに差異は無いでしょう。
- UIフレームワークで実現できるUIデザインの場合
- React.jsなら「Material-UI」等、Vue.jsなら「Vuetify」等で実装できます。
- 上記で実現できない凝ったUIデザインの場合
- React.js or Vue.jsに関わらず、UIフレームワークのカスタマイズや独自CSSの実装が必要です。
6.8 開発者が楽しい
開発者のモチベーションは大事ですね。
【結論】
引き分けです。
【理由】
開発者の主観で決まりますので引き分けです。
個人見解としては、どちらも楽しいです。7. テックリード/エンジニア募集中!
株式会社ビジョン・コンサルティングでは、アーキテクトや開発者を募集しています!
世界をより便利にすることに情熱を燃やし、新規事業部で新サービスを一緒に開発しませんか?
詳細はこちら!
- 投稿日:2020-09-11T18:22:50+09:00
React.js vs Vue.jsを真剣に評価してみたら、巷の評価とは違う結果になった
目次
1. 対象読者
2. 目的
3. 技術選定の考え方
4. 評価基準
5. 結論 | 比較表
6. 比較評価
7. テックリード/エンジニア募集中!1. 対象読者
React.jsとVue.jsどちらを採用するか?
を悩んでいるフロントエンドのアーキテクトや開発者向けです。2. 目的
適切な技術選定の手助けとなれればと思います。
3. 技術選定の考え方
技術は要件を満たすための手段です。
そのため、技術選定では、求められる要件をまず明確にするべきです。
そして、要件を最も満たす技術を採用するべきです。4. 評価基準
上記の考え方に基づき、よくある要件ごとにReact.js vs Vue.jsを比較評価しました。
- 多角的&客観的に評価するよう心掛けました。
- 主観的な評価の場合、個人見解である旨を明記しました。
【よくある要件をどう網羅したか】
要件は、機能要件/非機能要件に分けられます。
- 機能要件は、多種多様なので網羅困難です。よくありそうな要件(個人見解)のみにしました。
- 非機能要件はIPAの非機能要求グレードを参考に網羅しました。
5. 結論 | 比較表
- 可用性を細かく気にする場合、Vue.jsの方が未解決バグ数は少ないです。(可用性の詳細)
- テーブルの行入れ替えが多いシステムの場合、Vue.jsを選択した方が良いです。(性能の詳細)
- 海外の開発者が必要な場合、React.jsを選択した方が「やや良い」です。(開発者確保の詳細)
- 学習コストを重視する場合、React.jsを選択した方が良いです。(学習コストの詳細)
- それ以外の場合、どちらを選択しても良いです。
【比較表】
評価項目 React Vue 可用性 ○※1 ○ 保守性 ○ ○ セキュリティ ○ ○ 性能 ○※2 ○※2 開発者の確保しやすさ ○ ○ 学習コスト ○ △ 優れたUIの提供しやすさ ○ ○ 開発者が楽しい ○※3 ○※3 ※1 ただし、未解決バグ数がReact.jsの方が多いです。(可用性の詳細)
※2 大きな問題はありませんが、それぞれに得意/不得意があります。(性能の詳細)
※3 個人見解です。上記結論に至った詳細は、以下の通りです。
6. 比較評価
6.1 可用性
安定して継続的に本番稼動できる品質か?という観点で評価しました。
【結論】
引き分けです。未解決バグ数を気にされる場合は、Vue.jsの勝利です。
【理由】
どちらも本番運用実績が十分にある&十分な頻度で改修されているからです。
未解決バグ数はReact.jsの方が数字的には多いです。
個人見解としては気にするほどの差異ではありませんが、気にされる場合はVue.jsの勝利です。
詳細は以下の通りです。【本番運用実績】
どちらも十分な実績があります。
- React.js:Facebook,Uber,Tesla等
- Vue.js:Google, Apple, Nintendo, Gitlab等
【未解決バグ数】
React.jsの方がやや多いです。
GitのIssuesの「bug」タグの数を見ると以下です。(2020/09時点)※本来ならバグ率で比較したかったですが、規模が分からないので断念しました。
※バグ毎の重要度も異なりますので、バグ数はあくまでも参考値という扱いですね。【改修頻度】
どちらもすごい頻度で改修されています。
GitのReleasesから2019年のリリース回数を数えると以下です。6.2 保守性
【結論】
引き分けです。
【理由】
どちらもコンポーネント単位で開発できるため、保守性を確保しやすいからです。
もちろん技術選定以前に、保守性を確保した設計ができていることが大事です。6.3 セキュリティ
【結論】
引き分けです。
【理由】
以下の通り、セキュリティ対策内容に差異が無いためです。
主にフロントエンド側のセキュリティ対策を対象に調査しました。
どちらもXSS対策が組み込まれています。
具体的には以下の通りです。6.3.1 XSS(クロスサイトスクリプティング)
【XSSとは】
Webアプリに罠リンク等を表示できてしまう脆弱性のことです。
悪意のあるユーザが悪意のあるスクリプトやHTMLを入力したとき、
対策されていないWebアプリだと、罠リンク等が表示されてしまいます。罠リンクをクリックしたユーザは、例えばログインセッション情報を盗まれ、不正ログイン(なりすまし)されてしまったり、様々な被害を受けます。
詳細は、「3分でわかるXSSとCSRFの違い」が分かりやすいと思います。
【React.jsのXSS対策】
対策されています。自動でサニタイズ(エスケープ)してくれます。
公式 | JSX はインジェクション攻撃を防ぐ
デフォルトでは、React DOM は JSX に埋め込まれた値をレンダリングされる前にエスケープします。このため、自分のアプリケーションで明示的に書かれたものではないあらゆるコードは、注入できないことが保証されます。レンダーの前に全てが文字列に変換されます。これは XSS (cross-site-scripting) 攻撃の防止に役立ちます。
dangerouslySetInnerHTML
を使用する場合はサニタイズされませんので、脆弱性につながるリスクがあります。スクリプトに該当する文字列をサニタイズする等の対策が必要です。公式 | dangerouslySetInnerHTML
dangerouslySetInnerHTML は、ブラウザ DOM における innerHTML の React での代替です。一般に、コードから HTML を設定することは、誤ってあなたのユーザをクロスサイトスクリプティング (XSS) 攻撃に晒してしまいやすいため、危険です。※GoogleデベロッパーエキスパートでAuth0アンバサダー/エキスパートであるPhilippe De Ryck氏がReact.jsのXSS対策の記事を書いており、参考になります。
Preventing XSS in React※サニタイズとは、ユーザ入力値に含まれるHTML/JavaScript特殊文字をエスケープすることで、HTML/JavaScriptとして解釈されないようにすることです。
【Vue.jsのXSS対策】
対策されています。自動でサニタイズ(エスケープ)してくれます。
公式 | セキュリティ
テンプレートを使用する場合も、描画関数を使用する場合も、コンテンツは自動的にエスケープ処理されます。ただし、
v-html
やdomPropsInnerHTML
を使用する場合はサニタイズされませんので、脆弱性につながるリスクがあります。スクリプトに該当する文字列をサニタイズする等の対策が必要です。SSR(サーバサイドレンダリング)に乗せると、脆弱性につながる場合があります。こちらのサイトが参考になります。
6.3.2 XSS以外
【評価】
React.jsとVue.jsどちらも対策の仕組みはありません。
基本的にフロントエンドではなくバックエンドやミドルウェアで対策するものだからでしょう。【補足】
とはいえ例えば、CSRF対策のトークンをリクエストヘッダに埋め込む等の実装は必要ですね。
サーバで発行したCSRFトークンを、リクエスト毎にヘッダに設定するイメージです。
React.js or Vue.js問わず、Axios等で実装すると思いますが、
Vue.jsならこの記事、React.jsならこの記事が、参考になるかもしれません。6.4 性能
【結論】
引き分けです。
【理由】
一部で得意/不得意の差があるものの、処理時間/メモリ使用量ともに互角です。
詳細は以下の通りです。【処理時間】
ベンチマークサイトによると、それぞれに得意/不得意があります。
※react-v16.4.1、vue-v2.5.16の「keyed」を比較しました。
- React.jsは、テーブルの行入れ替えがVue.jsよりも遅いです。
- Vue.jsは、テーブル行の部分更新がReact.jsよりも遅いです。
- それ以外の処理時間は、どちらも互角です。
以下は、ベンチマークサイトの結果から作成した表です。
【メモリ使用量】
ベンチマークサイトによると、どちらも互角です。
※react-v16.4.1、vue-v2.5.16の「keyed」を比較しました。6.5 開発者の確保しやすさ
【結論】
国内は引き分け、海外は僅差でReact.jsの勝利です。
【理由】
どちらも人気(≒開発者が多い)だからです。
Googleトレンドでは海外だとReact.jsの方が多いです。
具体的には、以下の通りです。【人気度】
React.jsとVue.jsともに、人気度/要望度がトップです。
【GitのStar数】
どちらも同等の人気があります。
【Googleトレンド】
React.jsとVue.jsのGoogleトレンドは、国内は引き分け、海外はReact.jsの勝利です。
※国内はこちら↓
※海外はこちら↓
6.6 学習コスト
【結論】
定量評価だとReact.jsの勝利、定性評価だとVue.jsの勝利(個人見解)です。
客観的に見れば、定量評価を優先してReact.jsの勝利です。【理由】
定量評価だと、Vue.jsの方が覚える量が物理的に多いからです。
具体的には以下の通りです。6.6.1 定量評価:React.jsの勝利
【評価】
JSX記法より、Vue.js構文の方が覚える量が物理的に多いです。
それ以外のstateやRouter等の学習量は、React.jsとVue.jsでほぼ差異はありません。
詳細は以下の通りです。【React.jsで学習が必要なこと】
主に以下の学習が必要です。
- JSX記法
- state/Redux
- Router/hook等
【Vue.jsで学習が必要なこと】
主に以下の学習が必要です。
- Vue.js構文(各種ディレクティブ/computed/watch/method等)
- state/Vuex
- Router等
6.6.2 定性評価:Vue.jsの勝利(個人見解)
【評価】
Vue.jsの方が学習しやすいです。個人見解です。
【理由】
個人見解ですが、見慣れないJSX記法より、HTMLっぽく読めるVue.jsの方が、抵抗感無く学習できたからです。
※慣れてしまった今はJSX記法への抵抗感は無いですが、当初は抵抗感があったという意味です。6.7 優れたUIの提供しやすさ
【結論】
引き分けです。
【理由】
以下の通り、「優れたUI」を実装するコストに差異が無いためです。
【優れたUIの定義】
この記事では、ユーザーが考えずに操作できるUIを「優れたUI」と定義します。
※参考:Steve Krug著「Don't Make Me Think」優れたUIの具体例は以下です。
・どれがクリックできる要素か?が明確であること。
・説明がシンプル&明確であること。(自己満足な宣伝文句が無い)【評価観点】
まず、設計工程で「優れたUI」が設計されている必要があります。
その前提で、React.jsとVue.jsのどちらが実装コストが少ないか?で評価します。【評価】
実装コストに差異は無いでしょう。
- UIフレームワークで実現できるUIデザインの場合
- React.jsなら「Material-UI」等、Vue.jsなら「Vuetify」等で実装できます。
- 上記で実現できない凝ったUIデザインの場合
- React.js or Vue.jsに関わらず、UIフレームワークのカスタマイズや独自CSSの実装が必要です。
6.8 開発者が楽しい
開発者のモチベーションは大事ですね。
【結論】
引き分けです。
【理由】
開発者の主観で決まりますので引き分けです。
個人見解としては、どちらも楽しいです。7. テックリード/エンジニア募集中!
株式会社ビジョン・コンサルティングでは、アーキテクトや開発者を募集しています!
世界をより便利にすることに情熱を燃やし、新規事業部で新サービスを一緒に開発しませんか?
詳細はこちら!
- 投稿日:2020-09-11T18:18:03+09:00
簡易LISP処理系の実装例(JavaScript版)
Python版,Scheme版,C言語版,Ruby版に続く第五の実装例です.しばらくはここまでかな.
この記事は,下記拙作記事のJavaScript版を抜粋・修正したものを利用した,簡易LISP処理系の実装例をまとめたものです.
主旨およびプログラムコードはPython版とほぼ同じで,最低限の機能をもったLISP処理系の実装の場合,本体である超循環評価器(meta-circular evaluator)の作成はとても簡単であり,むしろ,字句・構文解析を行うS式入出力やリスト処理実装の方が開発言語ごとの手間が多く,それが敷居になっている人向けにまとめています.
処理系の概要
実行例は次の通り.Node.js 10.21にて確認.
> s_rep("(car (cdr '(10 20 30)))") '20' > s_rep("((lambda (x) (car (cdr x))) '(abc def ghi))") 'def' > s_rep("((lambda (f x y) (f x (f y '()))) 'cons '10 '20)") '(10 20)' > s_rep("((lambda (f x y) (f x (f y '()))) \ ... '(lambda (x y) (cons x (cons y '()))) \ ... '10 '20)") '(10 (20 ()))' > s_rep("((lambda (assoc k v) (assoc k v)) \ ... '(lambda (k v) \ ..... (cond ((eq v '()) nil) \ ....... ((eq (car (car v)) k) \ ......... (car v)) \ ....... ('t (assoc k (cdr v))))) \ ... 'Orange \ ... '((Apple . 120) (Orange . 210) (Lemmon . 180)))") '(Orange . 210)'実装内容は次の通り.
- "McCarthy's Original Lisp"をベースにした超循環評価器
- 数字を含むアトムは全てシンボルとし,変数の値とする場合は
quote
('
)を使用- 構文として
quote
の他,cond
とlambda
が使用可能- 組込関数:
atom
eq
cons
car
cdr
(内部でコンスセルを作成)- 真偽値は
t
(真)およびnil
(偽)=空リスト=null
- エラーチェックなし,モジュール化なし,ガーベジコレクションなし
"McCarthy's Original Lisp"の詳細についてはScheme版記事を参照.ダイナミックスコープということもあり,実行例ではlambda式を
letrec
(Scheme)やlabels
(Common Lisp)などの代わりに使用しています.実装例
ソースコード一式
jmclisp.js// // JMC Lisp: defined in McCarthy's 1960 paper, // with S-expression input/output and basic list processing // // basic list processing: cons, car, cdr, eq, atom function cons(x, y) { return Object.freeze([x, y]); } function car(s) { return s[0]; } function cdr(s) { return s[1]; } function eq(s1, s2) { return s1 === s2; } function atom(s) { return typeof s == 'string' || eq(s, null) || eq(s, true) || eq(s, false); } // S-expression input: s_read function s_lex(s) { s = s.replace(/(\(|\)|\'|\,)/g, ' $1 '); return s.split(/\s+/).filter(x => x != ''); } function s_syn(s) { function quote(x, s) { if (s.length != 0 && s.slice(-1)[0] == '\'') { s.pop(); return cons("quote", cons(x, null)); } else { return x } } var t = s.pop(); if (t == ')') { var r = null; while (s.slice(-1)[0] != '(') { if (s.slice(-1)[0] == '.') { s.pop(); r = cons(s_syn(s), car(r)); } else { r = cons(s_syn(s), r); } } s.pop(); return quote(r, s); } else { return quote(t, s); } } function s_read(s) { return s_syn(s_lex(s)); } // S-expression output: s_string function s_strcons(s) { var sa_r = s_string(car(s)); var sd = cdr(s); if (eq(sd, null)) { return sa_r; } else if (atom(sd)) { return sa_r + ' . ' + sd; } else { return sa_r + ' ' + s_strcons(sd); } } function s_string(s) { if (eq(s, null)) return '()'; else if (eq(s, true)) return 't'; else if (eq(s, false)) return 'nil'; else if (atom(s)) return s; else return '(' + s_strcons(s) + ')'; } // JMC Lisp meta-circular evaluator: s_eval function caar(x) { return car(car(x)); } function cadr(x) { return car(cdr(x)); } function cadar(x) { return car(cdr(car(x))); } function caddr(x) { return car(cdr(cdr(x))); } function caddar(x) { return car(cdr(cdr(car(x)))); } function s_null(x) { return eq(x, null); } function s_append(x, y) { if (s_null(x)) return y; else return cons(car(x), s_append(cdr(x), y)); } function s_list(x, y) { return cons(x, cons(y, null)); } function s_pair(x, y) { if (s_null(x) && s_null(y)) return null; else if (!atom(x) && !atom(y)) return cons(s_list(car(x), car(y)), s_pair(cdr(x), cdr(y))); } function s_assoc(x, y) { if (eq(caar(y), x)) return cadar(y); else return s_assoc(x, cdr(y)); } function s_eval(e, a) { if (eq(e, "t")) return true; else if (eq(e, "nil")) return false else if (atom(e)) return s_assoc(e, a); else if (atom(car(e))) { if (eq(car(e), "quote")) return cadr(e); else if (eq(car(e), "atom")) return atom(s_eval(cadr(e), a)); else if (eq(car(e), "eq")) return eq( s_eval(cadr(e), a), s_eval(caddr(e), a)); else if (eq(car(e), "car")) return car( s_eval(cadr(e), a)); else if (eq(car(e), "cdr")) return cdr( s_eval(cadr(e), a)); else if (eq(car(e), "cons")) return cons(s_eval(cadr(e), a), s_eval(caddr(e), a)); else if (eq(car(e), "cond")) return evcon(cdr(e), a); else return s_eval(cons(s_assoc(car(e), a), cdr(e)), a); } else if (eq(caar(e), "lambda")) return s_eval(caddar(e), s_append(s_pair(cadar(e), evlis(cdr(e), a)), a)); else console.log("Error"); } function evcon(c, a) { if (s_eval(caar(c), a)) return s_eval(cadar(c), a); else return evcon(cdr(c), a); } function evlis(m, a) { if (s_null(m)) return null; else return cons(s_eval(car(m), a), evlis(cdr(m), a)); } // REP (no Loop): s_rep function s_rep(e) { return s_string(s_eval(s_read(e), s_read("()"))); }解説
リスト処理:
cons
car
cdr
eq
atom
先の記事より,ほぼそのまま抜粋.S式入力:
s_read
Python版とほぼ同じ.先の記事から,字句解析部を()
および'
の識別に変更(s_lex
),抽象構文木生成部をドット対とクォート記号対応としつつ,リスト処理関数でコンスセルによる構文木を生成するよう変更(s_syn
),それらをまとめたS式入力関数s_read
を定義.S式出力:
s_string
ほぼPython版の書き換え.内部ではnull
である空リストは()
を,真偽値はt
nil
を出力するよう設定.超循環評価器:
s_eval
+ユーティリティ関数
こちらも,ほぼPython版の書き換え."McCarthy's Original Lisp"をベースにs_eval
関数およびユーティリティ関数を作成.REP (no Loop):
s_rep
s_read
→s_eval
→s_string
をまとめたs_rep
を定義.備考
記事に関する補足
- 超循環評価器のみの場合,約50行/1900バイトほど.Python版とほぼ同じかな.
更新履歴
2020-09-11:
eq
の定義について,==
ではなく===
を使用(コメントより)
2020-09-11:初版公開
- 投稿日:2020-09-11T17:39:50+09:00
【Node.js】dotenvを使用して環境変数を設定する方法&設定した環境変数をHerokuにも適用する方法
node.jsで環境変数を設定する場合、
「dotenv」を使用すれば楽に設定することができる
色々と遠回りというか勘違いをして時間がかかってしまったのでメモ手順
- ルートディレクトリに「.env」という名前のファイルを作成
- ターミナルにて
$npm install dotenv --save
を実行- 1で作成した.envに環境変数として使用したいkey&valueを以下のように記載
.envNODE_USER_ID=12345678 NODE_PASSWORD=abcdefgh4.環境変数を使用したい箇所に以下のように記載
app.jsrequire('dotenv').config(); let userId = process.env.NODE_USER_ID; // 12345678 console.log(userId);以上の手順で環境変数を設定できます。
※.gitignoreに .envを追記するのを忘れないようにしてください。
記載済みであれば大丈夫です。あくまでもローカル上での設定となりますので、
Herokuにデプロイしているアプリに対して環境変数を適用する方法を以下に記載しました。Herokuにデプロイする場合
便利ですよね、heroku。
Githubとherokuを連携している場合、.envファイルをプッシュしていないのでどうしたものかと・・・。Config Varsを設定する
2.「Reveal Config Vars」ボタンをクリック
3.お誂え向きなKEYとVALUEを入力できるフォームが出てくるので、
.envに記載している内容と同等のものを記載し、ADDをクリック
以上で、.envをgitに上げなくてもHerokuにデプロイしたアプリから、
環境変数を呼び出すことが可能となります。備考
アプリ公開しました!よろしければインストールお願いします。
とらんぽTwitter始めました!よろしければフォローお願いします。
@yajima_tohshu
- 投稿日:2020-09-11T17:39:50+09:00
【Node.js】dotenvを使用して環境変数を設定&設定した環境変数をHerokuにも適用する方法
node.jsで環境変数を設定する場合、
「dotenv」を使用すれば楽に設定することができる
色々と遠回りというか勘違いをして時間がかかってしまったのでメモ手順
- ルートディレクトリに「.env」という名前のファイルを作成
- ターミナルにて
$npm install dotenv --save
を実行- 1で作成した.envに環境変数として使用したいkey&valueを以下のように記載
.envNODE_USER_ID=12345678 NODE_PASSWORD=abcdefgh4.環境変数を使用したい箇所に以下のように記載
app.jsrequire('dotenv').config(); let userId = process.env.NODE_USER_ID; // 12345678 console.log(userId);以上の手順で環境変数を設定できます。
※.gitignoreに .envを追記するのを忘れないようにしてください。
記載済みであれば大丈夫です。あくまでもローカル上での設定となりますので、
Herokuにデプロイしているアプリに対して環境変数を適用する方法を以下に記載しました。Herokuにデプロイする場合
便利ですよね、heroku。
Githubとherokuを連携している場合、.envファイルをプッシュしていないのでどうしたものかと・・・。Config Varsを設定する
2.「Reveal Config Vars」ボタンをクリック
3.お誂え向きなKEYとVALUEを入力できるフォームが出てくるので、
.envに記載している内容と同等のものを記載し、ADDをクリック
以上で、.envをgitに上げなくてもHerokuにデプロイしたアプリから、
環境変数を呼び出すことが可能となります。備考
アプリ公開しました!よろしければインストールお願いします。
とらんぽTwitter始めました!よろしければフォローお願いします。
@yajima_tohshu
- 投稿日:2020-09-11T17:28:34+09:00
【Vue.js】何気なく使っているthisとかcontextとかって結局なんなの??
オブジェクト 指すもの 使う場面 this Vueインスタンス 現Vueインスタンスを指定する時 context ・Vueインスタンス生成前のインスタンス・Storeインスタンス ・まだVueインスタンスが作られる前にVueインスタンスを使いたい時。・Storeメソッドを使いたい時。 thisオブジェクト
data
Vueインスタンスを指す
data () { return { email: '' } }, methods: { into () { this.email = 'foo@bar.com' } }Vueメソッド
Vueインスタンスを指す
methods: { async login () { const res = await this.$axios.$get('/login') } }contextオブジェクト
asyncData
仮のVueインスタンスを指す
async asyncData(context) { const posts = await context.$axios.$get('/posts') return { posts } },
{ posts }
とは{ posts: posts }
の略async asyncData (context) { const res = await context.$axios.$get('/posts/' + context.params.id) return { post: res.data } }Vuexのstoreメソッド
Storeインスタンスを指す
export const actions = { async login (context) { await context.commit('switchLogin') }) }
- 投稿日:2020-09-11T17:12:08+09:00
javascript関数ドリル 初級編head関数の実相のアウトプット
initial関数の課題内容
詳細はこちら
↓
https://js-drills.com/blog/initial/initial関数の取り組む前の状態
配列の一番初めに何かをするのかと思った
initial関数に取り組んだ後の状態
分かった
initial関数の実装コード(答えを見る前)
実行できませんでした
initial関数の実装コード(答えを見た後)
function initial(array) { const copiedArray = [...array]; copiedArray.pop(); return copiedArray; } const numbers = [1, 2, 3]; console.log( initial(numbers) ); // => [1, 2] console.log('number : ', numbers);
- 投稿日:2020-09-11T17:12:08+09:00
javascript関数ドリル 初級編initial関数の実相のアウトプット
initial関数の課題内容
詳細はこちら
↓
https://js-drills.com/blog/initial/initial関数の取り組む前の状態
配列の一番初めに何かをするのかと思った
initial関数に取り組んだ後の状態
popメソットが配列の最後を取り除くことが分かった
initial関数の実装コード(答えを見る前)
実行できませんでした
initial関数の実装コード(答えを見た後)
function initial(array) { const copiedArray = [...array]; copiedArray.pop(); return copiedArray; } const numbers = [1, 2, 3]; console.log( initial(numbers) ); // => [1, 2] console.log('number : ', numbers);
- 投稿日:2020-09-11T16:43:54+09:00
javascript関数ドリル 初級編head関数の実相のアウトプット
indexOf関数の課題内容
詳細はこちら
↓
https://js-drills.com/blog/indexof/indexOf関数の取り組む前の状態
見てなんとなくわかった
indexOf関数に取り組んだ後の状態
return -1以外は分かった
indexOf関数の実装コード(答えを見る前)
function indexOf(array, value, secoundIndex = 0) { for(let i = secoundIndex; i < array.length; i++) { if(array[i] === value) { return i; }}}indexOf関数の実装コード(答えを見た後)
function indexOf(array, value, fromIndex = 0) { for(let i = fromIndex; i < array.length; i++) { if(array[i] === value) { return i; } } return -1; } // console.log( indexOf([1, 2, 1, 2], 2) ); // => 1 // Search from the `fromIndex`. console.log( indexOf([1, 2, 1, 2], 3, 2) ); // => 3
- 投稿日:2020-09-11T16:43:54+09:00
javascript関数ドリル 初級編indexOf関数の実相のアウトプット
indexOf関数の課題内容
詳細はこちら
↓
https://js-drills.com/blog/indexof/indexOf関数の取り組む前の状態
見てなんとなくわかった
indexOf関数に取り組んだ後の状態
return -1以外は分かった
indexOf関数の実装コード(答えを見る前)
function indexOf(array, value, secoundIndex = 0) { for(let i = secoundIndex; i < array.length; i++) { if(array[i] === value) { return i; }}}indexOf関数の実装コード(答えを見た後)
function indexOf(array, value, fromIndex = 0) { for(let i = fromIndex; i < array.length; i++) { if(array[i] === value) { return i; } } return -1; } // console.log( indexOf([1, 2, 1, 2], 2) ); // => 1 // Search from the `fromIndex`. console.log( indexOf([1, 2, 1, 2], 3, 2) ); // => 3
- 投稿日:2020-09-11T16:35:43+09:00
【React】クラスコンポーネント /関数コンポーネントの違いと使い分け。なぜ 関数コンポーネントが好まれるのか。
はじめに
どうもシュータといいます!
2019年、 React 16.8のリリースに伴いHooksが導入され、
stateやlife cycle methodを使用する際はClass Componentを使用した方が良いという判断が実情に合わなくなってしまったように思います。
この記事では今一度、クラスコンポーネントと関数コンポーネントの違いを明らかにしつつ、Hooksの導入に伴いどう変化したか、
そして関数コンポーネントが好まれやすいのは何故かという理由を記載します。関数コンポーネントとクラスコンポーネント
まず関数コンポーネントとクラスコンポーネントで
シンプルなコンポーネントを作成した例を示します。関数コンポーネントfunction Welcome(props) { return <h1>Hello, {props.name} </h1>; }こちらは基本的なjavascriptの関数と同様です。
propsを受け取り、使用することが可能です。クラスコンポーネントclass Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } }こちらはReactのCompoentクラスを継承しています。
クラスコンポーネントでもpropsを受け取り
使用することは可能です。Hooks導入以前の関数コンポーネントとクラスコンポーネントの主な違い
クラスコンポーネントでは関数コンポーネントと異なり、コンポーネント内で下記の二つを使用することができます。
- state(状態管理)
- Lifecycle method
stateの例
class Welcome extends React.Component { constructor(props){ super(props) this.state = { name: "hoge" } } render() { return <h1>Hello, {this.state.name}</h1>; } }Lifecycle methodの例
詳しくはこちらをご覧ください。
class Welcome extends React.Component { constructor(props){ super(props) this.state = { name: "hoge" } } componentDidMount() { this.setState({name:"fuga"}) } render() { return <h1>Hello, {this.state.name}</h1>; } }Hooks導入後
HooKs導入前は関数コンポーネントとクラスコンポーネントは
前述のような違いがありましたが
Hooksの登場により、関数コンポーネントでも
状態管理やライフサイクルの機能を使用できるようになりました。
そしてそれらはクラスコンポーネントで記述するよりも
簡潔に書くことが可能です。状態管理
Hooksを利用した関数コンポーネントで状態管理する例import React, { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }同様のコンポーネントをクラスコンポーネントで書いた場合class Example extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } render() { return ( <div> <p>You clicked {this.state.count} times</p> <button onClick={() => this.setState({ count: this.state.count + 1 })}> Click me </button> </div> ); } }ライフサイクル
Hooksを利用した関数コンポーネントでライフサイクルメソッドを使う例import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); // Similar to componentDidMount and componentDidUpdate: useEffect(() => { // Update the document title using the browser API document.title = `You clicked ${count} times`; }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> );同様のコンポーネントをクラスコンポーネントで書いた場合class Example extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } componentDidMount() { document.title = `You clicked ${this.state.count} times`; } componentDidUpdate() { document.title = `You clicked ${this.state.count} times`; } render() { return ( <div> <p>You clicked {this.state.count} times</p> <button onClick={() => this.setState({ count: this.state.count + 1 })}> Click me </button> </div> ); } }なぜ関数コンポーネントが好まれるか
- コードが簡潔にかける
これまでみてきたように
関数コンポーネントで記述することによってより見通しの良いコードがかけることに気付いていただけたと思います。
- Viewからの複雑さを排除することも可能となる
これまで示した例だけでなく、データフロー全体の設計からの観点となりますがコンポーネントになるべく状態を持たせない設計や、view以外ファイルにAPI通信などの副作用を局所化させる設計を行うことより
viewの責務を軽くすることも可能です。
将来的にReact以外のライブラリ、フレームワークを使用することになった際も乗り換えやすくなることが期待できます。最後に
読んでくださった方ありがとうございました!
誤字脱字・間違い等ございましたら、指摘して頂けますと幸いです!
また、説明にわかりづらい点がございましたら、改善致しますのでぜひコメントください。reference