gulp + webpack + babelをつかってみた

# はじめに
以前作ったこれ([文字列→塩基配列の相互変換ツールをつくってみた(アプリ版)](https://qiita.com/am10/items/3ecac20451c82133e900))の[Web版](https://adventam10.github.io/DNAConverter-web_vue/)でせっかくなんでよく聞くgulp, webpack, babelをつかってみました。色々みながらやりましたがバージョンの違いなどでエラー出まくってなかなか苦労しました。

あんまりwebさわったことないので間違ってたら優しく指摘していただけるとありがたいです。

とりあえず動くものはできました！！

# やりたいこと
* SassをCSSに変換
* CSS圧縮
* 画像圧縮
* js圧縮
* babelでjsをES5で出力
* webpackでjsをまとめる

[ソース](https://github.com/adventam10/DNAConverter-web_vue)

# 環境
* macOS Catalina 10.15.2
* node.js v13.7.0

# npm導入
[yarn](https://github.com/yarnpkg/yarn) ていうのもあるらしいですがとりあえず npm をインストール！

[node.js](https://nodejs.org/ja/) で最新版をいれました。

ターミナルで下記コマンドが実行できれば導入完了。

```
node -v
```

ターミナルでプロジェクトフォルダに移動し下記コマンドを実行し、 package.json を作成！

```
npm init -y
```

# gulp導入
下記コマンドで gulp を導入！

```
npm install -D gulp
```

gulp でやること

* SassをCSSに変換
* CSS圧縮
* 画像圧縮

下記コマンドで必要なやつを入れる！

```
npm install -D gulp-sass gulp-changed gulp-imagemin imagemin-pngquant imagemin-mozjpeg
```

* gulp-sass  
SassをCSSに変換/CSS圧縮用
* gulp-changed  
画像圧縮の際に差分のみやる用
* gulp-imagemin imagemin-pngquant imagemin-mozjpeg  
画像圧縮用

gulpfile.js を下記のように作成する。

```js:gulpfile.js
var gulp = require('gulp');
var sass = require('gulp-sass');
var changed  = require('gulp-changed');
var imagemin = require('gulp-imagemin');
var imageminPngquant = require("imagemin-pngquant");
var imageminMozjpeg = require("imagemin-mozjpeg");

var dist = './dist'; // 出力先

// sassをコンパイルしてcss圧縮
gulp.task('sass', function(done){
  gulp.src('./src/sass/*.scss')
    .pipe(sass({outputStyle: 'compressed'})) // 圧縮
    .pipe(gulp.dest(dist + '/css'));
  done();
});

// 圧縮前と圧縮後のディレクトリを定義
var paths = {
  srcDir : 'src',
  dstDir : dist
};

// いろんな拡張子を圧縮するためのオプション
var imageminOption = [
  imageminPngquant({ quality: [0.65, 0.8] }),
  imageminMozjpeg({ quality: 85 }),
  imagemin.gifsicle({
    interlaced: false,
    optimizationLevel: 1,
    colors: 256
  }),
  imagemin.optipng(),
  imagemin.svgo()
];

// 画像圧縮
gulp.task('imagemin', function(done){
  var srcGlob = paths.srcDir + '/**/*.+(jpg|jpeg|png|gif|svg)'; // 元画像
  var dstGlob = paths.dstDir; // 圧縮先
  gulp.src(srcGlob)
    .pipe(changed(dstGlob)) //差分のみ圧縮
    .pipe(imagemin(imageminOption))
    .pipe(gulp.dest(dstGlob));
  done();
});

gulp.task('default', gulp.series('sass', 'imagemin'), function(done) {
  done();
});
```

フォルダ構成

```
project/
  ├ src/
  │   ├ /sass
  │   │  └ index.scss
  │   └ /img
  │      └ image.png
  ├ dist/
  ├ gulpfile.js
  └ package.json
```

下記コマンドを実行！！

```
npx gulp
```
Sass を CSS に変換、CSS 圧縮、画像圧縮ができました:tada:

## ハマったとこ
### CSSの圧縮
最初は css の圧縮を gulp-minify-css でやろうとして、sass のコンパイル後に実行する方法がわからず...

結局 gulp-sass でオプションを設定するだけで圧縮までできました。

### 画像の圧縮
jpeg 画像圧縮を `imagemin.jpegtran({progressive: true})` で書いててエラーでつまりました。

`jpegtran` は使えない？みたいなエラーだったので imagemin-mozjpeg をいれました。

# webpack導入
webpackでやること

* js圧縮
* webpackでjsをまとめる

下記コマンドで必要なやつを入れる！

```
npm install -D webpack webpack-stream terser-webpack-plugin
```

* webpack-stream  
gulpでwebpackを使う用
* terser-webpack-plugin  
js圧縮用

webpack.config.js を下記のように作成する

```js:webpack.config.js
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  mode: 'production', // 本番用（開発ならdevelopment（圧縮されない））
  entry: './src/js/index.js', // バンドル前のやつのエントリポイント
  output: { // バンドル先
    filename: 'bundle.js',
    path: path.join(__dirname, 'dist/js')
  },
  optimization: {
        minimizer: [ // js圧縮
        new TerserPlugin({
            extractComments: 'all', // コメント削除
            terserOptions: {
                compress: {
                  drop_console: true, // console.log削除
                },
            },
        }),
      ],
    }
   };
```

js 圧縮参考：[Webpack 4 圧縮時にJavaScriptのコメントを全て削除する](https://www.monotalk.xyz/blog/Remove-all-JavaScript-comments-when-compressing-Webpack-4/)

フォルダ構成

```
project/
  ├ src/
  │   ├ /sass
  │   │  └ index.scss
  │   ├ /js
  │   │  ├ other.js 
  │   │  └ index.js
  │   └ /img
  │       └ image.png
  ├ dist/
  ├ gulpfile.js
  ├ webpack.config.js
  └ package.json
```

gulpfile.js に下記を追加する。

```js:gulpfile.js
var webpackStream = require("webpack-stream");
var webpack = require("webpack");
var webpackConfig = require("./webpack.config");

gulp.task("webpack", function(done){
  webpackStream(webpackConfig, webpack)
    .pipe(gulp.dest(dist + '/js'));
  done();
});

// webpack追加
gulp.task('default', gulp.series('sass'', 'imagemin', 'webpack), function(done) {
  done();
});
```

`npx gulp` でバンドルされる:tada:

## ハマったとこ
### jsの圧縮
* `UglifyJsPlugin` でやろうとしたら対応してなかった...
* `mode: 'development',` にしてたので圧縮されなかった...

### importとexport
`import * from モジュール` でモジュール内のやつが全部呼べると思ったがそんなことはなかった

`export default function test(){}` で `import Default from モジュール` で `export default` つけたやつ全部呼べると思ったけどそんなことはなかった（そもそも `export default` でエラーになる）

最終的には下記の様な感じで落ち着いた。

```js:test.js
export function testA() {
}

export function testB() {
}
```

```js:index.js
import {testA, testB} from './test';

testA();
testB();
```

import, export についてはもうちょっと勉強が必要:frowning2:

## 出力先
下記の `path: path.join(__dirname, 'dist/js')` のところが出力先だと思うのですが

```js:webpack.config.js
output: { // バンドル先
    filename: 'bundle.js',
    path: path.join(__dirname, 'dist/js')
  },
```

github pages で公開したかったのでフォルダ名を dist から docs に変えたのですが gulpfile.js だけ書き換えて webpack.config.js は dist のままでしたが docs/js にちゃんと bundle.js ができてました:thinking:

# babel導入
下記コマンドで必要なやつを入れる！

```
npm install -D webpack babel-loader @babel/core @babel/preset-env
```

webpack.config.js に下記を追加。

```js:webpack.config.js
optimization {
・
・
・
},
module: { // ここ追加
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: [
                '@babel/preset-env', // デフォルトでES5になるはず
              ]
            }
          }
        ]
      }
    ]
  }
```

`npx gulp` で ES5 で出力される:tada:

# インストールしたやつのバージョン
`npm install` したやつのバージョンを記載しておきます。

```js
"@babel/core": "^7.8.4",
"@babel/preset-env": "^7.8.4",
"babel-loader": "^8.0.6",
"gulp": "^4.0.2",
"gulp-changed": "^4.0.2",
"gulp-imagemin": "^7.1.0",
"gulp-sass": "^4.0.2",
"imagemin-mozjpeg": "^8.0.0",
"imagemin-pngquant": "^8.0.0",
"terser-webpack-plugin": "^2.3.4",
"webpack": "^4.41.5",
"webpack-stream": "^5.2.1"
```

# さいごに
前作ったやつは [XFREE](https://www.xfree.ne.jp/) のPHPサーバーで公開していたのですが、これ PHP いらなくね？と思いPHP の処理部分を js で置き換えてHTMLサーバーで公開しました。これで広告は出ない:clap:（が、まだhttp...）

PHP なくなったから github pages でいけるやんと思い完成したのがこちら

[https://adventam10.github.io/DNAConverter-web_vue/](https://adventam10.github.io/DNAConverter-web_vue/)

https!!:clap:

* [PHP版ソース](https://github.com/adventam10/DNAConverter-web)  
[WEBページ](http://adventam10.php.xdomain.jp/dna/index.php)
* [js版ソース](https://github.com/adventam10/DNAConverter-web_vue)  
[WEBページ](https://adventam10.github.io/DNAConverter-web_vue/)

せっかくなんでユニバーサルリンクとかやりたい

# 参考
* [最新版で学ぶwebpack 4入門 - Babel 7でES2020環境の構築（React, Vue, Three.js, jQueryのサンプル付き）](https://ics.media/entry/16028/)
* [Gulpで始めるwebpack 4入門](https://qiita.com/tonkotsuboy_com/items/2d4f3862e6d05dc0bea1)
* [Webpack 4 圧縮時にJavaScriptのコメントを全て削除する](https://www.monotalk.xyz/blog/Remove-all-JavaScript-comments-when-compressing-Webpack-4/)
* [GulpではじめるVue.js（最小構成）](https://qiita.com/yaaah93/items/be5a506a583b6cd17d68)
* [webpack 4 入門](https://qiita.com/soarflat/items/28bf799f7e0335b68186)