ありふれたdocker + gulpfile.js

## 実現したいこと
1. dockerを使用
1. typescriptのコンパイル
1. sassのコンパイル
1. ブラウザのautoリロード
1. bootstrap使いたい

## 最初に作成したgulpfile.js

```gulpfile.js
const { src, dest, watch, series, parallel } = require('gulp');
const sass = require('gulp-sass')(require('sass'));
const plumber = require("gulp-plumber");
const notify = require("gulp-notify"); 
const postcss = require("gulp-postcss");
const cssnext = require("postcss-cssnext");
const cleanCSS = require("gulp-clean-css");
const sourcemaps = require("gulp-sourcemaps");
const rename = require("gulp-rename");

//ブラウザリロード
var browserSync = require('browser-sync')
var browserify = require('gulp-browserify');


//typescript
const typescript = require("gulp-typescript").createProject("tsconfig.json");
const uglify = require("gulp-uglify");

//postcss-cssnext ブラウザ対応条件 prefix 自動付与
const browsers = [
    'last 2 versions',
    '> 5%',
    'ie = 11',
    'not ie <= 10',
    'ios >= 8',
    'and_chr >= 5',
    'Android >= 5',
];
const preprocessors =[ cssnext(browsers) ];
//参照元パス
const srcPath = {
    scss: './src/scss/*.scss',
    ts: './src/ts/*.ts',
}

//参照元パス
const destPath = {
    css: './www/html/lib/css',
    js: './www/html/lib/js',
    html: './www/html'
}

const cssSass = () => {
    return src(srcPath.scss)
    .pipe(sourcemaps.init())
    .pipe(sass({                                   // コンパイル実行（sass->css）
      includePaths: './node_modules/bootstrap/scss',
      outputStyle: 'expanded'
    }))
    .pipe(postcss( preprocessors ))//cssnext
    .pipe(plumber({
        errorHandler: notify.onError('Error:<%= error.message %>')
    }
    ))
    
    .pipe(sourcemaps.write('/maps'))  //ソースマップの出力
    .pipe(dest(destPath.css))
    .pipe(cleanCSS()) // CSS圧縮
    
}

//typescriptのコンパイル
const jsCompile = () => {
    return src(srcPath.ts)
      .pipe(
        plumber(              
          {
            errorHandler: notify.onError('Error: <%= error.message %>')
          }
        )
      )
      .pipe(typescript())
      .js
      .pipe(uglify({
        compress: {
          sequences: false
        }
      }))
      .pipe(rename("bundle.js"))
      .pipe(dest(destPath.js))
      
}

const initBrowser = () =>{
    let server = browserSync.init({
        proxy: 'localhost:<dockerのポート番号>',
        startPath : '/index.php'
    });
    return server;
}


const browserReload = () =>{
  browserSync.reload();
}

//ファイル監視
const watchFiles = () => {
    watch(srcPath.scss, series(cssSass,browserReload));
    watch(srcPath.ts, series(jsCompile,browserReload));
    watch("./www/html/*.php",series(browserReload));
}

exports.default = series(series(cssSass, jsCompile,initBrowser), watchFiles);
```

## 発生した問題
1. bootstrapでエラーが出ている
1. browser-syncが動かない
1. jsのエラーが発生する
1. dockerのサーバーのjs/cssがキャッシュ残ってる？

### bootstrapのcssでエラーが発生する問題について
:::note alert
Eror
postcss-custom-properties:~~~variable '--bs-border-radius-pill' is undefined and used without a fallback
:::

これは簡単でした。pipeの順番が間違っていました。

```gulpfile.js
const cssSass = () => {
    return src(srcPath.scss)
    .pipe(sourcemaps.init())
    .pipe(postcss( preprocessors )) //sassの前に移動　
    .pipe(sass({                                   // コンパイル実行（sass->css）
      includePaths: './node_modules/bootstrap/scss',
      outputStyle: 'expanded'
    }))
    
```
### browser-syncが動かない
browser-syncの初期化が完了していなかったことが原因なので、完了処理をいれる。
```gulpfile.js
const initBrowser = (done) =>{
    let server = browserSync.init({
        proxy: 'localhost:<dockerのポート番号>',
        startPath : '/all.php'
    });
    done();
    return server;
}
```

### jsのエラーが発生
::: note alert
Error
bundle.js:1 Uncaught ReferenceError: exports is not defined
:::

browserifyの導入を行う。

```gulpfile.js
const jsCompile = () => {
    return src(srcPath.ts)
      .pipe(
        plumber(              //エラーが出ても処理を止めない
          {
            errorHandler: notify.onError('Error: <%= error.message %>')
          }
        )
      )
      .pipe(typescript())
      .js
      .pipe(browserify({
        insertGlobals : true,
        debug:true
      }))
      .pipe(uglify({
        compress: {
          sequences: false
        }
      }))
      .pipe(rename("bundle.js"))
      .pipe(dest(destPath.js))
      
}
```
### dockerのキャッシュが残っているような気がする・・・
一応jsやcssにハッシュをつけておく
画像などにも付ける場合は、pipeで増やす。

```gulpfile.js
const addHash = () =>{
  return src([
    destPath.html+'/index.php'
  ])
  .pipe(replace('.css"','.css?' + hash + '"'))
  .pipe(replace('.js"','.js?' + hash + '"'))
}
```

### 上記の1~4までの問題を解決したgulpfile.js

```gulpfile.js
const { src, dest, watch, series, parallel } = require('gulp');
const sass = require('gulp-sass')(require('sass'));
const plumber = require("gulp-plumber");
const notify = require("gulp-notify"); 
const postcss = require("gulp-postcss");
const cssnext = require("postcss-cssnext");
const cleanCSS = require("gulp-clean-css");
const sourcemaps = require("gulp-sourcemaps");
const rename = require("gulp-rename");
const replace = require("gulp-replace");
const crypto = require('crypto'); 
const hash = crypto.randomBytes(8).toString('hex');


//ブラウザリロード
var browserSync = require('browser-sync')
var browserify = require('gulp-browserify');


//typescript
const typescript = require("gulp-typescript").createProject("tsconfig.json");
const uglify = require("gulp-uglify");

//postcss-cssnext ブラウザ対応条件 prefix 自動付与
const browsers = [
    'last 2 versions',
    '> 5%',
    'ie = 11',
    'not ie <= 10',
    'ios >= 8',
    'and_chr >= 5',
    'Android >= 5',
];
const preprocessors =[ cssnext(browsers) ];
//参照元パス
const srcPath = {
    scss: './src/scss/*.scss',
    ts: './src/ts/*.ts',
}

//参照元パス
const destPath = {
    css: './www/html/lib/css',
    js: './www/html/lib/js',
    html: './www/html'
}



const cssSass = () => {
    return src(srcPath.scss)
    .pipe(sourcemaps.init())
    .pipe(postcss( preprocessors ))//cssnext
    .pipe(sass({                                   // コンパイル実行（sass->css）
      includePaths: './node_modules/bootstrap/scss',
      outputStyle: 'expanded'
    }))
    .pipe(plumber({
        errorHandler: notify.onError('Error:<%= error.message %>')
    }
    ))
    
    .pipe(sourcemaps.write('/maps'))  //ソースマップの出力
    .pipe(dest(destPath.css))
    .pipe(cleanCSS()) // CSS圧縮
    
}

//typescriptのコンパイル
const jsCompile = () => {
    return src(srcPath.ts)
      .pipe(
        plumber(              
          {
            errorHandler: notify.onError('Error: <%= error.message %>')
          }
        )
      )
      .pipe(typescript())
      .js
      .pipe(browserify({
        insertGlobals : true,
        debug:true
      }))
      .pipe(uglify({
        compress: {
          sequences: false
        }
      }))
      .pipe(rename("bundle.js"))
      .pipe(dest(destPath.js))
      
}

const initBrowser = (done) =>{
    let server = browserSync.init({
        proxy: 'localhost:<dockerのポート番号>',
        startPath : '/index.php'
    });
    done();
    return server;
}

const addHash = () =>{
  return src([
    destPath.html+'/index.php'
  ])
  .pipe(replace('.css"','.css?' + hash + '"'))
  .pipe(replace('.js"','.js?' + hash + '"'))
}

const browserReload = () =>{
  browserSync.reload();
}

//ファイル監視
const watchFiles = () => {
    watch(srcPath.scss, series(cssSass,addHash,browserReload));
    watch(srcPath.ts, series(jsCompile,addHash,browserReload));
    watch("./www/html/*.php",series(addHash,browserReload));
}

exports.default = series(series(cssSass, jsCompile,addHash,initBrowser), watchFiles);

```


### 最後にもう一つ
browser-syncが１度しか動かない。
もう一箇所reload完了処理をいれるのを忘れてました。

```gulpfile.js
const browserReload = (done) =>{
  browserSync.reload();
  done();
}
```


## 完成したgulpfile

```gulpfile.js
const { src, dest, watch, series, parallel } = require('gulp');
const sass = require('gulp-sass')(require('sass'));
const plumber = require("gulp-plumber");
const notify = require("gulp-notify"); 
const postcss = require("gulp-postcss");
const cssnext = require("postcss-cssnext");
const cleanCSS = require("gulp-clean-css");
const sourcemaps = require("gulp-sourcemaps");
const rename = require("gulp-rename");
const replace = require("gulp-replace");
const crypto = require('crypto'); 
const hash = crypto.randomBytes(8).toString('hex');


//ブラウザリロード
var browserSync = require('browser-sync')
var browserify = require('gulp-browserify');


//typescript
const typescript = require("gulp-typescript").createProject("tsconfig.json");
const uglify = require("gulp-uglify");

//postcss-cssnext ブラウザ対応条件 prefix 自動付与
const browsers = [
    'last 2 versions',
    '> 5%',
    'ie = 11',
    'not ie <= 10',
    'ios >= 8',
    'and_chr >= 5',
    'Android >= 5',
];
const preprocessors =[ cssnext(browsers) ];
//参照元パス
const srcPath = {
    scss: './src/scss/*.scss',
    ts: './src/ts/*.ts',
}

//参照元パス
const destPath = {
    css: './www/html/lib/css',
    js: './www/html/lib/js',
    html: './www/html'
}



const cssSass = () => {
    return src(srcPath.scss)
    .pipe(sourcemaps.init())
    .pipe(postcss( preprocessors ))//cssnext
    .pipe(sass({                                   // コンパイル実行（sass->css）
      includePaths: './node_modules/bootstrap/scss',
      outputStyle: 'expanded'
    }))
    .pipe(plumber({
        errorHandler: notify.onError('Error:<%= error.message %>')
    }
    ))
    
    .pipe(sourcemaps.write('/maps'))  //ソースマップの出力
    .pipe(dest(destPath.css))
    .pipe(cleanCSS()) // CSS圧縮
    
}

//typescriptのコンパイル
const jsCompile = () => {
    return src(srcPath.ts)
      .pipe(
        plumber(              
          {
            errorHandler: notify.onError('Error: <%= error.message %>')
          }
        )
      )
      .pipe(typescript())
      .js
      .pipe(browserify({
        insertGlobals : true,
        debug:true
      }))
      .pipe(uglify({
        compress: {
          sequences: false
        }
      }))
      .pipe(rename("bundle.js"))
      .pipe(dest(destPath.js))
      
}

const initBrowser = (done) =>{
    let server = browserSync.init({
        proxy: 'localhost:<dockerのポート番号>',
        startPath : '/index.php'
    });
    done();
    return server;
}

const addHash = () =>{
  return src([
    destPath.html+'/index.php'
  ])
  .pipe(replace('.css"','.css?' + hash + '"'))
  .pipe(replace('.js"','.js?' + hash + '"'))
}

const browserReload = () =>{
  browserSync.reload();
  done();
}

//ファイル監視
const watchFiles = () => {
    watch(srcPath.scss, series(cssSass,addHash,browserReload));
    watch(srcPath.ts, series(jsCompile,addHash,browserReload));
    watch("./www/html/*.php",series(addHash,browserReload));
}

exports.default = series(series(cssSass, jsCompile,addHash,initBrowser), watchFiles);

```

## dockerの設定ファイル

```docker-compose.yml
version: "1"
services:
  app:
    build:
      context: "docker/app/"
    ports:
      - <dockerのポート番号>:80
    working_dir: /var/www
    volumes:
      - "./www/:/var/www"
      - "./docker/app/apache2/apache2.conf:/etc/apache2/apache2.conf"
      - "./docker/app/apache2/sites-available/000-default.conf:/etc/apache2/sites-available/000-default.conf"
volumes:
  storage:
```