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

Vue.js初心者お勉強-その1-

前回までのおさらい

firebase で テンプレ環境は展開できた。この後は、firebaseでさくっとvue.jsで作成したフロントエンドアプリを公開したいが、その前に少しくらいvue.jsをカスタマイズできるようになっておくべきと思ったので、vue.jsを勉強。なお、vue.jsを勉強した後のfirebase + vue.jsでググると山ほど記事が出てくるので、写経すればそんなに難しくない、と予想します。

触ってみる

こちらの記事が簡単そうだったので、やってみます。

vue-cliのインストール

vue-cliは雛形からプロジェクトを作成してくれる公式ツールです。よくある対話型で答えていけばうまい事やってくれるやつ。npm initとか、firebase initとかみたいな。

npm install -g vue-cli

vue-cliによるvueプロジェクト作成

以下のコマンドでプロジェクトを作成します。

vue init [テンプレート名] [プロジェクト名]

テンプレート名は写経してwebpackを指定。他にもいろいろあって、メリットもさまざまなのでしょうか…?

PS C:\first_vuejs> vue init webpack first_vuejs

? Project name first_vuejs
? Project description A Vue.js project
? Author teraco
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? Yes
? Pick an ESLint preset Airbnb
? Set up unit tests Yes
? Pick a test runner karma
? Setup e2e tests with Nightwatch? Yes
? Should we run `npm install` for you after the project has been created? (recommended) npm

などと入力するとガリガリとプロジェクトを作成していき

※ 最近のvueでは、vue create [プロジェクト名]でプロジェクトを作成するのが流行りの様子。

To get started:

  cd first_vuejs
  npm run dev

と指示されるので実行。

> webpack-dev-server --inline --progress --config build/webpack.dev.conf.js

 13% building modules 30/33 modules 3 active ...t_vuejs\src\components\HelloWorld.vue{ parser: "babylon" } is deprecated; we now treat it as { parser: "babel" }.
 95% emitting

 DONE  Compiled successfully in 16857ms                                                                         22:54:14

 I  Your application is running here: http://localhost:8080

めでたくHello worldに成功したようです。

image.png

さて、中身を見てみるとindex.htmlが不思議…。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>first_vuejs</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

index.htmlからjsなどへのリンクが張っていないが、Webpackを使って統合されるらしいです。
Vue.js初心者向け:インラインテンプレートから単一ファイルコンポーネントの使い方まで - Qiita

それではチュートリアル通りに中身をいじっていきます。

タイトル変更 & vueプロジェクトの構成

app.vue
<template>
  <div id="app">
    <img src="./assets/logo.png">
    <h1>Todo Management.</h1>
    <hr />
    <router-view/>
  </div>
</template>

index.htmlから呼ばれるapp.vueを編集し、H1を追加します。これで全てのページに反映されます。…とこの後のステップを言葉で書くのがつらいので、図にしてみました。
image.png

ちょいと拡大してみてほしいのですが、

  1. app.vueから個別ページ用の表示をスイッチする"view"機能を呼び出し。これをvueでは"ルーター"と呼ぶ。
  2. "ルーター"の実体はsrc/router/index.js。こいつで、どのパスにアクセスしたら、どのページを表示するかを決定する。ここでは "/" にアクセスしたら、HelloWorld.vueを表示、/hogeにアクセスしたらhoge.vueを表示としている。
  3. あとは、HelloWorld.vueとかhoge.vueを書けば、個別ページが書き変わる。

ここまでがvue-cliで始めるVue.jsチュートリアル (1) - Qiitaの内容です。


以下、vue-cliで始めるVue.jsチュートリアル (2) - Qiitaの内容。これも写経なのだが、画像で説明。

前述のHelloWorld.vueが個別ページの表示を決定するファイルだった。これを編集してチュートリアルを続ける。このxxxx.vueはの間にページの実体を書いていく形式なので、チュートリアル(1)で作成したの中身を削除し、チュートリアル(2)を進める。

リストの表示(ループ)

前述した通り、間にHTML(ぽいもの)を書けばページが表示できるがそれだと拡張性がないので、v-forを使って表示する。

image.png

v-forは公式ページでリストレンダリング — Vue.jsとして説明されているディレクティブである。ディレクティブとはテンプレート構文 — Vue.jsで説明されている通り、Vue.jsの世界でv-から始まる特別な属性、と理解すればよいみたい。

Todoの追加

これもVue.jsに用意されているディレクティブを利用してやってみる。

image.png

中のv-on:clickされたらaddTodo()メソッドを実行し、addTodoメソッドの内容は下部の赤枠に書いてある。内容はnewTodoに値を追加する事。

Todoの削除

Todoの削除とやっている事はあまり変わらず。v-onディレクティブを利用して、メソッドを呼び出して動作させる。

image.png

v-onの文字がなくなって@になっているのは、vue.jsの省略記法である。詳しくは以下ページを参照。

テンプレート構文 — Vue.js

Todoの編集 / 完了済みTodoへのclass付与

前者はv-ifディレクティブ、v-elseディレクティブを使って実装。後者はv-bindディレクティブを使って実装。画像省略。

GitHub Pagesでの配信

チュートリアルの通りにやったらできました。GitHub Pages初めて使ったけど、こりゃ簡単でいいですね。

以上です。


今後の勉強予定メモ

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

RabbitMQを使ってみる by JavaScript

初めまして、Guuuuuchanと申します。
初めての投稿です。

はじめに

最近、業務でRabbitMQを使いました。
初めて実装した時はドキュメントを読んでもどういうものかよくわからず、まずは動かして理解しようかと思いました。

備忘録的なところが多いので、多少説明が足りなくて申し訳ないかもしれないです。
その時はコメントで補足などもらえたら助かります。

また、僕の場合はJavaScript(Node.js)での実装になるので、JavaでRabbitMQ使いたい方はこちらの方が書いた素晴らしい記事が参考になるかと思います。

AMQPとは?

この辺はWikiとか公式を読んでもらった方が正確です。

AMQPは「Advanced Message Queuing Protocol」の略です。

プラットフォームに依存しないメッセージングミドルウェアです。メッセージをキューに入れて、非同期で取り出すといった単純なものです。

公式サイトには「To become the standard protocol for interoperability between all messaging middleware(すべてのメッセージングミドルウェア間の相互運用性の標準プロトコルになるため)」と書かれています。

  • 特徴
    • オープンスタンダードなアプリケーション層のためのプロトコル
    • メッセージ指向
    • キューイング
    • ルーティング
    • セキュア
    • 堅牢性

RabbitMQってなに?

RabbitMQはAMQPを実装したオープンソースのミドルウェアです。
似たようなミドルウェアとしてActiveMAやIBM MQ Lightなどがあります。

Erlang上で動いており、クラスタリングとフェイルオーバーを実現するためにOpen Telecom Platformフレームワーク上で構築されています。耐久性やスケーリングを考慮して設計されているようです。

クライアントアプリは以下の言語で動きます。

  • Python
  • Java
  • Ruby
  • PHP
  • C#
  • JavaScript
  • Go
  • Elixir
  • Objective-C
  • Swift
  • Spring AMQP

なぜRabbitMQを使う必要があるのか?

結論から言うと
1. スケーリングできる
1. 耐障害性がある
1. メンテナンスがしやすい

例えば大量のデータをバッチ実行したい場合、途中で失敗した場合最初からやり直す必要があります。
RabbitMQを使えば、バッチの引数に与えるデータをRabbitMQのキューに入れておくことで、バッチが途中で終了した場合でも失敗した箇所から実行できます。
そして、データが大量にある場合、キューを取り出すジョブを増やすことでスケールすることが可能です。
また、データをキューに入れておくことで、データを入れる側と取り出す側で任意のタイミングで処理を実行することができるので、どちらがメンテナンス状態になってもさほど大きな問題にはなりません。

準備

僕の環境では以下のツールが入っているので、もし動かしたい場合は先に以下のツールを先に入れておいてください。

  • Docker
  • Node.js
  • yarn

まずはRabbitMQサーバを立てよう!

DockerでコンテナにRabbitMQサーバを立てます。

まず、適当なディレクトリを作ります。

mkdir sample-rabbitmq-server
cd sample-rabbitmq-server

docker-compose.ymlを作成し、コンテナの内容を記載します。

touch docker-compose.yml

docker-composeの内容は以下のように記載します。

version: '3'

services:
  my-queue:
    container_name: rabbitmq
    image: rabbitmq:3.7.17-management
    ports:
      - '5672:5672'
      - '15672:15672'
    volumes:
      - rabbitmq-data:/var/lib/rabbitmq

volumes:
  rabbitmq-data:
docker-compose up -d

ブラウザを開き、http://localhost:15672にアクセスしてみましょう。

Screen Shot 2019-08-01 at 14.17.31.png

guest/guestでログインできます。

Screen Shot 2019-08-01 at 14.17.39.png

ログイン後はこんな画面になるはず

Screen Shot 2019-08-01 at 14.16.52.png

とりあえず、サーバのインストールは以上です。

また、rabbitmqのバージョンを投稿時の最新で記載していますが、こちらのページで最新バージョンを知ることができます。
RabbitMQ Changelog — RabbitMQ

RabbitMQのクライアントを使ってメッセージを送ってみよう

今回の投稿ではJavaScript(Node.js)で実装してみます。

まず、プロジェクトを作ります。yarn initでNodeのプロジェクトを作ります。successが出てくればOKです。

mkdir rabbitmq-client
cd rabbitmq-client
yarn init // 連打でOK

こんなメッセージが出てくるはず
yarn init v1.16.0
question name (rabbitmq-client):
question version (1.0.0):
question description:
question entry point (index.js):
question repository url:
question author:
question license (MIT):
question private:
success Saved package.json
✨  Done in 4.98s.

次に、RabbitMQのクライアントを入れましょう!

yarn add amqplib

メッセージを送るプログラムを作ります。

vim send.js

const amqp = require('amqplib/callback_api');

amqp.connect('amqp://localhost', (error0, connection) => {
    if (error0) throw error0;

    connection.createChannel((error1, channel) => {
        if (error1) throw error1;

        const queue = 'hello';
        const msg = 'Hello world';

        channel.assertQueue(queue, {
            durable: false
        });
        channel.sendToQueue(queue, Buffer.from(msg));

        console.log(" Sent message :", msg);
    });
    setTimeout(() => {
        connection.close();
        process.exit(0)
    }, 500);
});

保存したら、実行してメッセージを送ります。

node send.js

実行後、コンソールにメッセージが出るはずです。

$ node send.js
 Sent message : Hello world

メッセージが本当に送れているかWebUIで確認してみましょう。

Screen Shot 2019-08-01 at 14.16.13.png

次はメッセージを受信してみよう

メッセージを受信するプログラムを作ります。

vim receive.js
var amqp = require('amqplib/callback_api');

amqp.connect('amqp://localhost', function(error0, connection) {
    if (error0) {
        throw error0;
    }
    connection.createChannel(function(error1, channel) {
        if (error1) {
            throw error1;
        }

        var queue = 'hello';

        channel.assertQueue(queue, {
            durable: false
        });

        console.log(" [*] Waiting for messages in %s. To exit press CTRL+C", queue);

        channel.consume(queue, function(msg) {
            console.log(" [x] Received %s", msg.content.toString());
        }, {
            noAck: true
        });
    });
});

実行してみます。

$ node receive.js

こんなメッセージが出ればOKです。

[*] Waiting for messages in hello. To exit press CTRL+C
 [x] Received Hello world

Ctrl + Cを押すまで、待機状態になります。
別のコンソールで、send.jsを実行すると非同期でreceive.jsに受信されます。

その他

receive.jsを動かさない状態で、send.jsを何度か実行するとどんどんQueueにメッセージが溜まっていきます。

その時、receive.jsを起動すると、一気にキューを受け取ります。

また、複数のコンソールでreceive.jsを起動すると、ランダム?でどれかのreceive.jsに受信されます。キューからメッセージを受け取る時は一度しか取れないですからです。これは設定で変更することができます。

最後に

最近のフロントエンドでは、非同期処理が当たり前のように使われるようになってきました。
もしかしたら今後、RabbitMQを使うシーンがまたあるかもしれないです。

また、別の投稿でRabbitMQの使い方を紹介しようと思っています。

参考文献

業務で使う場合はやはり公式ドキュメントが一番よいと思います。
Messaging that just works — RabbitMQ

RabbitMQのチュートリアルがあるのでこちらを参考にしてください
Getting started with RabbitMQ — RabbitMQ

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

Node JSのコールバックパターン

継続渡しスタイル(continuation-passing style : CPS)

JavaScriptにおいてコールバック関数とは、ある関数を呼び出す時に、引数として指定する関数で、FuncAの処理が完了した時にFuncAの結果を通知するために起動される関数のことを指します。

同期的継続渡しスタイル

test.js
function add(a, b, callback) {
  callback(a + b)
}

console.log('before')
add(1, 2, result => console.log('Result : ' + result))
console.log('after')

結果

example.sh
$ node test.js
before
Result : 3
after

非同期CPS

test.js
function addAsync(a, b, callback) {
  setTimeout(() => callback(a + b), 100)
}

console.log('before')
add(1, 2, result => console.log('Result : ' + result))
console.log('after')

結果

example.sh
$ node test.js
before
after
Result : 3

継続渡しではないコールバック

test.js
const result = [1, 5, 7].map(element => element - 1)
console.log(result) // [0, 4, 6]

ちなみに以下のことはダイレクトスタイル(Direct Style:DS)と呼びます。

example.js
function add(a, b) {
  return a + b
}

console.log(add(1,2)) // 3

同期処理か非同期処理か

どっちでもいいですが、まず避けなければならないのは「一貫性がないAPI」です。

同期と非同期の混在

もっとも危険なのは、ある条件には同期処理、ある条件には非同期処理を行う関数です。
以下のコードは一貫性がないコードの例です。

test.js
const fs = require('fs')
const cache = {}

function inconsistentRead(filename, callback) {
  if(cache[filename]) {
     callback(cache[filename]) // cacheにデータがある場合、同期的に実行される。
  } else {
     // cacheにデータがない場合、ひい同期関数fs.readFile()を呼び出す。
     fs.readFile(filename, 'utf8', (err, data) => {
       cache[filename] = data
       callback(data)
     }
  }
}

混在がもたらす問題

test.js
const fs = require('fs')
const cache = {}

function inconsistentRead(filename, callback) {
  if(cache[filename]) {
     callback(cache[filename]) // cacheにデータがある場合、同期的に実行される。
  } else {
     // cacheにデータがない場合、ひい同期関数fs.readFile()を呼び出す。
     fs.readFile(filename, 'utf8', (err, data) => {
       cache[filename] = data
       callback(data)
     })
  }
}

function createFileReader(filename) {
  const listeners = []
  inconsistentRead(filename, value => {
    listeners.forEach(listener => listener(value))
  })

  return {
    onDataReady: listener => listeners.push(listener)
  }
}

const reader1 = createFileReader('data.txt')
reader1.onDataReady(data => {
  console.log('First call data: ' + data)
  // しばらくしてから同じファイルを呼び出す
  const reader2 = createFileReader('data.txt')
  reader2.onDataReady(data => {
    console.log('Second call data: ' + data)
  })
})

結果

example.sh
$ node test.js
First call data: some data

解決策1同期APIの利用

同期関数を使えば解決できます。

test.js
const fs = require('fs')
const cache = {}
function consistentReadSync(filename) {
  if (cache[filename]) {
    return cache[filename]
  } else {
    cache[filename] = fs.readFileSync(filename, 'utf8') // 同期関数使用
    return cache[filename]
  }
}

しかし、以下の留意点があります。
・ある機能に関して常に同期バージョウンが用意されているとは限らない
・他のリクエストは処理待ちとなるため、全体的にパフォーマンスが落ちる。

解決策2遅延実行

同期的なコールバックが「将来」起動されるようにスケジュールする。

test.js
const fs = require('fs')
const cache = {}
function consistentReadAsync(filename) {
  if (cache[filename]) {
    process.nextTick(() => callback(cache[filename]))
  } else {
     fs.readFile(filename, 'utf8', (err, data) => {
       cache[filename] = data
       callback(data)
     }
  }
}

Node.jsのコールバック

エラーの伝播

test.js
const fs = require('fs')
function readJSON(filename, callback) {
  fs.readFile(filename, 'utf8', (err, data) => {
    let parsed
    if (err) {
      return callback(err)
    }

    try {
      parsed = JSON.parse(data)
    } catch (err) {
      return callback(err)
    }
    callback(null, parsed)
  })
}

キャッチされない例外

test.js
const fs = require('fs')
function readJSONThrows(filename, callback) {
  fs.readFile(filename, 'utf8', (err, data) => {
    let parsed
    if (err) {
      return callback(err)
    }
    callback(null, JSON.parse(data))
  })
}

try {
  readJSONThrows('nonjson.txt', err => {
    if (err) { console.log(err) } else { JSON.stringify(json) }
  })
} catch(err) {
   console.log('こうしてもキャッチはできません。')
}

上記の場合、キャッチされません。なぜなら、readJSONThrowsを呼び出すスタックとコールバックを呼び出すスタックがことなるからです。
これは下記のようにコードを作ったらキャッチされます。

test.js
readJSONThrows('nonjson.txt', err => {
  if (err) { console.log(err) } else { JSON.stringify(json) }
})

process.on('uncaughtException', (err) => {
  console.error('ここでキャッチ')
  process.exit(1) // エラーコード1で終了。これがないと実行を継続する。
})

参考文献
Node.jsデザインパターン 第2版 - Mario Casciaro (著), Luciano Mammino (著), 武舎 広幸 (翻訳), 阿部 和也 (翻訳)

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

Webpack でビルドが稀に落ちる現象の回避

こういうやつ。

image.png

V8 がメモリ不足か何かで落ちる現象みたいです。

Ineffective mark-compacts near heap limit Allocation failed - Javascript heap out of memory

これを回避するには --max_old_space_size={MB} を Node.js の引数として設定してあげればいいらしい。

npm scripts で Webpcak を使ってる場合はこんな感じ。

{
  "dev": "cross-env NODE_OPTIONS=--max_old_space_size=2048 webpack"
  "dev2": "node --max_old_space_size=2048 node_modules/webpack/bin/webpack.js"
}

参考:

ただ記載されているのが --max-old-space-size だったり --max_old_space_size だったりして、どっちが正しいのか分からないしV8も意図的に落とせないので効果が確認しづらい。Node.js の --help を見ても両方とも載ってないので、効いてるのかどうか分からない…。

ちょっと古いけど、詳細な設定はこちらの記事を参考にするとよさそう。
2016年版 Node.jsで幸せになれる10の習慣 - Qiita

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

ESLint v6.2.0

v6.1.0 | 次 (2019/08/31 JST)

ESLint 6.2.0 がリリースされました。

お盆休み中に ESTree 仕様が更新されたので、BigInt と Dynamic Imports 構文をサポートしました。

既知の問題:

質問やバグ報告等ありましたら、お気軽にこちらまでお寄せください。

? 日本語 Issue 管理リポジトリ
? 日本語サポート チャット
? 本家リポジトリ
? 本家サポート チャット

? 本体への機能追加

BigInt と Dynamic Imports をサポートしました。

これらを利用するには、env.es2020 設定と、(デフォルトのパーサーでは) parserOptions.ecmaVersion 設定を指定します。

.eslintrc.json
{
    "parserOptions": {
        "ecmaVersion": 2020
    },
    "env": {
        "es2020": true
    }
}
  • parserOptions.ecmaVersion 設定により、新しい構文 (import("source")100n) が有効になります。
  • env.es2020 設定により、新しいグローバル変数 (BigInt, BigInt64Array, BigUint64Array) が有効になります。

設定ファイルに noInlineConfig プロパティが追加されました。

? RFC 22, #12091

.eslintrc.json
{
    "noInlineConfig": true
}

この設定は --no-inline-config CLI オプションとほぼ同等です。今まで CLI でしか指定できなかったものが設定ファイルでも指定できるようになりました。

? 新しいルール

function-call-argument-newline

関数呼び出しの各実引数の間に改行を入れるかどうかを矯正するスタイル ルールが追加されました。

/* eslint function-call-argument-newline: [error, consistent] */

//✘ BAD
foo(a, b,
    c);

//✔ GOOD
foo(a, b, c);
foo(
    a,
    b,
    c
);

Online Demo

? オプションが追加されたルール

特になし。

✒️ eslint --fix をサポートしたルール

特になし。

⚠️ 非推奨になったルール

特になし。

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

Macでnodenvで管理しているnpmで入れたモジュールにパスを通す

この記事を書いたきっかけ:

Node.jsをnodebrewで管理していたのをやめ、nodenvでインストールし直したが、npmでグローバルインストールしたモジュールにアクセスできなくて困ったから

参考: nodebrew管理からnodenv管理への移行ははこちらを参考に行いました

注意:上記記事ではanyenvではなく、git経由でnodenvがクローンされています。anyenv経由でnodenvをインストールする方法も調べると出てきます。

前提

  • Node.jsをanyenvのnodenvで管理している
    • nodenvのバージョン: 1.1.2-1-g18489d7
    • Node.jsのバージョン: 9.11.1
    • npmのバージョン: 5.6.0

実際の手順

作業の順番に沿って説明します。

npmがnodenvで管理されたNode.jsのものであることを確認する

nodenvでのNode.jsのインストールは完了していると考えます。
Node.jsをインストールした際に自動的にnpmもインストールされています。

npmがnodenvで管理されたNode.jsのものであることを確認します↓

$ which npm
/Users/{your_user_name}/.anyenv/envs/nodenv/shims/npm

/usr/local/binなどが表示された場合、nodebrewなどを利用してインストールされていると思われます。

npmのパスが通らない場合

.bash_profileに以下の記述を追加します
zshを使用している場合は書き込み先を .zshrcにするなど、適宜読み替えてください。

  • 直接編集する
bash_profile
export PATH="$HOME/.anyenv/envs/nodenv/bin:$PATH"
  • echoする
$ echo 'export PATH="$HOME/.nodenv/bin:$PATH"' >> ~/.bash_profile
  • 更新する
$ source ~/.bash_profile

では、このnodenv配下のnpmでモジュールをグローバルインストールします。

どのNode.jsのnpmか確認する

npmでグローバルインストールする場合は、nodenvでグローバルに設定したNode.jsのnpmを使うほうがいいと思います。nodenvで複数の環境を管理している場合は特に注意です。

  • nodenvでNode.jsのバージョン管理をしているか確認する
$ nodenv versions
8.11.1
* 9.11.1 (set by /Users/{your_user_name}/.anyenv/envs/nodenv/version)

ローカルバージョンを参照している場合、参照先のファイルが $ nodenv local {バージョン番号}実行時に作成されたファイル .node_versionになります。

$ nodenv versions
* 8.11.1 (set by /{where_your_locally_set_node_is}/.node-version)
9.11.1

グローバルバージョンが設定されていない場合

  • Node.jsにグローバルバージョンを設定する
$ nodenv global {バージョン番号}

npmでモジュールをグローバルインストールする

今回は例として aws-cdkというモジュールをインストールしようとしていますが、適宜読み替えてください。

  • npmで aws-cdkをグローバルインストールする
$ npm install -g aws-cdk
/Users/{your_user_name}/.anyenv/envs/nodenv/versions/9.11.1/bin/cdk -> /Users/{your_user_name}/.anyenv/envs/nodenv/versions/9.11.1/lib/node_modules/aws-cdk/bin/cdk
+ aws-cdk@1.4.0
updated 1 package in 10s

インストールできたっぽいです。

モジュールのコマンドを確認する

$ cdk
-bash: cdk: command not found
# そんなコマンドねえよと怒られます

$ which cdk
# 反応なし

はい、通っていません。

先ほどnpmインストールした時に

/Users/{your_user_name}/.anyenv/envs/nodenv/versions/9.11.1/bin/cdk -> /Users/{your_user_name}/.anyenv/envs/nodenv/versions/9.11.1/lib/node_modules/aws-cdk/bin/cdk

とありましたので、このディレクトリに向かってパスを通しました。

  • 直接編集する
.bash_profile
export PATH="$HOME/.anyenv/envs/nodenv/versions/*/bin:$PATH"
  • echoする
$ echo 'export PATH="$HOME/.anyenv/envs/nodenv/versions/*/bin:$PATH"' >> ~/.bash_profile
  • 更新する
$ source ~/.bash_profile

今度こそパスが通っているか確認します。

コマンドが通っているか確認します。

$ cdk
Usage: cdk -a <cdk-app> COMMAND
# (略)

$ which cdk
/Users/{your_user_name}/.anyenv/envs/nodenv/shims/cdk

通りました!

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