awacleberryの備忘録

アナログ人間のデジタル日記。

Android の apk 出力で Unsupported major.minor version 52.0 エラー

出力する apk ファイルの量が多いので、コマンドラインから gradle 使ってビルドをすることが多いけど、今回急に次のエラーが出て戸惑った。

A problem occurred evaluating project ':app'.
> java.lang.UnsupportedClassVersionError: me/tatarka/RetrolambdaPlugin : Unsupported major.minor version 52.0

結論だけ言えば、java8 を使えば解消される。 以下が詳しくて助かった。

Androidアプリのビルドで「Unsupported major.minor version 52.0」のビルドエラーが発生する

webpack をサクッと使う手順


webpack の基本操作 にて述べた方法で、効率良く開発環境を整える手順を改めてまとめておく。

要件は、

  • js モジュールの統合と単一書き出し
  • sass の 統合と css 単一書き出し
  • compass の読み込み
  • js, css のミニマイズ
  • js, css の map ファイルの生成
  • ES6 -> ES5 トランスパイル(コンパイル
  • jquery の読み込み
  • watch で変更を監視

完成後のディレクトリ構成(ビルド前)は次のようになる。

project/
    ├── _css
    │     ├── entry.sass
    │     └── sub.sass
    ├── _js
    │     ├── entry.js
    │     └── sub.js
    ├── css
    ├── js
    ├── node_modules
    ├── package.json
    ├── webpack_index.html
    └── webpack.config.js
  • ビルド前の各モジュールは _(アンダースコア)から始まるディレクトリに入れる
  • ビルド後のファイルは、それぞれ js, css ディレクトリに格納される
  • webpack_index.html は確認用の html

0. ディレクトリとテストファイルの準備

# 各ディレクトリ
mkdir {_css,_js,css,js}
# テスト用 html
echo '<html><link rel="stylesheet" media="all" href="./css/style.css"><body><h1></h1></body><script src="./js/bundle.js"></script></html>' > webpack_index.html
# entry.scss
echo '@import "compass"; @import "sub"; h1 { @include inline-block; color: #f00; }' > _css/entry.scss
# sub.scss
echo '@import "compass"; h1 { background-color: #000; }' > _css/sub.scss
# entry.js
echo 'var $ = require("jquery"); $(function(){$("h1").text(require("./sub.js"));});' > _js/entry.js
# sub.js
echo 'module.exports = "OK";' > _js/sub.js
  • webpack_index.html ではビルド後の js と css の読み込みの他、h1 タグを用意しておく
  • entry.scss では sub.scss を読み込む他、h1 を赤字に、また compass で inline-block にする
  • sub.scss では h1 の背景を黒にする
  • entry.js では jquery の読み込みの他、sub.js の出力を h1 にセットする
  • sub.js は “OK” を返す
  • ビルド後のイメージは次の感じ

スクリーンショット 2017-06-01 6.41.20.png

1. package.json を作る

-y オプションを付けて対話をせずに、初期化する。

npm init -y

2. devDependencies に追加する

npm install --save-dev webpack babel-loader babel-core babel-preset-es2015 node-sass style-loader css-loader sass-loader extract-text-webpack-plugin compass-mixins

それぞれ、

  • webpack 本体

    • webpack
  • ES6 対応

    • babel-loader
    • babel-core
    • babel-preset-es2015
  • sass 対応
    • node-sass
    • style-loader
    • css-loader sass-loader
  • sass -> css 書き出し対応
    • extract-text-webpack-plugin
  • compass 対応

3. dependencies に追加する

npm install jquery --save

4. package.json を修正

...
"private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --optimize-minimize"
  },
...
  • プライベート用にして警告排除
  • "private": true
  • ビルドファイルのミニマイズ設定
  • "build": "webpack --optimize-minimize"

5. webpack.config.js を置く

var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = [
    /**
     * js
     */
    {
        entry: "./_js/entry.js",
        watch: true,
        output: {
            path: path.join(__dirname, './js'),
            filename: "bundle.js"
        },
        module: {
            loaders: [{
                test: /\.js[x]?$/,
                exclude: /node_modules/,
                loader: 'babel-loader?presets[]=es2015'
            }]
        },
        devtool: 'source-map'
    },
    /**
     * Sass
     */
    {
        entry: './_css/entry.scss',
        watch: true,
        output: {
            path: path.join(__dirname, './css'),
            filename: 'style.css'
        },
        module: {
            loaders: [{
                test: /\.scss$/,
                loader: ExtractTextPlugin.extract({
                    use: [{
                            loader: 'css-loader'
                        },
                        {
                            loader: 'sass-loader',
                            options: {
                                includePaths: ['node_modules/compass-mixins/lib']
                            },
                        }
                    ],
                    fallback: 'style-loader'
                })
            }]
        },
        plugins: [
            new ExtractTextPlugin('style.css')
        ],
        devtool: 'source-map'
    }
];

6. ビルドして確かめる

npm run build

実行後、webpack_index.html をブラウザで開き、

スクリーンショット 2017-06-01 6.41.20.png

と表示されれば、js, sass ともにビルドができている。

また、js/bundle.js, css/style.css はそれぞれミニマイズされていて、かつ同階層に map ファイルも出力されていれば問題ない。

webpack の基本設定

webpack を初めて触ったので、調べたことなどを備忘録として残しておく。webpack のインストールから、ES6, jQuery, Sass, compass の対応まで。

1. npm の準備

package.jsonを作る。

npm init

2. ローカルに webpack をインストー

package.json に書き込みたいので、--save-dev オプションをつける。

npm install webpack --save-dev

No repository field. と怒られた場合、一先ず、package.json"private": true を追加すれば警告は消える。

ドキュメントに依ると、

If you set “private”: true in your package.json, then npm will refuse to publish it.

This is a way to prevent accidental publication of private repositories. If you would like to ensure that a given package is only ever published to a specific registry (for example, an internal registry), then use the publishConfig dictionary described below to override the registry config param at publish-time.

要は公開用のリポジトリじゃなく、プライベートなリポジトリのみで使うっていう設定。これを指定すれば、repository field の指定がなくても許される。

3. ローカルにパスを通す

このままだと、webpack コマンドは動かないので、パスを通す。

export PATH=$PATH:./node_modules/.bin

以下でバージョンが確認出来る。

webpack -v

もちろん、パスを通す必要がないなら、直接、

node_modules/.bin/webpack -v

でも良い。

4. webpack でビルドをテストする

適当に、sub.js を作る。

module.exports = ["a", "b", "c"]; 

module.export は return 的なやつ。これを app.js で読み込み、出力する。

console.log(require("./sub.js")); 

これを bundle.js としてビルドする。

webpack app.js bundle.js

実行すると、

Version: webpack 2.6.1
Time: 81ms
    Asset     Size  Chunks             Chunk Names
bundle.js  2.78 kB       0  [emitted]  main
   [0] ./sub.js 34 bytes {0} [built]
   [1] ./app.js 34 bytes {0} [built]

こんな感じの実行結果と bundle.js が書き出されている。

この bundle.js を実行すると、次のような結果になる。

[ 'a', 'b', 'c' ]

なお、npm の実行時にこれも一緒にビルドして欲しいので、build: の項目を設け、そこに追加する。

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack app.js bundle.js"
  },

そうすれば、

npm run build

でビルドしてくれる。

5. webpack.config.js からビルドする

そもそも webpack 実行時に js のビルドも自動的にしてほしいので、webpack.config.js にその設定を書く。

まずは、package.jsonbuild: 項目を webpack だけにして、

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },

以下のように webpack.config.js を作成。entryoutputfilename 指定する。

module.exports = {                                                     
    entry: "./app.js",
    output: {
    filename: "bundle.js"
    }
}

そうすれば、先ほどと同様に、

npm run build

でビルド出来る。ディレクトリパスを別途指定するなら、path モジュールを読み込んで、

var path = require('path');
module.exports = {                                                     
    entry: "./js/modules/app.js",
    watch: true,
    output: {
        path: path.join(__dirname, './js'),
        filename: "bundle.js"
    }
}

のようにする。

6. watch モードにする

ファイルを監視させて、変更時に自動ビルド。コマンドラインから設定するなら、

webpack --watch

一方、webpack.config.js で指定するなら、watch: を設けて、true にする。

module.exports = {
  watch: true,
  entry: "./app.js",
  ...省略...

7. jquery を使う

まずは、npm で jquery をダウンロード。プロダクトでもつかうので、 オプションは --save

npm install jquery --save
var $ = require("jquery");
$(function(){

});

件の通り、$ に jquery をつっこむだけ。

8. ES6 に対応させる

ES6 を ES5 にコンパイルというかトランスパイルというか、とにかく変換する場合は、babel-loader を使う。

開発用なので、オプションは --save-dev でインストールする。

npm install babel-loader babel-core babel-preset-es2015 --save-dev

webpack.config.js に以下を追加する。

...省略...
  module: {
    loaders: [{
      test: /\.js[x]?$/,
      exclude: /node_modules/,
      loader: 'babel-loader?presets[]=es2015'
    }]
  }
...省略...

正規表現で node_modules を除く js 系の拡張子を対象にしている。

試しに app.js を次のように書き換え、

/*jshint esversion: 6 */
var $ = require("jquery");
$(function(){
    "use strict";
    const hoge = "!!!!";
    $("body").text(hoge);
});

ビルドすると、bundle.js では、

...省略...

/*jshint esversion: 6 */
var $ = __webpack_require__(0);
$(function () {
    "use strict";

    var hoge = "!!!!";
    $("body").text(hoge);
});

...省略...

const -> var の変換がされている。

9. js を minimize する

圧縮したいなら、packege.jsonbuild:--optimize-minimize のオプションをつける。

ただ、このままだとデバッグし難いので、更に --devtool source-map のオプションもつけて、デベロッパーツールから圧縮前を見れるようにする。

...省略...
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --optimize-minimize --devtool source-map"
  },
...省略...

これで、Chrome デベロッパーツールの Sources タブに webpack:// のディレクトリが表示される。

source-map は webmap.config.js でも指定できる。

末尾に devtool: の項目を追加し、source-map を指定する。

...省略...
  module: {
    loaders: [{
      test: /\.js[x]?$/,
      exclude: /node_modules/,
      loader: 'babel-loader?presets[]=es2015'
    }]
  },
  devtool: 'source-map'
...省略...

10. Sass の設定をする

まずは、必要なモジュールをインストール。

npm install --save-dev node-sass style-loader css-loader sass-loader extract-text-webpack-plugin

css の出力も可能にするため、extract-text-webpack-plugin も入れている。

webpack.config.js の exports の対象をオブジェクト({})からオブジェクトの配列([{},{}])形式にして、次のように変更する。

var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = [
    /**
     * js の設定
     */
    {
        entry: "./js/modules/app.js",
        watch: true,
        output: {
            path: path.join(__dirname, './js'),
            filename: "bundle.js"
        },
        module: {
            loaders: [{
                test: /\.js[x]?$/,
                exclude: /node_modules/,
                loader: 'babel-loader?presets[]=es2015'
            }]
        },
        devtool: 'source-map'
    },
    /**
     * Sass の設定
     */
    {
        entry: './css/modules/style.scss',
        watch: true,
        output: {
            path: path.join(__dirname, './css'),
            filename: 'app.css'
        },
        module: {
            loaders: [{
                test: /\.scss$/,
                loader: ExtractTextPlugin.extract('css-loader!sass-loader')
            }]
        },
        plugins: [
            new ExtractTextPlugin('app.css')
        ],
        devtool: 'source-map'
    }
];

これで、複数指定ができる。なお、出力先のディレクトリなども整理してある。

11. compass を使う場合

まずは、compass-mixins をインストール。

npm install --save-dev compass-mixins

sass-loader の includePaths に compass-mixins/lib を指定して読み込ませる。

    /**
     * Sass の設定
     */
    {
        entry: './css/modules/style.scss',
        watch: true,
        output: {
            path: path.join(__dirname, './css'),
            filename: 'app.css'
        },
        module: {
            loaders: [{
                test: /\.scss$/,
                loader: ExtractTextPlugin.extract({
                    use: [{
                            loader: 'css-loader'
                        },
                        {
                            loader: 'sass-loader',
                            options: {
                                includePaths: ['node_modules/compass-mixins/lib']
                            },
                        }
                    ],
                    fallback: 'style-loader'
                })
            }]
        },
        plugins: [
            new ExtractTextPlugin('app.css')
        ],
        devtool: 'source-map'
    }

下の config ファイルを参考にさせてもらった。

https://github.com/iliran11/react-cordova-boilerplate/blob/2b68ade24c9a56512140ff2c3419d401afd0737b/bin/get-webpack-config.js


参考 - Webpackを使って、Sassをコンパイルする方法 2017年4月版

wkhtmltopdf で HTML を PDFにする

wkhtmltopdf のインストー

以下よりインストーラーをダウンロードして、インストー

wkhtmltopdf

コマンド確認

wkhtmltopdf -h

上手くインストールされていれば、なんか色々表示される。

PDF に変換

試しに google.com を PDF 出力する。

wkhtmltopdf http://google.com google.pdf

これで簡単に出力できてハッピーなはずが……

スクリーンショット 2017-05-30 18.37.56.png

ちっさ。サイズがひどいことになってる……。

サイズが小さい問題の対処

--disable-smart-shrinking というオプションを付ければ良さそうという記事を読んで、さっそくトライするも、変わらず。このオプションは最適化してくれるものだけど、この出力は最悪化されているので、まぁ、違うだろう。

で、もう少し調べ、ようやく同じ事例を発見。

https://stackoverflow.com/questions/40814680/wkhtmltopdf-generates-tiny-output-on-mac

ここで問題が報告されている Mac OS のバージョンが自分のものと一致していて、少し、面倒臭い雰囲気がする……。なお、この時点の環境は、

  • OS バージョン: 10.11.6(15G31)
  • wkhtmltopdf バージョン: 0.12.4

手動で wkhtmltopdf を消し去って、別バージョンを入れてみる。インストール先に wkhtmltoimage もあって、一緒にインストールされたものなのでこれも消す。

以下から新しく 0.12.3 のインストーラーを落としてインストール。

https://downloads.wkhtmltopdf.org/0.12/0.12.3/

改めて、出力する。

スクリーンショット 2017-05-30 18.41.29.png

はい、ハッピーになれた。

PHP Composer の導入

installer のダウンロード

curl -sS https://getcomposer.org/installer | php

コマンドの確認するなら、

php composer.phar

local/bin/compoer に移動しておく。

mv composer.phar /usr/local/bin/composer

~/composer/composer.phar とかにしている人もいるので、ここじゃなきゃいけない、みたいなのはないのかな。分からなくなったら、

which composer

とかすればいい。

プロジェクトを作る

新しくプロジェクトを作るなら、

composer init

で、対話形式に composer.json が作れる。最初に、

Package name (<vendor>/<name>)

ベンダー名/パッケージ名 が聞かれるので、このスラッシュ形式で指定。

Description

プロジェクトの説明を記入。

Author

name <mail address> の形式で指定。

Minimum Stability

最小限の「安定度合い」的なものを聞かれるので、dev, alpha, beta, RC, and stable から適時選択。デフォルトは、stable

Package Type

プロジェクトなら project としてれば良さそう。デフォルトは library

License

オプショナルだけど、ドキュメントは、

Optional, but it is highly recommended to supply this.

と言っている。まぁ、そうだな。

Search for a package: 

いよいよパッケージ。例えば、phpunit など。

[0] phpunit/phpunit
[1] eher/phpunit
[2] jbzoo/phpunit
[3] sugared-rim/phpunit
[4] hiqdev/php-units
[5] task/phpunit
[6] phpunit/phpunit-mock-objects
[7] phpunit/phpunit-selenium
[8] phpunit/phpunit-story
[9] phpunit/phpunit-skeleton-generator
[10] phpunit/dbunit
[11] phpunit/phpunit-dom-assertions
[12] phpunit/phpcov
[13] phpunit/phpunit-mink-trait
[14] phpunit/php-timer

ばーっと候補がでるので、0 を入力。

Enter the version constraint to require (or leave blank to use the latest version)

最新版を使うなら、そのまま return で進む。

Using version ^6.1 for phpunit/phpunit
Search for a package: 

うっす。もういらないので、return で進む。

{
    "name": "hoge/composer-test",
    "description": "this is a test.",
    "type": "project",
    "require-dev": {
        "phpunit/phpunit": "^6.1"
    },
    "authors": [
        {
            "name": "hoge",
            "email": "hoge@huga.com"
        }
    ],
    "require": {}
}

Do you confirm generation [yes]? 

こんな json ができれば、OK。yes で終了。ls で確認すれば、composer.jsonディレクトリに作成されている。

パッケージのインストー

さっそく json で定義したものをインストー

composer install

と、手元の環境の PHP5.5.36 だったので、

  Problem 1
    - phpunit/phpunit 6.1.4 requires php ^7.0 -> your PHP version (5.5.36) does not satisfy that requirement.
    - phpunit/phpunit 6.1.3 requires php ^7.0 -> your PHP version (5.5.36) does not satisfy that requirement.
    - phpunit/phpunit 6.1.2 requires php ^7.0 -> your PHP version (5.5.36) does not satisfy that requirement.
    - phpunit/phpunit 6.1.1 requires php ^7.0 -> your PHP version (5.5.36) does not satisfy that requirement.
    - phpunit/phpunit 6.1.0 requires php ^7.0 -> your PHP version (5.5.36) does not satisfy that requirement.
    - Installation request for phpunit/phpunit ^6.1 -> satisfiable by phpunit/phpunit[6.1.0, 6.1.1, 6.1.2, 6.1.3, 6.1.4].

composer.json を編集して、phpunit のバージョンを phpunit-4.8.35.phar とする。

"require-dev": {
    "phpunit/phpunit": "4.8.35"
},
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 21 installs, 0 updates, 0 removals
  - Installing symfony/yaml (v3.2.8): Downloading (100%)         
  - Installing sebastian/version (1.0.6): Downloading (100%)         
  - Installing sebastian/global-state (1.1.1): Downloading (100%)         
  - Installing sebastian/recursion-context (1.0.5): Downloading (100%)         
  - Installing sebastian/exporter (1.2.2): Downloading (100%)         
  - Installing sebastian/environment (1.3.8): Downloading (100%)         
  - Installing sebastian/diff (1.4.3): Downloading (100%)         
  - Installing sebastian/comparator (1.2.4): Downloading (100%)         
  - Installing doctrine/instantiator (1.0.5): Downloading (100%)         
  - Installing phpunit/php-text-template (1.2.1): Downloading (100%)         
  - Installing phpunit/phpunit-mock-objects (2.3.8):Downloading (100%)         )
  - Installing phpunit/php-timer (1.0.9): Downloading (100%)         
  - Installing phpunit/php-file-iterator (1.4.2): Downloading (100%)         
  - Installing phpunit/php-token-stream (1.4.11): Downloading (100%)         
  - Installing phpunit/php-code-coverage (2.2.4): Downloading (100%)         
  - Installing webmozart/assert (1.2.0): Downloading (100%)         
  - Installing phpdocumentor/reflection-common (1.0): Downloading (100%)          - Installing phpdocumentor/type-resolver (0.2.1): Downloading (100%)         
  - Installing phpdocumentor/reflection-docblock (3.1.1): Downloading (100%)      - Installing phpspec/prophecy (v1.7.0): Downloading (100%)         
  - Installing phpunit/phpunit (4.8.35): Downloading (100%)         
symfony/yaml suggests installing symfony/console (For validating YAML files using the lint command)
sebastian/global-state suggests installing ext-uopz (*)
phpunit/php-code-coverage suggests installing ext-xdebug (>=2.2.1)
phpunit/phpunit suggests installing phpunit/php-invoker (~1.1)
Writing lock file
Generating autoload files

依存モジュールもまとめて、いっぱい。 ls すると、

composer.json    composer.lock   vendor

lock ファイル と vendor ディレクトリができている。vendor という名前のディレクトリに外部の依存モジュールが格納されるので、.gitignore にこのディレクトリを指定しておけば OK。

なお、phpunitphp バージョンの対応は、

PHPUnitとPHPのバージョン対応表

を参考。

パッケージの追加

composer require cebe/markdown

require で追加できる。composer.json と lock ファイルも更新される。バージョン指定する場合は、

composer require hoge/huge:1.1.11

みたいにする。


参考

Markdown を PDF にする

前提

node.js が動くこと。

npm で markdown-pdf をインストー

npm install -g markdown-pdf

pdf に変換

markdown-pdf hoge.md

このままだとスタイルがないので、まず、github のスタイルを拝借。
https://gist.github.com/andyferra/2554919
css のオプションをつけて、

markdown-pdf hoge -s github.css

なお、6系の node.js だとエラーがでるけど、出力はちゃんとできる。

(node:63631) Warning: Possible EventEmitter memory leak detected. 2 end listeners added. Use emitter.setMaxListeners() to increase limit

参考 - マークダウンで文章を書いてHTML / Docx / PDF に変換する

PHPでOS差を吸収する定数を使う

PHP_EOL

改行コードを直接指定すると、

$hoge = "hoge";
echo $hoge, "\n";

みたいにしがち、これだとCRLFに対応できないので、PHP_EOLを使って、

echo $hoge, PHP_EOL ;

にしたほうがよい。環境の違いで、出力をかえてくれるみたい。ちなみに、EOLはEnd of Lineの略。

改行 改行コード
LF \n
CELF \r\n

DIRECTORY_SEPARATOR

ディレクトリパスもつい、

$hoge = "hoge";
$fuga = "fuga";
echo $hoge, "/", $fuga, PHP_EOL;

みたいにしちゃうけど、

echo $hoge, DIRECTORY_SEPARATOR, $fuga, PHP_EOL;

で環境差を吸収できる。

他、PATH_SEPARATORなんかもあるみたい。なお、PHP_OSでOS種を返してくれる。