銀の弾丸

プログラミングに関して、いろいろ書き残していければと思っております。

ES6に対応した「grunt-contrib-uglify-es」を使用する

grunt-contrib-uglifyのES6対応版がgrunt-contrib-uglify-esという名で別途公開されてましたというお話。

f:id:takamints:20180322202444p:plain

速習ECMAScript6: 次世代の標準JavaScriptを今すぐマスター! 速習シリーズ
WINGSプロジェクト (2015-08-28)
売り上げランキング: 1,828

JavaScriptのタスクランナーGruntからUglify-Jsを使用してスクリプトを圧縮・難読化する grunt-contrib-uglify なんですが、ES6に対応していなくて困ってました。 ES6の「アロー関数」や「 letによるブロックスコープの変数宣言」は、うっかりミスの防止に役立ちますから今後なるべく使いたい。 この手のバグは見つけにくいので手を焼きますから。

「しかし uglify でコケるから・・・」ってのはまさに本末転倒。ということで、本腰入れて「どうにかならんか?」と調べてみたら Stack Overflow に、

「grunt-contrib-uglify の harmony ブランチが使えるぜ!」という情報がありました。 このブランチで(その名の通り)ES6対応しているようです(完全ではないとも書いてありますが)。 で、GitHub から特定ブランチをnpmでインストールするには以下のようにすれば良いらしい。

$ npm install git://github.com/gruntjs/grunt-contrib-uglify.git#harmony --save-dev

これを実行すると grunt-contrib-uglify-es というモジュールがインストールされたので、まさかと思って npm で grunt-contrib-uglify-es を検索すると、なんとそのものズバリが公開されているじゃありませんか。てことで、GitHubから取ってこなくても、以下の普通なnpmでよかったみたい。

$ npm install grunt-contrib-uglify-es --save-dev

加えてモジュール名が変わったので、 Gruntfile.js のタスクロード部分も書き換えが必要ですね。

Gruntfile.js

    ~
    grunt.loadNpmTasks('grunt-contrib-uglify-es');
    ~

これでめでたくアロー関数とletが使えるようになりました。

元々入ってた grunt-contrib-uglify は、残しておいても問題なさそうですが、 まあ、使わないならアンインストールしておくべきでしょう。

参考サイト

AdSense「自動広告」の破壊力!~ゲームのルールが変わったかもね?全部おまかせでよいのかな?

f:id:takamints:20180307110302j:plain
photo credit: vinayaketx Top 12 Tips To INCREASE ADSENSE REVENUE | Adsense Optimization 2018 via photopin (license)


最近AdSenseで「自動広告」なるものが使えるようになりました。 とても便利でお手軽で、素晴らしいソリューションだと感動しました。 しかし「AIが人々の仕事を奪っちゃう!」とまでは行きませんが、少し危機感も感じてます(後述)・・・。

てことで、ちょっとホットなAdSenseの「自動広告」について(遅ればせながら)書いておきます。

まずは「AdSenseアドセンス)ってなに?」って所から

(ここはAdSenseのアカウントを持ってる人は読み飛ばしてもらって結構です)

AdSenseGoogleの広告配信サービスです。自社製品やサービスを宣伝したい広告主と、ブログやWebサイトをインターネットに公開している人(=サイト運営者)をAdSenseが結びつけ、広告主の広告をサイト運営者のサイトへ表示します。

サイト運営者は自分のサイトの広告を表示したい場所に、広告ユニットというAdSenseが提供するHTML要素(SCRIPTとDIV)を貼り付けます。広告ユニットはAdSenseの管理画面で、サイズや種類を指定して自分で作る必要がありますよ。この広告ユニットをサイトを訪れた人(=サイト来訪者)が見たり、クリックしたりすると、サイト運営者に収入が発生するのです。

AdSense自体の収入源は広告主から出される広告の掲載料金(出稿料)なのですが、そこから運営者のサイト内で実際に広告が表示された回数(=PV:ページビュー)や、サイト来訪者が興味を示した度合い(≒クリック数)に応じて、サイト運営者に一定の金額が還元されます(=サイト運営者の収益額、もしくは見積もり収益額)。

サイト運営者の収益額は、広告が表示された回数とクリックされた回数にほぼ比例しているのですが、実際には表示された広告や世の中の動きによって細かく変動します。 しかし、少なくともある一定期間内の平均として、PVに対する収益の指標は存在していますので、サイト運営者が効率よく収益を上げるには、自サイトのPVを上げることと、PVに対して効率よく収益を上げること(=たくさんクリックしてもらうこと)です。

「自動広告」の便利なところ・凄いところ

さて本題。「自動広告」の便利なところですが、簡単に言ってしまえば、広告の表示位置やサイズをあれこれ考える必要がないところ。

専門知識が不要です

既にAdSenseを利用している方たちならおわかりでしょう。 広告ユニットの表示位置やサイズには流行りあって、そのとき「どう選択するか?」は、それなりのテクニックやノウハウだったと思います。

でも自動広告では考える必要がなくなりました。 ブログやWEBサイトに所定のスクリプトを貼り付ければ、Googleさんがサイト内の最適な表示位置とサイズを決定して、広告ユニットを表示してくれるのです。 つまりサイトの運営者は「サイト来訪者に最高に訴求する広告は、どこにどれぐらいのサイズだろうか?」などと頭をひねる必要がありません。

加えて、

レイアウトをいじらなくて済みますね

多くの(特に無料の)ブログシステムでは、レイアウトへのアクセスに制限がかかっている場合や、編集しづらい場合がありますね。

そのため自分で「最適だ」と考えた位置に広告を表示できなかったり、特定のプログラミングスキル(JavaScript, HTML, DOM, CSS)を習得しなければならなかったりしていました。あたしはそこは、それなりに専門なので問題ありませんけれど、おしゃれで小粋な次世代ブロガー全員が、その方面に明るいわけではありません。

しかし繰り返しになりますが、自動広告ではグーグルさんが最適な位置に表示してくれるので、まったく問題になりません。

だから参入障壁がなくなった

広告のレイアウトを一度決めたら、あとからあまり変更しないとは思いますが、AdSenseへの参入障壁にはなっていたような気もします。

しかし、これから始めようという人にとって「自動広告」で敷居は下がった、もしくは敷居がなくなった。

これはおそらくすごいことだと思うんですよ。

さらに端末種類を選ばない

AdSenseには、以前からモバイル用のページ単位の広告というのがあり、所定のスクリプトを貼るだけで、モバイルの画面に広告を表示してくれるというものでした。ページ遷移時に画面全面の広告だったり、コンテンツの上部や下部に表示してくれたりするものでした。しかし今回利用可能になった自動広告はすべての端末に有効なんです。

当面は収入アップを見込めるかも?

グーグルさんにとってAdSenseの売上は収入の大きな柱ですよね。 そしてこれまでの20年近くでWebサイトと広告に関するビッグデータを持っています。 さらに人工知能で先頭を走る大企業ですから、広告を妙なところに貼っちゃうはずがないのです(多分)。

実際に、今回手前のブログやWEBサイトで使ってみたのですが、広告ユニットの表示回数が多くなって見積収益額も上昇傾向にあるような気がします。まだあくまでも「感覚的に」の域ですが。

ということで、

AdSenseのコードをコピー

AdSenseへ行って、

f:id:takamints:20180309090909p:plain

左上の ≡ をクリックするとメニューが開きます。

f:id:takamints:20180309091218p:plain

メニューの [広告の設定]/[自動広告] をポイントすると、自動広告の設定画面が表示されますね。

f:id:takamints:20180309091801p:plain

ここで右上の「自動広告を設定」をクリックすると、以下のように、ヘッダーに貼り付けるコードが表示されます。 下に表示されている「コードスニペットをコピー」して、HEADに貼り付けるとヨロシイ。

f:id:takamints:20180309091333p:plain

はてなブログでHEADにコードを貼り付ける

ダッシュボードの左のメニューから「設定」をクリックし、右側に表示された「詳細」タブページの真ん中から少し下辺りの 「検索エンジン最適化」というブロックに「headに要素を追加」というテキストボックスがあるでしょう。

そこの最初か最後にAdSenseの自動広告の設定でコピーしたコードをペーストすれば良い。マジこれだけです。

HEADじゃなくてもいいみたい

はてなブログではHEADに貼り付けられますが、それができないブログもあります(ココログBasicとかね)。

でも大丈夫。

AdSenseの設定画面では「HEADに貼り付ける」と指示されていますが、実際には別な場所(例えばサイドメニューのリストとか) でもかまわないようです(Chromeだけで確認しました)。

なのでHEADの内容にアクセス出来ないようなブログシステムでも、自動広告は使えるようです。

ただし、非公式な使い方ではあるので自己責任で。

どこに危機感を感じているのか?

これまで読んでいただいた方は「そんな嬉しいお話なのに何に危機感を感じているの?」と思われてるかもしれません。

それはまあ、非常にせこい話なのですが、参入障壁が下がって、みんなが使い始めたらクリック単価が下がるんじゃないの?(涙)ってことなんですね(=死活問題)。

「薦めておいて何言ってる!(書かなきゃいいのに!)」との、お叱りの言葉もなく、ご清聴ありがとうございました!

いやマジで、ゲームのルールが変わった気がするんですよねえ。

Gitでアリバイ工作するスクリプトはコチラです

f:id:takamints:20180217200222p:plain
[Defi] Master and Servant by Franck Mahon, on Flickr


あなたはとある事件の容疑者だ。 悪いことに、事件当日の居場所を証明できないでいる。

というか、ここだけの話ホントはアナタが真犯人。だからこの際アリバイ工作するしか無いようだ・・・

そこであなたは、Gitのコミット日時を書き換える(え?)・・・

(という設定で以下進行ってなんだそりゃ?)

コミット日時を偽装する

ってな時に、Gitのコミット日時を偽装して、簡単にアリバイ工作(?)できるスクリプトが、これ(↓)ですね。

git-giso

#!/bin/sh
if [ "$1" = "" ]; then
    echo "Error: datetime need to be specified"
    exit 1
fi
echo git commit --amend -C HEAD --date="$1" && \
git commit --amend -C HEAD --date="$1" && \
echo && \
echo git rebase HEAD~ --committer-date-is-author-date && \
git rebase HEAD~ --committer-date-is-author-date

このファイルに実行属性を付けてPATHの通った所へINSTALL。

実行例

実行すると以下のようになりますよ(極秘情報は伏せてある)。

$ git-giso '2018-02-17 20:26:45'
git commit --amend -C HEAD --date='2018-02-17 20:26:45'
[working-branch abcdefg] #$%S&Gys7&%$#
 Date: #$$ Feb %& $%#2#$$%&'(&%%%
 n file changed, 4 insertions(+)

git rebase HEAD~ --committer-date-is-author-date
Current branch working-branch is up to date, rebase forced.
First, rewinding head to replay your work on top of it...
Applying: %&%S$%S&&D'F/??./

それは、ヒ・ミ・ツ

理由は明かせないけれど、コミット日時を書き換えたいときがあります(よね?)。あるんです。

絡み合う2つの日時・・・

  1. Gitのコミットには author-datecommitter-dateという2つの日付がありまして、最初にコミットした時、両方同時刻に設定されます。
  2. でも、git commit --amend した時には、committer-date しか書き換わらないの・・・
  3. てことで、git commit --amend -C HEAD --date='<datetime>' として author-date を書き換える。
  4. しかし、committer-date が、その時の時刻になってしまっているので、
  5. git rebase HEAD~ --committer-date-is-author-datecommitter-dateauthor-dateに一致させるというわけです。

ふう・・・

masterブランチでやっちゃダメ

これ、amendしてrebaseするので、ワーキングブランチでやりましょう。

masterブランチでコレやって、push -f とかしちゃったら、市中引き回しの上獄門ですから気をつけて。


なんで縄文・・・

DynamoDBをSQLで操作するNodeモジュール

Amazon DynamoDBSQL的な記述言語(SQL-ish)で操作できるNodeモジュールのご紹介。

f:id:takamints:20180206230625p:plain

目次

www.npmjs.com



概要

このモジュールからはDynamoDBのテーブルをSQL的な文(SQL-ish)で操作できるステートメントを提供しています。

ステートメントを生成する関数は以下の4つ:

それぞれ、引数にSQL(によく似た)文を与えてステートメントを生成します。 各ステートメントは後からパラメータを与えて実行可能(※ただしDeleteItemStatementは現在パラメタライズが出来ません)。

このほか、ScanとQueryの結果の中の Itemsを(DynamoDBのマップ型の配列から)普通のオブジェクトの配列に変換する DynamoDbResultSet クラスgetItemsメソッドが使えます。

また、v0.9.6では、 PutItemStatement が返す DynamoDBPutItemStatementクラスsetValuesメソッドで、新たなVALUESを設定してステートメントを実行できます。

以下にScanとQueryの簡単なサンプルコードを掲載してます。 他のステートメントのサンプルやAPIの詳細はAPIリファレンスを参照してくださいね。

SQL-ish Statement クラスの使用例

実際に動作させるには、DynamoDBにstarsというテーブルがあり、HASHキーがString型のmainStar、RANGEキーがNumber型のorbitOrderとなっている必要があります。

"use strict";
const awsNodeUtil = require("aws-node-util");
const ScanStatement = awsNodeUtil.dynamodb.ScanStatement;
const QueryStatement = awsNodeUtil.dynamodb.QueryStatement;
const ResultSet = awsNodeUtil.dynamodb.ResultSet;

// Connect (change each value for your account)
awsNodeUtil.dynamodb.connect(
//    { accessKeyId: 'AKID', secretAccessKey: 'SECRET', region: 'us-west-2' }
);

// Prepare 'Scan' statement
var scanStatement = ScanStatement(
        "FROM stars WHERE name=:name");

// Prepare 'Query' statement
var queryStatement = QueryStatement(
        "SELECT mainStar, orbitOrder, name " +
        "FROM stars " +
        "WHERE mainStar=:mainStar");

// Run the statements
ScanStatement("FROM stars").run({}, (err, resp) => {
    console.log("-----------------------");
    console.log("SCAN all items of stars");
    console.log("-----------------------");
    printResult(err, resp);
    scanStatement.run({ ":name": "EARTH" }, (err, resp) => {
        console.log("--------------");
        console.log("SCAN the EARTH");
        console.log("--------------");
        printResult(err, resp);

        queryStatement.run({ ":mainStar": "EARTH" }, (err, resp) => {
            console.log("------------------------------");
            console.log("QUERY child stars of the EARTH");
            console.log("------------------------------");
            printResult(err, resp);
        });
    });
});

// Handler to print result of scan / query
function printResult(err, result) {
    if(err) {
        console.error("Error:", err.stack);
    } else {
        ResultSet.printScanResult(result);
    }
}

実行時の出力例:

$ node sample/sqlish-sample.js
-----------------------
SCAN all items of stars
-----------------------
Count: 10
ROWNUM diameter rotation role      mass      gravity density escapeVelocity name    orbitOrder mainStar
     1     3475    655.7 satellite    0.0073     1.6    3340            2.4 MOON             1 EARTH
     2     4879   1407.6 planet       0.33       3.7    5427            4.3 MERCURY          1 SUN
     3    12104  -5832.0 planet       4.87       8.9    5243           10.4 VENUS            2 SUN
     4    12756     23.9 planet       5.97       9.8    5514           11.2 EARTH            3 SUN
     5     6792     24.6 planet       0.642      3.7    3933            5.0 MARS             4 SUN
     6   142984      9.9 planet    1898.0       23.1    1326           59.5 JUPITER          5 SUN
     7   120536     10.7 planet     568.0        9.0     687           35.5 SATURN           6 SUN
     8    51118    -17.2 planet      86.8        8.7    1271           21.3 URANUS           7 SUN
     9    49528     16.1 planet     102.0       11.0    1638           23.5 NEPTUNE          8 SUN
    10     2370   -153.3 planet       0.0146     0.7    2095            1.3 PLUTO            9 SUN
ScannedCount: 10
--------------
SCAN the EARTH
--------------
Count: 10
ROWNUM diameter rotation role   mass gravity density escapeVelocity name  orbitOrder mainStar
     1    12756     23.9 planet 5.97     9.8    5514           11.2 EARTH          3 SUN
ScannedCount: 10
------------------------------
QUERY child stars of the EARTH
------------------------------
Count: 1
ROWNUM name orbitOrder mainStar
     1 MOON          1 EARTH
ScannedCount: 1

SQL-ishの構文

各Statementの構文を以下にざっくり説明します。 []は省略可能を意味します。<> は後述します。

/* Scan */
[SELECT <projection-expression>]
FROM <table-name>
[WHERE <filter-expression>]
[LIMIT <limit>]

/*Query*/
[SELECT <projection-expression>]
FROM <table-name>
WHERE <key-condition-expression>
[FILTER <filter-expression>]
[LIMIT <limit>]

/*PutItem*/
INSERT INTO <table-name> ( <attribute-list> )
VALUES ( <value-list> )
[WHERE <key-condition-expression>]

/*DeleteItem*/
DELETE FROM <table-name>
[WHERE <key-condition-expression>]

SELECT句

SELECT句には<projection-expression>にカンマ区切りで選択する属性名を指定します。 通常のSQLと違ってSELECT句は省略可能です。省略時は全属性が選択されます。 (「属性」は一般的なDBでは列、またはカラムに相当します)

FROM句

FROM句は必須です。 <table-name>に検索を行うテーブル名を指定します。JOINなどは出来ません。

WHERE句

WHERE句はScanとその他のステートメントでは意味が違います。

ScanStatementでは、フィルター条件式(<filter-expression>)を指定します。これは省略可能です。省略すると全件取得。 フィルタ条件式にはキー属性を記述できません。これが必要な場合はQueryを使用します。

他のステートメントではキーの条件式(<key-condition-expression>)を指定します。 QueryStatementでは必ず記述しなければなりません。 キーの条件式には、キー以外の属性を記述できません。 QueryStatementでキー以外の属性で絞り込みたい時はFILTER句を使用します。

その他、キーの条件式には、以下のような制限もあります。これらは全てDynamoDBのKeyConditionExpressionの制限です。

  • パーティションキーの条件は必須で、 = で一致させなくてはなりません。
  • ソートキーの条件をANDで追加できます。この条件式で使用できる比較演算子=, <, <=, >, >=, BETWEEN ~ ANDだけです。INは使用できません。関数はbegins_withだけ使用できます。
  • 詳細はQuery - Amazon DynamoDB(英文)に書いてあります。

FILTER句

FILTER句は、QueryStatementにフィルタを設定するために記述します。 省略可能。省略時はフィルタはかかりません。

ScanStatementにFILTER句は指定できません(WHERE句に指定)。

LIMIT句

LIMIT句は<limit>にScanする件数(数値)を指定します。

省略可能ですが注意が必要。

LIMIT句を省略するとScanStatementではWHERE句(フィルタ)の指定に関わらず、全件をスキャンすることになります。 QueryStatementでは必ずパーティションキーの条件が入っていますのである程度件数は絞られます。 いずれにせよ項目数の多いテーブルでLIMIT句を省略すると処理速度や料金に影響しますので注意して下さい。 これはDynamoDBの仕様です。

VALUES句

PutItemStatementのVALUES句は、( <attribute-list> ) VALUES ( <attribute-list> )という形式で、 追加・上書きする項目の属性(RDBでのカラム名に相当)と値をそれぞれカンマ区切りで並べたものです。 属性と値の数は一致しなければなりません。 各値の型は表記から自動的に判断されます。

プレースホルダーについて

DynamoDBを使う上でちょっと邪魔くさい「名前のプレースホルダー」、「値のプレースホルダー」について気にする必要はありません。 本モジュール内で構文解析時に自動的に識別して変換します。

ステートメントのパラメタライズ

上の例に示しているように、パラメータ化する箇所には半角コロン:で始まる識別子を直接記述しておけば、実行時にパラメータを与えて処理できるようになります。

DynamoDBについての基本事項

DynamoDBはNoSQL

DynamoDBはAWSAmazon Web Service ― のNoSQL型データベース。 リレーショナルではありませんので複数テーブルの突き合わせ(JOIN)とかは出来ません。

DynamoDBのScanとQueryの違いについて

ScanもQueryもDynamoDBのテーブルから項目を読み込む機能ですが、読み込み方に違いがあります。

Scanはキーによる絞り込みが出来なくて、項目の並び順に順次読み込み(=スキャン)する感じ。 Queryはスキャンの前にキーの条件で絞り込めます。

どちらもスキャンしたあとに「フィルター」をかけられ、スキャンする項目数を指定できます。 また、続きから読むという操作も可能です。

あとがき

DQLというPython製ですが似たコンセプトのモジュールがあるらしいですね。 使ったことがないのでよくわからないですが、シェルから実行できる対話式のクライアントという感じでしょうか。

当npmをリリースした後「似たようなのって既にあるんじゃないの?」って検索して知ったのでワタシは無罪。 しかし、こちらが後発なのは明らかなので今後構文的にDQLに寄せていくのもありかなと思っています。BNFもドキュメントで規定されているし。

package-lock.jsonの潜在的セキュリティ脆弱性を解消しました

f:id:takamints:20180112204146p:plain
photo credit: wuestenigel blue padlock via photopin (license)

昨年12月末、GitHubに置いてる自作npmリポジトリに「潜在的なセキュリティの脆弱性がありますよ」ってメッセージが表示されるようになって、 「公開しているnpmのリポジトリに、こんなの表示されたらかなわんなあ」と思いながらも、 なんか怖いし対処法も分からんし、2週間ぐらいは見て見ぬふりしていましたが、この度正しく対処してメデタク解消致しました。

結果的には大したことはしていませんが記録として書いておきます。

関連する最新記事(↓): なんとワンクリックで対処できるようになってます。 takamints.hatenablog.jp

潜在的セキュリティ脆弱性があるらしい

何やら怪しげなメッセージは、コチラ(↓)です。

f:id:takamints:20180110111240p:plain

”potential security vulnerabilities”が「潜在的セキュリティ脆弱性」。

文章部分を、ちゃんと翻訳すると以下のようになりますね。

We found potential security vulnerabilities in your dependencies. Some of the dependencies defined in your package-lock.json have known security vulnerabilities and should be updated. Only the owner of this repository can see this message.


「わたしたちは、あなたの依存パッケージに潜在的なセキュリティ脆弱性の可能性を見つけました。 あなたの package-lock.json 内の依存パッケージのいくつかは、既知のセキュリティ脆弱性があり、これらは更新されるべきです。 リポジトリのオーナーだけがこのメッセージを見ることができます。

最後の一文でホッとしましたが、どうすりゃいいかはわからない。 とりあえず「Review Vulnerable dependencies」ボタンを押せば、以下(↓)の詳細が表示されます。

f:id:takamints:20180110113541p:plain

このページ、昨年末にGitHubに追加された機能ですね。「早速動いているんだな」と当たり前のことに感心しました。

それはさておき、どうやら marked0.3.6脆弱性があるようです。 そして、小さなドロップダウンを開くと、修正された 0.3.9 以降に更新すればいいよと言ってるようだ。

ただし自作パッケージではmarkedを使用していません。依存パッケージのどれかが依存しているのでしょう。

package-lock.jsonを編集するのはよろしくないかも

最初は単純に package-lock.json に記述されてる marked のバージョンを 0.3.9に書き換えればよいと思いましたが、そうでもなさそう。 セマンティックバージョニングを厳格に適用するなら、以下の理由によって正しく動作する保証がありません。

  • marked に依存しているパッケージは marked@0.3.9 で動かされた実績がありません(パッチレベルのバージョンアップですので実際には動くかもしれませんが、それでも確証はありません)。
  • markedのメジャーバージョンは0(=正式リリースされていない状態)なので互換性が保証されない可能性があります。
  • package-lock.json は古いバージョンに固定したい(勝手に新しいバージョンが使われないようにする)時に使うものだと思ってます(あってますかね?)ので、新しいバージョンに固定するのは気持ち悪い。

ということから、直接 marked に依存しているパッケージを更新し、marked@0.3.9 以上に依存するのが安全ぽいという結論に。

どいつが依存しているんだ?

しかし、package-lock.json を開いても、どのパッケージがmarkedに依存しているかという情報はないのですね。

npmの依存関係は npm ls で全部表示できるのですが、恥ずかしながらこの時スッカリ忘れていまして、findとgrepで node_modules以下にインストールされた全パッケージのpackage.jsonからmarkedをゴリゴリ検索しちゃいました。これ結構時間がかかりますので良い子は真似しない。npm ls はnode_module以下を見ずに依存ツリーを表示してくれるのでこちらが標準。

$ find . -name 'package.json' -exec egrep -H '^\s*"marked"' {} \;
./express/package.json:    "marked": "0.3.6",
./jsdoc/package.json:    "marked": "~0.3.6",
./marked/package.json:    "marked": "./bin/marked"

はい出ました。expressjsdocでした(最後の行はmarked自身)。

あとは更新してプッシュ

どちらも、npmで確認すると新バージョンが出ておりまして、それぞれ修正済みのmarkedへ依存していました。 そこで、この2つのパッケージを最新版に更新し、package-lock.json も更新し、 GitHub へアップすれば一件落着。

Push後すぐにはメッセージは消えませんでしたが、少なくとも1時間後には消えていました。

github.com

まとめ

  • ちょっと邪魔くさかったけど、定期的に npm-check-updates してればこういう目に合わなくてよいのかも知れないなと。
  • npm 5で追加されたpackage-lock.jsonについて、きちんと理解する必要があると痛感しました。

www.npmjs.com