使用Gulp和Docker NGINX映像为生产环境构建AngularJs

时间:2019-05-02 20:30:31

标签: angularjs docker nginx gulp production

预先感谢您的支持。

我有一个使用npm和bower构建的AngularJS Web应用程序,并且我有几个gulp脚本来构建该Web应用程序。

这是我的 package.json 脚本属性。

"scripts": {
    "serve": "gulp build & gulp serve:dev",
    "serve:build": "gulp serve:build",
    "build": "gulp build --mode=local"
  },

此外, package.json 主标记指向“ gulpfile.js”

"main": "gulpfile.js"

我的gulpfile.js如下:

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');

我的gulp.config.js

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;
};

我的gulp.bootstrap

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: '<!-- inject:templates:js -->'
      }))
    .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 --> CSS');

  return gulp.src(config.less)
    .pipe($.plumber())
    .pipe($.less())
    .pipe($.autoprefixer({
      browser: [
        'last 2 version',
        '> 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));
  }
}

现在,我可以使用npm run serve运行我的开发或本地服务器。但是,我的生产服务器为我提供了这一点:

enter image description here

您可以看到装载程序微调器正在工作,但并非页面中的所有内容都在构建中。另外,这是我的Dockerfile和entrypoint.sh。

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
#!/bin/bash
gulp build --mode=$NODE_ENV

nginx -g 'daemon off;'

我的docker ps

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->80/tcp                             frontend_1
16e2683d51bf        backend    "/bin/sh -c ./entryp…"   9 minutes ago       Up 9 minutes           0.0.0.0:3000->3000/tcp, 0.0.0.0:8443->8443/tcp   backend_1
c4f02481efce        nginx                        "/bin/bash -c 'nginx…"   About an hour ago   Up About an hour       0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp         nginx_web_1

我还有另一个配置为https的nginx docker映像, 看起来像这样。

location = / {
        proxy_pass      http://servers_internal_ip:8080/panel/client/index.html;
    }

我不确定这是怎么回事。如果是gulpfiles或nginx配置未指向正确的位置。

编辑: / build文件夹无法正确构建,请查看树输出。

├── 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

因此,我认为它不能正确编译我所有的javascript文件,并且它给我上面的错误。我所有最小的文件都在面板/客户端/中。生产文件应该作为gulpfile.js放在/ build上。另外,当我做docker exec -it containerid bash 我看不到任何/ build文件夹,只是项目的根目录。

1 个答案:

答案 0 :(得分:0)

在第2步中指定正确的缩小文件夹后,使用docker多阶段构建器模式缩小图像,如下所示:

FROM node:10-alpine 
RUN npm install -g gulp
RUN npm install -g bower
ARG environment
ENV PROFILE ${environment}
COPY . /app
WORKDIR /app
RUN npm  install --loglevel verbose
RUN gulp build --mode=${PROFILE}

FROM nginx:alpine as build
ADD ./nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=0 /app/{your minified folder} /usr/share/nginx/html