gzipでの圧縮と画像の最適化をしてみる。【ver.4.4】

ファイルをminifyして圧縮したので、次はgzipでさらに圧縮をかけていく。

bundle.jsの圧縮

webpackのgzip用のプラグインをインストールし、設定ファイルを編集する。

> npm install compression-webpack-plugin --save-dev

webpack.config.babel.js

import webpack from "webpack";
import path from "path";
import CompressionPlugin from "compression-webpack-plugin";

export default {
  "entry": "./source/renderer/renderer.jsx",
  "output": {
    "filename": "bundle.js",
    "path": path.resolve(__dirname, "build")
  },
  "resolve": {
    "extensions": ["*", ".js", ".jsx"]
  },
  "plugins": [
    new webpack.DefinePlugin({
      "process.env": {
        NODE_ENV: JSON.stringify("production")
      }
    }),
    new webpack.optimize.UglifyJsPlugin(),
    new CompressionPlugin({
      "asset": "[path]"
    })
  ],
  "module": {
    "loaders": [
      {
        "test": /\.jsx$/,
        "exclude": /node_modules/,
        "loader": ["babel-loader"]
      },
      {
        "test": /\.css/,
        "loaders": ["style-loader", "css-loader?modules"]
      }
    ]
  }
};

index.htmlの圧縮

gulpのgzip用のプラグインをインストールし、設定ファイルを編集する。

> npm install gulp-gzip --save-dev

gulpfile.babel.js

※次のmain.jpgの圧縮も行っている。

import gulp from "gulp";
import webserver from "gulp-webserver";
import minifyHTML from "gulp-htmlmin";
import gzip from "gulp-gzip";

gulp.task("server", () => {
  startServer();
});

gulp.task("build:assets", () => {
  buildAssets();
});

gulp.task("build:css", () => {
  buildCSS();
});

gulp.task("build:html", () => {
  buildHTML();
});

function buildAssets() {
  gulp.src(["source/**/*.txt", "source/**/*.xml", "source/**/*.ico"])
      .pipe(gulp.dest("build"));

  gulp.src(["source/**/*.jpg"])
      .pipe(gzip({
        "append": false
      }))
      .pipe(gulp.dest("build"));
}

function buildCSS() {
  gulp.src(["source/**/*.css"])
      .pipe(gulp.dest("build"));
}

function buildHTML() {
  gulp.src(["source/**/*.html"])
      .pipe(minifyHTML({
        "collapseWhitespace": true,
        "minifyCSS": true
      }))
      .pipe(gzip({
        "append": false
      }))
      .pipe(gulp.dest("build"));
}

function startServer() {
  gulp.src(["build"])
      .pipe(webserver());
}

main.jpgの最適化

main.jpgは描画時に最大の高さが220pxにしかならないのに対して、ファイル自体の大きさは643x629と必要以上に大きい。

ImageMagickを使って画像を最適化する。

www.imagemagick.org

> magick main.jpg -resize x220 -strip -depth 8 -colors 256 main.jpg
  • -resize x220: 高さ220pxでリサイズ
  • -strip: メタデータの削除
  • -depth 8: 色深度を8bitに変更
  • -colors 256: 色数を256色に変更

  • diff

main.jpg BEFORE (114KB)

f:id:KazmaArakaki:20170621223323j:plain

main.jpg AFTER (22.5KB)

f:id:KazmaArakaki:20170621223352j:plain

main.jpgの圧縮

index.htmlを圧縮したgulp-gzipで圧縮可能。

gulpfile.babel.js

// 上記「index.htmlの圧縮」を参照。

Content-Encoding: gzipをレスポンスのHTTPヘッダに追加する

サーバーに問い合わせた後返ってくるデータのヘッダにContent-Encoding: gzipが含まれていなければ、ブラウザはgzip解凍を行わない。

server.js

import express from "express";

const app = express();

app.use(express.static(__dirname + "/build", {
  "setHeaders": (response, path, stat) => {
    switch(path.substr(path.lastIndexOf("."))) {
      case ".html":
      case ".js":
      case ".jpg":
        response.set("Content-Encoding", "gzip");
    }
  }
}));

app.listen(3000, () => {
  console.log("Server is running...");
});

BEFORE (Load: 4.38s)

f:id:KazmaArakaki:20170620205220j:plain

AFTER (Load: 1.77s)

f:id:KazmaArakaki:20170621223022j:plain

style.cssをindex.htmlの中に書き込んでみる。【ver.4.3】

html内にstyleを書き込む

index.html

<!DOCTYPE html>
<html lang="ja" prefix="og: http://ogp.me/ns#">
<head itemscope itemtype="http://schema.org/Article">
  <meta charset="utf-8">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>Kazma Arakaki</title>
  <meta name="url" content="https://arakakikazuma.info/">
  <meta name="description" content="The New Portfolio of Kazma Arakaki">
  <meta property="og:type" content="website">
  <meta property="og:url" content="https://arakakikazuma.info/">
  <meta property="og:title" itemprop="name" content="Kazma Arakaki">
  <meta property="og:site_name" content="Kazma Arakaki">
  <meta property="og:locale" content="ja_JP">
  <meta property="og:description" itemprop="description" content="The New Portfolio of Kazma Arakaki">
  <meta property="og:image" itemprop="image" content="https://arakakikazuma.info/images/main.jpg">
  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:site" content="KazmaArakaki">
  <link rel="author" href="/humans.txt">
  <link rel="canonical" href="https://arakakikazuma.info/">
  <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico">
  <link href="https://fonts.googleapis.com/css?family=Ubuntu" rel="stylesheet">
  <style>
    body {
      margin: 0;
      padding: 0;
      color: #3f4f5e;
      line-height: 1.6;
      font-size: 16px;
      font-weight: 300;
      font-family: "Ubuntu",
          "Helvetica", "Arial",
          "游ゴシック", "YuGothic",
          "ヒラギノ角ゴ Pro", "Hiragino Kaku Gothic Pro",
          "メイリオ", "Meiryo",
          sans-serif;
    }

    a {
      color: #476a30;
    }

    a:visited {
      color: #86af49;
    }

    a:hover {
      color: #ef5c6e;
    }
  </style>
</head>
<body>
  <div id="app"></div>

  <script src="./bundle.js"></script>
</body>
</html>

gulp-htmlminにCSSをminifyするための設定を追加する

gulpfile.babel.js

import gulp from "gulp";
import webserver from "gulp-webserver";
import minifyHTML from "gulp-htmlmin";

gulp.task("server", () => {
  startServer();
});

gulp.task("build:assets", () => {
  buildAssets();
});

gulp.task("build:css", () => {
  buildCSS();
});

gulp.task("build:html", () => {
  buildHTML();
});

function buildAssets() {
  gulp.src(["source/**/*.jpg", "source/**/*.txt", "source/**/*.xml", "source/**/*.ico"])
      .pipe(gulp.dest("build"));
}

function buildCSS() {
  gulp.src(["source/**/*.css"])
      .pipe(gulp.dest("build"));
}

function buildHTML() {
  gulp.src(["source/**/*.html"])
      .pipe(minifyHTML({
        "collapseWhitespace": true,
        "minifyCSS": true
      }))
      .pipe(gulp.dest("build"));
}

function startServer() {
  gulp.src(["build"])
      .pipe(webserver());
}

BEFORE (Load: 4.40s)

f:id:KazmaArakaki:20170619195649j:plain

AFTER (Load: 4.38s)

f:id:KazmaArakaki:20170620205220j:plain

index.htmlをminifyしてみる。【ver.4.2】

index.htmlはそんなに容量が大きいわけではないので効果は薄いと思われるが、bundle.jsをminifyしたついでなのでこちらもminifyしてみる。

gulp-htmlminのインストー

> npm install gulp-htmlmin --save-dev

gulpfileにminifyの処理を追加する

minifyHTMLに設定できるオプションはkangax/html-minifierにリストアップされている。

gulpfile.babel.js

import gulp from "gulp";
import webserver from "gulp-webserver";
import minifyHTML from "gulp-htmlmin";

gulp.task("server", () => {
  startServer();
});

gulp.task("build:assets", () => {
  buildAssets();
});

gulp.task("build:css", () => {
  buildCSS();
});

gulp.task("build:html", () => {
  buildHTML();
});

function buildAssets() {
  gulp.src(["source/**/*.jpg", "source/**/*.txt", "source/**/*.xml", "source/**/*.ico"])
      .pipe(gulp.dest("build"));
}

function buildCSS() {
  gulp.src(["source/**/*.css"])
      .pipe(gulp.dest("build"));
}

function buildHTML() {
  gulp.src(["source/**/*.html"])
      .pipe(minifyHTML({
        "collapseWhitespace": true
      }))
      .pipe(gulp.dest("build"));
}

function startServer() {
  gulp.src(["build"])
      .pipe(webserver());
}

minifyの前後比較

BEFORE (1.41KB)

f:id:KazmaArakaki:20170619195533j:plain

AFTER (1.30KB)

f:id:KazmaArakaki:20170619195649j:plain

ほぼ変化なし。

【Java練習問題】Warmup-1: diff21

問題

Given an int n, return the absolute difference between n and 21, except return double the absolute difference if n is over 21.

  • diff21(19) → 2
  • diff21(10) → 11
  • diff21(21) → 0

http://codingbat.com/prob/p116624

問題(日本語訳)

以下の関数diff21を実装する。

public int diff21(int n) {
  
}

1つのint値nが与えられたとき、21とnとの差の絶対値を返す。

nが21より大きい場合、21とnとの差の絶対値を2倍して返すこと。

回答1

public int diff21(int n) {
  if(n > 21) {
    return Math.abs(21 - n) * 2;
  }
  else {
    return Math.abs(21 - n);
  }
}

回答2

public int diff21(int n) {
  return (n > 21)? Math.abs(21 - n) * 2: Math.abs(21 - n);
}

回答3

public int diff21(int n) {
  return Math.abs(21 - n) * ((n > 21)? 2: 1);
}

kazmaarakaki.hatenablog.com

【Java練習問題】Warmup-1: sumDouble

問題

Given two int values, return their sum. Unless the two values are the same, then return double their sum.

  • sumDouble(1, 2) → 3
  • sumDouble(3, 2) → 5
  • sumDouble(2, 2) → 8

http://codingbat.com/prob/p154485

問題(日本語訳)

以下の関数sumDoubleを実装する。

public int sumDouble(int a, int b) {
  
}

2つのint値が与えられたとき、それらの合計を返す。

与えられた2つのint値が同じとき、合計の2倍の値を返す。

回答1

public int sumDouble(int a, int b) {
  if(a == b) {
    return (a + b) * 2;
  }
  else {
    return a + b;
  }
}

回答2

public int sumDouble(int a, int b) {
  return (a == b)? (a + b) * 2: a + b;
}

回答3

public int sumDouble(int a, int b) {
  return (a + b) * ((a == b)? 2: 1);
}

kazmaarakaki.hatenablog.com

【Java練習問題】Warmup-1: monkeyTrouble

問題

We have two monkeys, a and b, and the parameters aSmile and bSmile indicate if each is smiling. We are in trouble if they are both smiling or if neither of them is smiling. Return true if we are in trouble.

  • monkeyTrouble(true, true) → true
  • monkeyTrouble(false, false) → true
  • monkeyTrouble(true, false) → false

http://codingbat.com/prob/p181646

問題(日本語訳)

以下の関数monkeyTroubleを実装する。

public boolean monkeyTrouble(boolean aSmile, boolean bSmile) {
  
}

二匹のサル、aとbがいる。それぞれが笑っているかどうかが引数aSmilebSmileで与えられる。

もしサルが2匹とも笑っているか、もしくは2匹とも笑っていなければ、問題が生じる。

問題が生じる場合にtrueを返す関数を作成せよ。

ベン図

 {
  (A \cap B) \cup (\overline{A \cup B})
}

ド・モルガンの法則から

 {
  (A \cap B) \cup (\overline{A} \cap \overline{B})
}

とも表せる。

f:id:KazmaArakaki:20170618220327p:plain

回答1

public boolean monkeyTrouble(boolean aSmile, boolean bSmile) {
  if((aSmile && bSmile) || !(aSmile || bSmile)) {
    return true;
  }
  else {
    return false;
  }
}

回答2

public boolean monkeyTrouble(boolean aSmile, boolean bSmile) {
  return ((aSmile && bSmile) || !(aSmile || bSmile));
}

回答3

public boolean monkeyTrouble(boolean aSmile, boolean bSmile) {
  if((aSmile && bSmile) || (!aSmile && !bSmile)) {
    return true;
  }
  else {
    return false;
  }
}

回答4

public boolean monkeyTrouble(boolean aSmile, boolean bSmile) {
  return ((aSmile && bSmile) || (!aSmile && !bSmile));
}

kazmaarakaki.hatenablog.com

bundle.jsをminifyしてみる。【ver.4.1】

先の記事に載せたスクリーンショットの通り、現在bundle.jsのファイル容量が大きくなっている。

kazmaarakaki.hatenablog.com

ビルドされたbundle.jsの中身を確認すると、不要なコメントや改行が多く、minifyするだけでかなり圧縮できるものと思われる。

f:id:KazmaArakaki:20170618180512j:plain

Webpackの設定にminifyを追加する

Webpackでは、minifyするために追加のパッケージをインストールする必要はない。

設定ファイルにプラグインを追記してあげるだけでよい。

UglifyJsPluginを追加するだけだとレンダリング時にコンソールエラーが表示される。

内容はエラーというよりは警告に近く、「せっかくminifyするなら開発用じゃなくて本番用にビルドしなよ」ということである。

以下のページを参考に、DefinePluginで適切な値を設定したらエラーが表示されなくなった。

facebook.github.io

webpack.config.babel.js

import webpack from "webpack";
import path from "path";

export default {
  "entry": "./source/renderer/renderer.jsx",
  "output": {
    "filename": "bundle.js",
    "path": path.resolve(__dirname, "build")
  },
  "resolve": {
    "extensions": ["*", ".js", ".jsx"]
  },
  "plugins": [
    new webpack.DefinePlugin({
      "process.env": {
        NODE_ENV: JSON.stringify("production")
      }
    }),
    new webpack.optimize.UglifyJsPlugin()
  ],
  "module": {
    "loaders": [
      {
        "test": /\.jsx$/,
        "exclude": /node_modules/,
        "loader": ["babel-loader"]
      },
      {
        "test": /\.css/,
        "loaders": ["style-loader", "css-loader?modules"]
      }
    ]
  }
};

minifyの前後比較

BEFORE (920KB)

Version: webpack 2.5.1
Time: 2870ms
    Asset    Size  Chunks                    Chunk Names
bundle.js  920 kB       0  [emitted]  [big]  main
   [4] ./~/react/react.js 56 bytes {0} [built]
  [24] ./~/react/lib/React.js 3.32 kB {0} [built]
  [64] ./~/react-router-dom/es/index.js 925 bytes {0} [built]
 [100] ./~/react-dom/index.js 59 bytes {0} [built]
 [107] ./source/renderer/renderer.jsx 3.09 kB {0} [built]
 [149] ./~/react-dom/lib/ReactDOM.js 5.14 kB {0} [built]

 [206] ./~/react-router-dom/es/BrowserRouter.js 2.12 kB {0} [built]
 [207] ./~/react-router-dom/es/HashRouter.js 2.1 kB {0} [built]
 [208] ./~/react-router-dom/es/MemoryRouter.js 55 bytes {0} [built]
 [209] ./~/react-router-dom/es/NavLink.js 2.48 kB {0} [built]
 [210] ./~/react-router-dom/es/Prompt.js 49 bytes {0} [built]
 [211] ./~/react-router-dom/es/Redirect.js 51 bytes {0} [built]
 [212] ./~/react-router-dom/es/Route.js 48 bytes {0} [built]
 [213] ./~/react-router-dom/es/Router.js 49 bytes {0} [built]
 [214] ./~/react-router-dom/es/StaticRouter.js 55 bytes {0} [built]
    + 233 hidden modules

f:id:KazmaArakaki:20170618182830j:plain

AFTER (215KB)

Version: webpack 2.5.1
Time: 5366ms
    Asset    Size  Chunks             Chunk Names
bundle.js  215 kB       0  [emitted]  main
   [3] ./~/react/react.js 56 bytes {0} [built]
  [20] ./~/react/lib/React.js 3.32 kB {0} [built]
  [60] ./~/react-router-dom/es/index.js 925 bytes {0} [built]
  [88] ./~/react-router-dom/es/Link.js 3.82 kB {0} [built]
  [95] ./~/react-dom/index.js 59 bytes {0} [built]
 [102] ./source/renderer/renderer.jsx 3.09 kB {0} [built]
 [143] ./~/react-dom/lib/ReactDOM.js 5.14 kB {0} [built]
 [193] ./~/react-router-dom/es/BrowserRouter.js 2.12 kB {0} [built]
 [194] ./~/react-router-dom/es/HashRouter.js 2.1 kB {0} [built]
 [195] ./~/react-router-dom/es/MemoryRouter.js 55 bytes {0} [built]
 [196] ./~/react-router-dom/es/NavLink.js 2.48 kB {0} [built]
 [197] ./~/react-router-dom/es/Prompt.js 49 bytes {0} [built]
 [198] ./~/react-router-dom/es/Redirect.js 51 bytes {0} [built]
 [199] ./~/react-router-dom/es/Route.js 48 bytes {0} [built]
 [201] ./~/react-router-dom/es/StaticRouter.js 55 bytes {0} [built]
    + 220 hidden modules

f:id:KazmaArakaki:20170618183042j:plain