title: AngularJs Build with Gulp and Docker NGINX Image for Production Environment
body: <p>Thank you in advance for your support. </p>
  
  <p>I have an AngularJS web app build with npm and bower, and I have a couple of gulp scripts to build the web app.</p>
  
  <p>This are my <strong>package.json</strong> scripts property.</p>
  
  <pre><code>"scripts": {
      "serve": "gulp build &amp; gulp serve:dev",
      "serve:build": "gulp serve:build",
      "build": "gulp build --mode=local"
    },
  </code></pre>
  
  <p>Also, the <strong>package.json</strong> main tag points to "gulpfile.js"</p>
  
  <pre><code>"main": "gulpfile.js"
  </code></pre>
  
  <p>my gulpfile.js is the following: </p>
  
  <pre><code>var gulp = require('gulp')
  var rename = require('gulp-rename');
  var template = require('gulp-template');
  var argv = require('yargs').argv;
  
  gulp.task('build', function(done) {
      mode = argv.mode || 'local';
      configs = require('./panel/client/js/configs/' + mode);
      return gulp.src(['./panel/client/js/configs/index.js'])
        .pipe(template(configs))
        .pipe(rename({basename: 'config'}))
        .pipe(gulp.dest('./panel/client/js/'));
  });
  
  
  require('./gulp.bootstrap');
  </code></pre>
  
  <p>my gulp.config.js </p>
  
  <pre><code>module.exports = function() {
    var client = './panel/client/';
    var root = './';
    var clientApp = client;
    var server = './node_modules/http-server/bin/';
    var temp = './.tmp/';
  
    var config = {
      temp: temp,
      alljs: [
        './panel/**/*.js',
        './*.js'
      ],
      browserReloadDelay: 1000,
      build: './build/',
      client: client,
      css: [
        temp + 'styles.css'
      ],
      fonts: [
        './bower_components/font-awesome/fonts/*.*',
        './bower_components/bootstrap/dist/fonts/*.*',
        './bower_components/simple-line-icons/fonts/*.*'
      ],
      html: '**/*.html',
      htmltemplates: clientApp + '**/*.html',
      images: [
        client + 'images/**/*.*'
      ],
      index: client + 'index.html',
      js: [
        clientApp + '**/*.module.js',
        clientApp + '**/*.js',
        '!' + clientApp + '**/*.spec.js'
      ],
      less: [
        client + '/styles/styles.less'
      ],
      optimized: {
        app: 'app.js',
        lib: 'lib.js'
      },
      root: root,
      server: server,
      bower: {
        json: require('./bower.json'),
        directory: './bower_components',
        ignorePath: '../..'
      },
      packages: [
        './package.json',
        './bower.json',
      ],
      templateCache: {
        file: 'templates.js',
        options: {
          module: 'core',
          standAlone: false,
          root: 'app/'
        }
      },
      defaultPort: 7203,
      nodeServer: './node_modules/http-server/bin/http-server',
  
    };
  
    config.getWiredepDefaultOptions = function() {
      var options = {
        bowerJson: config.bower.json,
        directory: config.bower.directory,
        ignorePath: config.bower.ignorePath
      };
  
      return options;
    };
  
    return config;
  };
  </code></pre>
  
  <p>my gulp.bootstrap</p>
  
  <pre><code>var gulp = require('gulp'),
    args = require('yargs').argv,
    config = require('./gulp.config')(),
    del = require('del'),
    browserSync = require('browser-sync'),
    port = process.env.PORT || config.defaultPort,
    $ = require('gulp-load-plugins')({ lazy: true });
  
  gulp.task('help', $.taskListing);
  
  gulp.task('default', ['opt']);
  
  gulp.task('opt', ['inject', 'fonts', 'images'], function() {
    log('Optimizing the javascript, css and html');
  
    var assets = $.useref.assets({ searchPath: './' });
    var cssFilter = $.filter('**/*.css');
    var jsLibFilter = $.filter('**/' + config.optimized.lib);
    var jsAppFilter = $.filter('**/' + config.optimized.app);
  
    var templateCache = config.temp + config.templateCache.file;
  
    return gulp.src(config.index)
      .pipe($.plumber())
      .pipe($.inject(
        gulp.src(templateCache, { read: false }), {
          starttag: '&lt;!-- inject:templates:js --&gt;'
        }))
      .pipe(assets)
      .pipe(cssFilter)
      .pipe($.csso())
      .pipe(cssFilter.restore())
      .pipe(jsLibFilter)
      .pipe($.uglify())
      .pipe(jsLibFilter.restore())
      .pipe(jsAppFilter)
      .pipe($.ngAnnotate())
      .pipe($.uglify())
      .pipe(jsAppFilter.restore())
      .pipe($.rev())
      .pipe(assets.restore())
      .pipe($.useref())
      .pipe($.revReplace())
      .pipe(gulp.dest(config.build))
      .pipe($.rev.manifest())
      .pipe(gulp.dest(config.build));
  });
  
  /**
   * Bump the version
   * --type=pre will bump the prerelease version *.*.*-x
   * --type=patch or no flag will bump the patch version *.*.x
   * --type=minor will bump the minor version *.x.*
   * --type=major will bump the major version x.*.*
   * --version=1.2.3 will bump to a specific version and ignore other flags
   */
  gulp.task('version', function() {
    var msg = 'Versioning';
    var type = args.type;
    var version = args.version;
    var options = {};
  
    if (version) {
      options.version = version;
      msg += ' to ' + version;
    } else {
      options.type = type;
      msg += ' for a ' + type;
    }
  
    log(msg);
  
    return gulp.src(config.packages)
      .pipe($.bump(options))
      .pipe(gulp.dest(config.root));
  });
  
  gulp.task('fonts', ['clean:fonts'], function() {
    log('Copying the Fonts');
  
    return gulp.src(config.fonts)
      .pipe(gulp.dest(config.build + 'fonts'));
  });
  
  gulp.task('images', ['clean:images'], function() {
    log('Copying the Images and Compressing them');
  
    return gulp.src(config.images)
      .pipe($.imagemin({ optimizationLevel: 4 }))
      .pipe(gulp.dest(config.build + 'images'));
  });
  
  gulp.task('serve:dev', ['inject'], function() {
    server(true);
  });
  
  gulp.task('serve:build', ['opt'], function() {
    server(false);
  });
  
  gulp.task('wiredep', function() {
    log('Wire up the bower css js and our app js into html');
    var options = config.getWiredepDefaultOptions();
    var wiredep = require('wiredep').stream;
  
    return gulp.src(config.index)
      .pipe(wiredep(options))
      .pipe($.inject(gulp.src(config.js)))
      .pipe(gulp.dest(config.client));
  });
  
  gulp.task('inject', ['wiredep', 'styles', 'templatecache'], function() {
    log('Wire up the app css into the html and call wiredep');
    return gulp.src(config.index)
      .pipe($.inject(gulp.src(config.css)))
      .pipe(gulp.dest(config.client));
  });
  
  gulp.task('watcher:less', function() {
    gulp.watch(config.less, ['styles']);
  });
  
  gulp.task('styles', ['clean:styles'], function() {
    log('Compiling Less --&gt; CSS');
  
    return gulp.src(config.less)
      .pipe($.plumber())
      .pipe($.less())
      .pipe($.autoprefixer({
        browser: [
          'last 2 version',
          '&gt; 5%'
        ]
      }))
      .pipe(gulp.dest(config.temp));
  });
  
  gulp.task('clean', function() {
    log('Cleaning Styles, Images and Fonts');
    var delconfig = [].concat(config.build, config.temp);
    clean(delconfig);
  });
  
  gulp.task('clean:fonts', function() {
    var files = config.build + 'fonts/**/*.*';
    clean(files);
  });
  
  gulp.task('clean:images', function() {
    var files = config.build + 'images/**/*.*';
    clean(files);
  });
  
  gulp.task('clean:styles', function() {
    var files = config.temp + '**/*.css';
    clean(files);
  });
  
  gulp.task('templatecache', ['clean:code'], function() {
    log('Creating AngularJS $templateCache');
  
    return gulp.src(config.htmltemplates)
      .pipe($.minifyHtml({ empty: true }))
      .pipe($.angularTemplatecache(
        config.templateCache.file,
        config.templateCache.options
      ))
      .pipe(gulp.dest(config.temp));
  });
  gulp.task('clean:code', function() {
    var files = [].concat(
      config.temp + '**/*.js',
      config.build + '**/*.html',
      config.build + 'js/**/*.js'
    );
    clean(files);
  });
  
  gulp.task('vet', function() {
    log('Analyzing source with JSHing and JSCS');
  
    return gulp.src(config.alljs)
      .pipe($.if(args.verbose, $.print()))
      .pipe($.jscs({ fix: true }))
      .pipe($.jscs.reporter())
      .pipe($.jscs.reporter('fail'))
      .pipe($.jshint())
      .pipe($.jshint.reporter('jshint-stylish', { verbose: true }))
      .pipe($.jshint.reporter('fail'));
  });
  
  function server(isDev) {
    var nodeOptions = {
      script: config.nodeServer,
      delayTime: 0,
      env: {
        'PORT': port,
        'NODE_ENV': isDev ? 'dev' : 'build'
      },
      watch: [config.server]
    };
  
    return $.nodemon(nodeOptions)
      .on('restart', ['vet'], function(ev) {
        log('*** nodemon restarted ***');
        log('files changed on restart:\n' + ev);
        setTimeout(function() {
          browserSync.notify('reloading now...');
          browserSync.reload({ stream: false });
        }, config.browserReloadDelay);
      })
      .on('start', function() {
        log('*** nodemon started ***');
        startBrowserSync(isDev);
      })
      .on('crash', function() {
        log('!!!!!!! nodemon CRASHED !!!!!');
      })
      .on('exit', function() {
        log('*** nodemon bye bye ***');
      });
  }
  
  function changeEvent(event) {
    var srcPattern = new RegExp('/.*(?=/' + config.source + ')/');
    log('File ' + event.path.replace(srcPattern, '') + ' ' + event.type);
  }
  
  function startBrowserSync(isDev) {
    if (args.nosync || browserSync.active) {
      return;
    }
  
    log('Starting browser-sync');
  
    if (isDev) {
      gulp.watch(config.less, ['styles'])
        .on('change', function(event) {
          changeEvent(event);
        });
    } else {
      gulp.watch([config.less, config.js, config.html], ['opt', browserSync.reload])
        .on('change', function(event) {
          changeEvent(event);
        });
    }
  
    var options = {
      proxy: 'localhost:' + port + (isDev ? '/panel/client' : '/build'),
      port: 9000,
      files: isDev ? [
        config.client + '**/*.*',
        '!' + config.less,
        config.temp + '**/*.css'
      ] : [],
      ghostMode: {
        clicks: true,
        location: false,
        forms: true,
        scroll: true
      },
      injectChanges: true,
      logFileChanges: true,
      logLevel: 'debug',
      logPrefix: 'Leonardo',
      notify: true,
      reloadDelay: 0
    };
  
    browserSync(options);
  }
  
  function clean(path) {
    log($.util.colors.red.bold('Cleaning: ' + path));
    del.sync(path);
  }
  
  function log(msg) {
    if (typeof(msg) === 'object') {
      for (var item in msg) {
        if (msg.hasOwnProperty(item)) {
          $.util.log($.util.colors.blue(msg[item]));
        }
      }
    } else {
      $.util.log($.util.colors.blue(msg));
    }
  }
  
  </code></pre>
  
  <p>Now I run my development or local server just fine with npm run serve. However, my production server gives me this:</p>
  
  <p><a href="https://i.stack.imgur.com/z11gC.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/z11gC.png" alt="enter image description here"></a></p>
  
  <p>You can see the loader spinner working, but not everything in the page is being build. Also, This is my Dockerfile and entrypoint.sh.</p>
  
  <pre><code>FROM nginx:1.14.0
  
  RUN apt-get update
  RUN apt-get install vim -y
  RUN apt-get install -y git
  RUN apt-get -y install g++
  RUN apt-get install build-essential -y
  
  RUN apt-get install curl -y
  
  RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -
  RUN apt-get install nodejs -y
  
  RUN npm install -g gulp
  RUN npm install -g bower
  
  WORKDIR /usr/share/nginx/html
  COPY package*.json /usr/share/nginx/html/
  #ADD package.json /usr/share/nginx/html
  
  RUN npm install
  
  ADD . /usr/share/nginx/html
  
  RUN bower install --allow-root -f
  
  ADD ./nginx.conf /etc/nginx/conf.d/default.conf
  
  RUN chmod a+x ./entrypoint.sh
  CMD ./entrypoint.sh
  </code></pre>
  
  <pre><code>#!/bin/bash
  gulp build --mode=$NODE_ENV
  
  nginx -g 'daemon off;'
  </code></pre>
  
  <p>My docker ps</p>
  
  <pre><code>CONTAINER ID        IMAGE                        COMMAND                  CREATED             STATUS                 PORTS                                            NAMES
  1ff42de7aab3        flex-frontend   "/bin/sh -c ./entryp…"   9 minutes ago       Up 9 minutes           0.0.0.0:8080-&gt;80/tcp                             frontend_1
  16e2683d51bf        backend    "/bin/sh -c ./entryp…"   9 minutes ago       Up 9 minutes           0.0.0.0:3000-&gt;3000/tcp, 0.0.0.0:8443-&gt;8443/tcp   backend_1
  c4f02481efce        nginx                        "/bin/bash -c 'nginx…"   About an hour ago   Up About an hour       0.0.0.0:80-&gt;80/tcp, 0.0.0.0:443-&gt;443/tcp         nginx_web_1
  </code></pre>
  
  <p>I have another nginx docker image with the configuration of https,
  which looks something like this.</p>
  
  <pre><code>location = / {
          proxy_pass      http://servers_internal_ip:8080/panel/client/index.html;
      }
  </code></pre>
  
  <p>I am not sure what is wrong here. If it is the gulpfiles or the nginx config not pointing to the right place.</p>
  
  <p>EDIT: 
  /build folder is not building correctly, please look at tree output.</p>
  
  <pre><code>├── fonts
  │   ├── FontAwesome.otf
  │   ├── Simple-Line-Icons.eot
  │   ├── Simple-Line-Icons.svg
  │   ├── Simple-Line-Icons.ttf
  │   ├── Simple-Line-Icons.woff
  │   ├── Simple-Line-Icons.woff2
  │   ├── fontawesome-webfont.eot
  │   ├── fontawesome-webfont.svg
  │   ├── fontawesome-webfont.ttf
  │   ├── fontawesome-webfont.woff
  │   ├── fontawesome-webfont.woff2
  │   ├── glyphicons-halflings-regular.eot
  │   ├── glyphicons-halflings-regular.svg
  │   ├── glyphicons-halflings-regular.ttf
  │   ├── glyphicons-halflings-regular.woff
  │   └── glyphicons-halflings-regular.woff2
  ├── index.html
  ├── js
  │   └── lib-b5b0862f96.js
  ├── rev-manifest.json
  └── styles
      └── lib-7f60b29f0b.css
  </code></pre>
  
  <p>Thus, I don't think it is compiling all my javascript files correctly and it gives me the error above. All my unminimized files are in panel/client/. Production files should go on /build as my gulpfile.js. Also, when I did <code>docker exec -it containerid bash</code>
  I couldn't see any /build folders, just the root of my project.</p>