Cloud9 で始めるAngular2 開発!

Cloud9 を使って angular2 の開発を始めてみよう。

すんなり行くはずだったけど、ng serve してもうまく外部アクセスできなかった。
いろいろ迷走するなか、うまくいく手順が分かったので記載しておきます。

Cloud9 環境を用意する。

Cloud9 の環境を用意しよう。

環境はBlank (Ubuntu)を選択してワークスペースを作成すると良い。
こういう使い捨ての環境が簡単につくれるのは本当にありがたい。

nodejsの更新

ワークスペースが準備できたら、早速必要なものをインストール。

すでに、初期段階でnvm (Node Version Manager) がインストールされている。
しかし、デフォルトのNodeバージョンは古い。

$ node --version
v4.6.1

Angular2 は node6以降でないと動作しないので、バージョンアップしておく必要がある。
nvmを使えば、最新node のインストールも簡単だ。

-- 追記 --

$ node --version
v6.11.2

2017年12月現在であれば、
デフォルトで入っているNodeバージョンは6になっているみたいですね。
なので、nodejsの更新はしなくてもOKです。

nvm の使い方

nvm help

Usage:
  nvm help                                  Show this message
  nvm --version                             Print out the latest released version of nvm
  nvm install [-s] <version>                Download and install a <version>, [-s] from source. Uses .nvmrc if available
    --reinstall-packages-from=<version>     When installing, reinstall packages installed in <node|iojs|node version number>
  nvm uninstall <version>                   Uninstall a version
  nvm use [--silent] <version>              Modify PATH to use <version>. Uses .nvmrc if available
  nvm exec [--silent] <version> [<command>] Run <command> on <version>. Uses .nvmrc if available
  nvm run [--silent] <version> [<args>]     Run `node` on <version> with <args> as arguments. Uses .nvmrc if available
  nvm current                               Display currently activated version
  nvm ls                                    List installed versions
  nvm ls <version>                          List versions matching a given description
  nvm ls-remote                             List remote versions available for install
  nvm version <version>                     Resolve the given description to a single local version
  nvm version-remote <version>              Resolve the given description to a single remote version
  nvm deactivate                            Undo effects of `nvm` on current shell
  nvm alias [<pattern>]                     Show all aliases beginning with <pattern>
  nvm alias <name> <version>                Set an alias named <name> pointing to <version>
  nvm unalias <name>                        Deletes the alias named <name>
  nvm reinstall-packages <version>          Reinstall global `npm` packages contained in <version> to current version
  nvm unload                                Unload `nvm` from shell
  nvm which [<version>]                     Display path to installed node version. Uses .nvmrc if available

最新の安定版をインストール

# stableバージョンをインストール
nvm install stable

# Shellを起動し直すと、また古い方のNodeが使用されるので、
# デフォルトNodeを設定しておく。
nvm alias default stable
Downloading https://nodejs.org/dist/v7.10.0/node-v7.10.0-linux-x64.tar.xz...
######################################################################## 100.0%
Now using node v7.10.0 (npm v4.2.0)

default -> stable (-> v7.10.0)

Nodeのバージョンにあわせて、npmのバージョンも更新されている。

Angular-CLI

Angular2 プロジェクトを作成するなら、
CLI からプロジェクトのテンプレート作成するのがよい。

前回の記事: Angular2で始めるフロントエンド開発

angular-cli のインストール

npm install -g @angular/cli

ng コマンドが使えるようになっている。

プロジェクト作成

ngコマンドを使ってプロジェクトを作成

ng new MyApp
Successfully initialized git.
Installing packages for tooling via npm.

のあと、しばらく止まったように見えるが、
npm install が走っているのでしばらく待ちましょう。

完了すると、下記のようにcreatedと出力されるぞ。

Installed packages for tooling via npm.
Project 'MyApp' successfully created.

実行してみる。

本来なら、以下のコマンドで終わりかと思っていたが、
起動はするもののCloud9のPreviewアドレスからアクセスできない。。

npm run start
> my-app@0.0.0 start /home/ubuntu/workspace/MyApp
> ng serve

** NG Live Development Server is listening on localhost:8080, open your browser on http://localhost:8080 **
Hash: 398a066707b4bb1df2d0
Time: 17738ms
chunk    {0} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 157 kB {4} [initial] [rendered]
chunk    {1} main.bundle.js, main.bundle.js.map (main) 3.63 kB {3} [initial] [rendered]
chunk    {2} styles.bundle.js, styles.bundle.js.map (styles) 10.5 kB {4} [initial] [rendered]
chunk    {3} vendor.bundle.js, vendor.bundle.js.map (vendor) 2.4 MB [initial] [rendered]
chunk    {4} inline.bundle.js, inline.bundle.js.map (inline) 0 bytes [entry] [rendered]
webpack: Compiled successfully.

curlでローカルからアクセス curl localhost:8080 してみると、
正常にレスポンスが返ってくるので、外部からアクセスできない模様。

--host=0.0.0.0 を付けて起動すれば良いという記事も見つけたが、
今度は Invalid Host Header... というエラーが出てしまったり・・・

解決方法

参考URL

いろいろ、調べてみたが、
対応方法は以下の3つのどれかを行えば良さそう。

-- 追記 --

最後の方に、追記いたしました。
ng serve に --public-host オプションを指定して実行する事ができますので、
これらの解決方法は不要となりました。

解決法1 Server.js を、書き換える。

node_modules/webpack-dev-server/lib/Server.js のcheckHost関数で
return trueを返すようにするというもの。
一番手っ取り早いが、ライブラリを直接書き換えるので、何か無理矢理感が否めない。

node_modules/webpack-dev-server/lib/Server.js

Server.prototype.checkHost = function(headers) {
    // allow user to opt-out this security check, at own risk
    if(this.disableHostCheck) return true;

    // get the Host header and extract hostname
    // we don't care about port not matching
    const hostHeader = headers.host;
    if(!hostHeader) return false;
    const idx = hostHeader.indexOf(":");
    const hostname = idx >= 0 ? hostHeader.substr(0, idx) : hostHeader;

    // always allow localhost host, for convience
    if(hostname === "127.0.0.1" || hostname === "localhost") return true;

    // allow hostname of listening adress
    if(hostname === this.listenHostname) return true;

    // also allow public hostname if provided
    if(typeof this.publicHost === "string") {
            const idxPublic = this.publicHost.indexOf(":");
            const publicHostname = idxPublic >= 0 ? this.publicHost.substr(0, idxPublic) : this.publicHost;
            if(hostname === publicHostname) return true;
    }

    // disallow
    return false;
}

解決法2 disableHostCheck: true に設定する。

webpack.config.js で、disableHostCheck: true という設定をする。

こっちは試してないが、
解決法1と同じで、Server::checkHost 関数が無条件でtrueを返すようになる。

解決法3 --public オプションでホスト名をちゃんと指定する。

正しいpublicホストを指定してやる。

ng serve によるサーバー起動では、publicホストの指定ができないので、以下の手順が必要。

# ng server コマンドではなく、webpackコマンドを使うように変更する。
ng eject

# package.json が更新されるので、再度インストール。
npm install
==========================================================================================
Ejection was successful.

To run your builds, you now need to do the following commands:
   - "npm run build" to build.
   - "npm run test" to run unit tests.
   - "npm start" to serve the app using webpack-dev-server.
   - "npm run e2e" to run protractor.

Running the equivalent CLI commands will result in an error.

==========================================================================================
Some packages were added. Please run "npm install".

webpack.config.js も生成される。

package.json を編集する。
--public で指定しているホストは、自身のCloud9のホスト名を指定する。

package.json

@@ -4,7 +4,7 @@
   "scripts": {
     "ng": "ng",
-    "start": "webpack-dev-server --port=4200",
+    "start": "webpack-dev-server --port=8080 --host=0.0.0.0 --public=angular2-workspace-tyabuta.c9users.io",
     "build": "webpack",
     "test": "karma start ./karma.conf.js",

おしまい

これでCloud9でAngular2 開発ができるぞ!!

npm run start
> my-app@0.0.0 start /home/ubuntu/workspace/MyApp
> webpack-dev-server --port=8080 --host=0.0.0.0 --public=angular2-workspace-tyabuta.c9users.io


 10% building modules 3/3 modules 0 activeProject is running at http://angular2-workspace-tyabuta.c9users.io/
webpack output is served from /

~ 省略 ~

webpack: Compiled successfully.

Preview > Preview Running Application

追記

コメントいただきました。
ありがとうございました。

2017年12月時点で試してみると、確かにng serveコマンドにpublic オプションを渡して実行できるようです。

バージョンは以下の通り。

$ ng --version
Angular CLI: 1.6.2
Node: 6.11.2
OS: linux x64
Angular: 5.1.2
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, router

@angular/cli: 1.6.2
@angular-devkit/build-optimizer: 0.0.36
@angular-devkit/core: 0.0.22
@angular-devkit/schematics: 0.0.42
@ngtools/json-schema: 1.1.0
@ngtools/webpack: 1.9.2
@schematics/angular: 0.1.11
@schematics/schematics: 0.0.11
typescript: 2.4.2
webpack: 3.10.0

一応、ng serve のヘルプも記載します。

$ ng help
ng serve <options...>
  --port (Number) (Default: 8080) Port to listen to for serving.
    aliases: -p <value>, -port <value>
  --host (String) (Default: localhost) Listens only on localhost by default.
    aliases: -H <value>, -host <value>
  --public-host (String) Specify the URL that the browser client will use.
    aliases: --live-reload-client <value>, --publicHost <value>

--public-host じゃなくて、--publicでもOKでした。

package.json

"start": "ng serve --port=8080 --host=0.0.0.0 --public-host=angular2-workspace-tyabuta.c9users.io",

これで、npm run start するだけでいけます。

Cloud9 のポートについて

ちなみに、portは指定しなくても、デフォルトで8080ポートで起動します。

Cloud9 では、8080ポートが公開ポートとして動作します。

https://angular2-workspace-tyabuta.c9users.io       -> OK
https://angular2-workspace-tyabuta.c9users.io:8080  -> OK
https://angular2-workspace-tyabuta.c9users.io:80    -> NG

URLのポートを省略した場合でも、8080ポートに繋がっているようです。

3件のコメント

  1. こんにちは。とてもありがとうございます。助かりました!私が試したところ、ng serveはpublicオプションを受け付けてくれました。Angularのバージョンは4.2.4でした。

清川 にコメントする コメントをキャンセル