読者です 読者をやめる 読者になる 読者になる

Engineer's Way

主にソフトウェア関連について色々書くブログです。

Exrm(Elixir Release Manager)を使ったリリースでエラーが出た時の対処法

Elixir デプロイ

 

f:id:matsnow:20170314012129j:plain:w300

最近Elixirを勉強中だけど、ビルド周りで少しハマったのでメモ。

現象

Exrmを導入した状態で「mix release」コマンドを実行してElixirのアプリをビルドしようとしたところ、「(CaseClauseError) no case clause matching: :eacces」というエラーが発生した。

% MIX_ENV=prod mix release
  :
** (CaseClauseError) no case clause matching: :eacces
    lib/exrm/utils/utils.ex:110: ReleaseManager.Utils.relx/5
    lib/mix/tasks/release.ex:339: anonymous fn/4 in Mix.Tasks.Release.do_release/1
    lib/ex_unit/capture_io.ex:146: ExUnit.CaptureIO.do_capture_io/2
    lib/ex_unit/capture_io.ex:119: ExUnit.CaptureIO.do_capture_io/3
    lib/mix/tasks/release.ex:338: Mix.Tasks.Release.do_release/1
    lib/mix/tasks/release.ex:78: Mix.Tasks.Release.do_run/1
    (mix) lib/mix/task.ex:294: Mix.Task.run_task/3
    (mix) lib/mix/cli.ex:58: Mix.CLI.run_task/2

対処法

調べたところ、とりあえずsudoをつけることで解決することが判明。
mix release fails with 'no case clause matching: :eacces' · Issue #401 · bitwalker/exrm · GitHub

% sudo  MIX_ENV=prod mix release
==> The release for sample-app-0.0.1 is ready!
==> You can boot a console running your release with `$ rel/sample-app/bin/sample-app console`

別の対処

Exrmの代わりにdistilleryを使う。
release.initが事前に必要になるが、sudoをわざわざ付ける必要はなくなる。

%  MIX_ENV=prod mix release.init

An example config file has been placed in rel/config.exs, review it,
make edits as needed/desired, and then run `mix release` to build the release

%  MIX_ENV=prod mix release
==> Assembling release..
==> Building release sample-app:0.0.1 using environment prod
==> Including ERTS 8.2.2 from /usr/local/Cellar/erlang/19.2.3/lib/erlang/erts-8.2.2
==> Packaging release..
==> Release successfully built!
    You can run it in one of the following ways:[f:id:matsnow:20170314011357p:plain]
      Interactive: _build/prod/rel/sample-app/bin/sample-app console
      Foreground: _build/prod/rel/sample-app/bin/sample-app foreground
      Daemon: _build/prod/rel/sample-app/bin/sample-app start

BrowserifyからWebpack(バージョン2.2.1)に移行してみた

Webpack gulp JavaScript

 

目次

今までのプロジェクトで、ずっとフロントの開発環境としてBrowserifyを使ってきたけど、gulpの記述が悪いのか、
とにかく重たいのでWebpackを試してみることにした。

f:id:matsnow:20170306024225p:plain

1 Webpackの特徴

事前に調べてみた範囲では以下のような特徴があるとのこと。

  1. JSの依存関係を解決できる。
  2. JS以外のファイルもまとめて扱える。
  3. gulpを置き換えることもできる。
  4. ビルド結果を複数にすることが容易。
  5. トランスパイラ機能あり(Sass、TypeScript、Babel)
  6. 全ファイルをjsにするので、cssなどを別扱いにするなら、gulpと組み合わせる方が良い。

2 今回やりたいこと

  • JavaScriptファイルを複数の単位でまとめる。
  • JSONもマージしたい。
  • 難読化、minifyする。
  • ソースマップを作る。
  • watchも機能させる。

3 インストール方法

  1. webpackをnpmインストールする。(以下ではnpm iの代わりにyarn addを使用)
    $ yarn [global] add webpack
    $ yarn [global] add ***-loader
    # ***の部分はbabelやsass、ts、jsonなど。読み込みたいファイルに対応したloaderをインストールする。
    
  2. 開発用サーバをインストールする。(任意)
    $ yarn add webpack-dev-server
    # node 4.7以上が必要。
    
  3. webpack.config.jsを作成する。
  4. コマンドを打つなり、gulpに組み込むなりで動かす。

4 動かし方

4-1 コマンドで動かす方法

  1. webpackを実行する。
    $ webpack
    
  2. watchを実行する。
    $ webpack --progress --colors --watch
    
  3. serverを起動する。
    $ webpack-dev-server --progress —colors
    

4-2 gulpで動かす方法

  1. 「webpack-stream」をnpmインストールする。
  2. 以下のようなgulpタスクを作成する。
    import webpackStream from 'webpack-stream';
    import webpack from 'webpack';
    import webpackConfig from '../webpack.config';  // webpack.config.jsのパスを指定する。
    
    gulp.task('webpack', () => {
    
      webpackConfig.watch = true;  // watchをしたい場合は必要。webpack.config.jsに直接書いてもOK。
    
      return webpackStream(webpackConfig, webpack)
        .on('error', function handleError() { // watch中のエラーで死なないようにする。
          this.emit('end');
        })
        .pipe(gulp.dest(config.sources.dest));
    });
    
  3. gulpを実行する。

5 webpack.config.jsの書き方

5-1 最低限必要な内容

const config = {
  // メインとなるJavaScriptファイル(エントリーポイント)
  entry: './app/js/index.js',

  // ファイルの出力設定
  output: {
    filename: 'bundle.js',
  }
}

5-2 難読化、最適化してみる。

  • webpack.config.jsに以下を追記。
plugins: [
    new webpack.optimize.UglifyJsPlugin({ minimize:true }),
    new webpack.optimize.OccurrenceOrderPlugin()
]

UglifyJsPluginは、gulp-uglifyと同じく難読化とminifyを行ってくれるプラグイン
OccurrenceOrderPluginは、Uglifyされたスクリプト中に出てくるIDの桁数を短くするプラグイン(らしい)。

5-3 ソースマップを使う。

  1. UgilifyJsPluginの引数のオブジェクトに「sourceMap: true」を追加する。
  2. webpack.config.jsに以下を追記。
  devtool: 'inline-source-map'

5-4 作成するファイルを複数に分割する。(browserifyとの大きな違い)

  1. entryをオブジェクトで記述する。
    1. 配列を使うと、マージする順番を指定できる。(GoogleAnalyticsをファイルの最後に追加するなど)
  2. outputのfilenameに[name]をつける。

5-5 共通処理を1つのJSファイルにまとめる。

  1. webpack.optimize.CommonsChunkPluginを使う。

5-6 JSONコンパイル対象にする。(同様に画像やCSSコンパイルできる)

  1. デフォルトで拡張子jsonコンパイル対象なので、気にしなくて良い。
  2. loaderに以下を追加。
  3. { test: /.json$/, loader: ‘json-loader’ },

5-7 CDNの外部ライブラリを使ってみる。

externalsを定義することで、CDNで取得した外部ライブラリを、import無しで使用可能となる。

  externals: {
    '$': 'jQuery',
    'jquery-ui': 'jquery-ui',
  },

5-8 一部のローカルライブラリのimportでエラーが出る場合

今回Amchartsを使おうとしたところ、名前が解決できないというエラーが出てしまった。 webpack.config.jsに以下のようにresolve.aliasを書くと解消できた。

resolve: {
    alias: {
      amcharts3$: path.resolve(__dirname, 'app/js/lib/amcharts/amcharts.js')
    }
  }

6 webpack.config.jsのサンプル

最終的に作って見たwebpack.config.jsはこんな感じ。

const webpack = require('webpack');
const path = require('path');
const env = process.env.NODE_ENV;

const config = {
  // メインとなるJavaScriptファイル(エントリーポイント)
  entry: {
    'bundle': path.resolve(__dirname, '../app/js/index.js'),
    'chart':  path.resolve(__dirname, '../app/js/chart.js'),
  },

  // ファイルの出力設定
  output: {
    filename: '[name].js',
  },

  // amcharts3のimport失敗への対応
  resolve: {
    alias: {
      amcharts3$: path.resolve(__dirname, '../app/js/lib/amcharts/amcharts.js')
    }
  },

  externals: {
    '$': 'jQuery',
    'jquery-ui': 'jquery-ui',
  },

  module: {
    rules: [
      { test: /\.js$/,   loader: 'babel-loader', exclude: /node_modules/ },
      { test: /\.json$/, loader: 'json-loader' },
    ]
  },

  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(env)
    }),
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.optimize.CommonsChunkPlugin({
      name:     'commons',
      filename: 'commons.js',
      minChunks: Infinity
    })
  ]
};

if (env === 'production') {
  config.plugins.push(new webpack.optimize.UglifyJsPlugin({
    compress: {
      warnings: false
    }
  }));
} else {
  config.plugins.push(
    new webpack.optimize.UglifyJsPlugin({
      sourcemap: true, minimize: true
    })
  );
  config.devtool = 'source-map';
}

module.exports
 = config;

AmchartsのTips

Amcharts JavaScript

 

f:id:matsnow:20170306032523p:plain

最近のプロジェクトでAmcharts(https://www.amcharts.com/)を使っていたが、
ドキュメントの内容がイマイチ、かつ日本語の情報が少なく苦労したので、備忘録を兼ねて記載しておく。

    "graph": {
        "alphaField": "fillAlphas", // グラフの透過度
        "bulletField": "bullet",   // バレットタイプの追加
        "bulletSizeField": "bulletSize", // バレットサイズの追加
    },
    "categoryField": "category", // 行タイトル
    "colorField": "fillColors", // グラフの色
    "startField": "start", // ガント線の開始時間 or 日時
    "endField": "end", // ガント線の終了時間 or 日時
    "durationField": "duration", // ガント線の長さ (2時間など)
    "dataProvider": [ {
        "category": "John",
        "segments": [ {
            "start": 7,
            "duration": 2,
            "fillColors": "#46615e",
            "task": "Task #1"
        }, {
  • グラフのマージンに関わらない変更はmakeChartをやり直さず、validateNowでやった方が軽い。

  • 「usePrefixes:true」をJSONに指定することで、桁の大きい数字を自動的に小さくできる。

    • 例:1,000,000 -> 1M
  • exportプラグインを使うとき、captureメソッドの引数に「backgroundColor: (色コード)」を渡すと、Annotateモードや画像ダウンロード時の背景色を変えられる。

gulpで「CALL_AND_RETRY_LAST Allocation failed」というエラーが出た時の対処

gulp

 

gulpで「CALL_AND_RETRY_LAST Allocation failed」というエラーが発生

gulp-concatでファイルを結合していたら、以下のようなエラーが発生してしまった。

<--- Last few GCs --->

  120788 ms: Mark-sweep 1379.7 (1455.9) -> 1379.7 (1455.9) MB, 1211.9 / 0 ms [allocation failure] [GC in old space requested].
  121826 ms: Mark-sweep 1379.7 (1455.9) -> 1379.7 (1455.9) MB, 1038.5 / 0 ms [allocation failure] [GC in old space requested].
  122882 ms: Mark-sweep 1379.7 (1455.9) -> 1379.7 (1455.9) MB, 1055.0 / 0 ms [last resort gc].
  123942 ms: Mark-sweep 1379.7 (1455.9) -> 1379.7 (1455.9) MB, 1060.2 / 0 ms [last resort gc].


<--- JS stacktrace --->

==== JS stack trace =========================================

Security context: 0x3b31c8a5a91 <JS Object>
    1: /* anonymous */(aka /* anonymous */) [0x3b31c8041b9 <undefined>:~2655] [pc=0x2ffd9b29ee8e] (this=0x3b31c8041b9 <undefined>)
    2: /* anonymous */(aka /* anonymous */) [0x3b31c8041b9 <undefined>:~2134] [pc=0x2ffd9b2972ac] (this=0x3b31c8041b9 <undefined>)
    3: /* anonymous */(aka /* anonymous */) [0x3b31c8041b9 <undefined>:~2599] [pc=0x2ffd9b29b423] (this=0x3b31c8041b9 <undefined>,allow_...

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
zsh: abort      gulp build:local

エラーの原因

原因は「out of memory」というエラーの通り、ヒープメモリが不足していたことだった。
参考にさせて頂いたサイトによると、Node.jsは512MBがデフォルトとのこと。
Node.js の out of memory エラー回避方法 : まだプログラマーですが何か?

対処方法

gulpを実行するときに、--max_old_space_sizeのオプションを付けてメモリサイズを大きくすればOK
ただ、手打ちはもちろん、シェルのaliasを設定するのもどうかなと思ったので、
package.jsonに以下のようにスクリプト定義を追加することで対処。

"scripts": {
   "dev": "./node_modules/.bin/gulp --max_old_space_size=8192 dev",
}

gulpの場合、オプションの単語がハイフンではなくアンダースコアで繋がれているのが微妙なハマりポイントかも。

  • gulp:–max_old_space_size
  • node:–max-old-space-size

結合されたtableタグをJavaScriptで分割する方法

JavaScript

 

特に何ということは無いのだけども。
ExcelのUIを実現するJSライブラリ」を使っている時、クリックしたりマウスオーバーしたセルの列名が欲しくなることがある。
その時、列名のセルを結合していると列番号から引っ張れないので、こんな感じで分割する一手間が必要になることもあったり。
まあ今回は不要だったけど。

let data = [];
const getter = () => {
  const tr = $("table tr");
  const cells = tr.eq(0).children();
  for( const cell of cells ){
    const text = $(cell).text();
    const colspan = $(cell).attr("colspan");
    const number = colspan ? Number(colspan) : 1;

    for (let i = 0; i < number; i++){
       data.push(text);
    }
  }
};

getter();
$('#result').text(data);

http://codepen.io/anon/pen/WpvamY

Docker for mac v1.13でdocker pullできない問題

Docker Mac

  

ある時から、Macでdocker pull をしようとすると、なぜか以下のようなエラーが出るようになってしまった。

% docker pull ubuntu
Using default tag: latest
Error response from daemon: Get https://registry-1.docker.io/v2/:
 dial tcp: lookup registry-1.docker.io on 192.168.65.1:53: server misbehaving

エラーメッセージで検索するとDNSの問題みたいだったので、
/etc/resolv.confにnameserver 8.8.8.8を追加してみたり、
/etc/hosts に「registry-1.docker.io」のIPアドレスを直接書いたり、
dockerを再インストールするなどしてみたが、完全に解決するには至らず。

結果として、v1.13のBeta版をインストールすれば治りました。
dockerの問題だったのだろうか。

(2017/2/14追記)
ブコメによると、以下のissueが該当するようです。情報ありがとうございます!
github.com

はてなブログのトップページでボタンやコメント欄(ついでに広告も)を消す方法

CSS はてなブログ

 

続きを読む

高機能でシンプルUIのプロジェクト管理サービスasana

プロジェクト管理 asana

 

続きを読む

最新のMBaaS、Firebaseのチュートリアルをやってみた

Firebase mBaaS Google

 

続きを読む

AndroidStudio(Mac)でデバイスが認識されない時の対策

Android Mac

 

続きを読む