amyloula
amyloula

Reputation: 1566

how to deploy mean.js to production?

I have built out a yeoman generator - mean.js app

I have set up an aws ec2 linux instance, I have installed nginx as server, I have set up node as proxy server I have set up ports I have use grunt to build out my dist folder which includes application.js, application.css, templates.js, vendor.js and vendor.css

I cannot run the site off these files locally or remotely, it only works if I use a dev environment and load the site of the 80 something individual js files, rather than my new uglified, concatenated production files so I am wondering what I am missing in my dist folder? (or in general)

I followed this tutorial : https://blog.dylants.com/2014/11/19/bundling-production-assets-for-mean-js/ As originally, on running grunt build, I only got an application.js and an application.css file

I try to run grunt prod and get

Warning: Task "jshint:all" failed. Used --force, continuing.

Running "eslint:target" (eslint) task

Running "csslint:all" (csslint) task
Warning: Unable to read ".csslintrc" file (Error code: ENOENT). Used --force, continuing.

Running "ngAnnotate:production" (ngAnnotate) task
>> 1 file successfully generated.

Running "loadConfig" task
Warning: angular is not defined Used --force, continuing.

Running "ngtemplates:mean" (ngtemplates) task
File public/dist/templates.js created.

Running "uglify:production" (uglify) task
>> 2 files created.

Running "cssmin:combine" (cssmin) task
>> 2 files created. 928.08 kB → 730.04 kB

Running "concat:production" (concat) task

Running "env:prod" (env) task

Running "mkdir:upload" task

Running "copy:localConfig" (copy) task


Running "concurrent:default" (concurrent) task
    Running "nodemon:dev" (nodemon) task
    Running "watch" task
    Waiting...
    [nodemon] 1.9.2
    [nodemon] to restart at any time, enter `rs`
    [nodemon] watching: server.js config/**/*.js modules/*/server/**/*.js
    [nodemon] starting `node --debug server.js`
    Debugger listening on port 5858

At the moment I have just cloned my whole repo to my instance, which I know is incorrect, and my cpu is at 8% and load time is at about 60 seconds. I am not sure what to do.

production.js

'use strict';

module.exports = {
  assets: {
    lib: {
        css: "public/dist/vendor.min.css",
        js: "public/dist/vendor.min.js"
    },
    css: "public/dist/application.min.css",
    js: [
        "public/dist/application.min.js",
        "public/dist/templates.min.js"
    ]
}
};

grunt file

'use strict';

/**
 * Module dependencies.
 */
var _ = require('lodash'),
  defaultAssets = require('./config/assets/default'),
  testAssets = require('./config/assets/test'),
  testConfig = require('./config/env/test'),
  fs = require('fs'),
  path = require('path');

module.exports = function (grunt) {
  // Project Configuration
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    env: {
      test: {
        NODE_ENV: 'test'
      },
      dev: {
        NODE_ENV: 'development'
      },
      prod: {
        NODE_ENV: 'production'
      },
      build: {
        NODE_ENV: 'build'  
      },
    },
    watch: {
      serverViews: {
        files: defaultAssets.server.views,
        options: {
          livereload: true
        }
      },
      serverJS: {
        files: _.union(defaultAssets.server.gruntConfig, defaultAssets.server.allJS),
        tasks: ['jshint'],
        options: {
          livereload: true
        }
      },
      clientViews: {
        files: defaultAssets.client.views,
        options: {
          livereload: true
        }
      },
      clientJS: {
        files: defaultAssets.client.js,
        tasks: ['jshint'],
        options: {
          livereload: true
        }
      },
      clientCSS: {
        files: defaultAssets.client.css,
        tasks: ['csslint'],
        options: {
          livereload: true
        }
      },
      clientSCSS: {
        files: defaultAssets.client.sass,
        tasks: ['sass', 'csslint'],
        options: {
          livereload: true
        }
      },
      clientLESS: {
        files: defaultAssets.client.less,
        tasks: ['less', 'csslint'],
        options: {
          livereload: true
        }
      }
    },
    nodemon: {
      dev: {
        script: 'server.js',
        options: {
          nodeArgs: ['--debug'],
          ext: 'js,html',
          watch: _.union(defaultAssets.server.gruntConfig, defaultAssets.server.views, defaultAssets.server.allJS, defaultAssets.server.config)
        }
      }
    },
    concurrent: {
      default: ['nodemon', 'watch'],
      debug: ['nodemon', 'watch', 'node-inspector'],
      options: {
        logConcurrentOutput: true
      }
    },
    jshint: {
      all: {
        src: _.union(defaultAssets.server.gruntConfig, defaultAssets.server.allJS, defaultAssets.client.js, testAssets.tests.server, testAssets.tests.client, testAssets.tests.e2e),
        options: {
          jshintrc: true,
          node: true,
          mocha: true,
          jasmine: true
        }
      }
    },
    eslint: {
      options: {},
      target: _.union(defaultAssets.server.gruntConfig, defaultAssets.server.allJS, defaultAssets.client.js, testAssets.tests.server, testAssets.tests.client, testAssets.tests.e2e)
    },
    csslint: {
      options: {
        csslintrc: '.csslintrc'
      },
      all: {
        src: defaultAssets.client.css
      }
    },
    ngtemplates: {
    options: {
        htmlmin: {
            collapseWhitespace: true,
            removeComments: true
        },
        url: function(url) {
            return url.replace('public', 'assets');
        },
        prefix: "/"
    },
    'mean': {
        src: 'modules/*/client/views/**/*.html',
        dest: 'public/dist/templates.js'
        }
    },  
    ngAnnotate: {
      production: {
        files: {
          'public/dist/application.js': defaultAssets.client.js
        }
      }
    },
    uglify: {
      production: {
        options: {
          mangle: false
        },
        files: {
          'public/dist/application.min.js': 'public/dist/application.js',
          'public/dist/templates.min.js': 'public/dist/templates.js'
        }
      }
    },
    cssmin: {
      combine: {
        files: {
          'public/dist/application.min.css': defaultAssets.client.css,
          'public/dist/vendor.min.css':  defaultAssets.client.lib.css //'config/assets/build.js/assets/lib/css/*.css' //'pubic/lib/**/*.css' //'<%= vendorCSSFiles %>'
        }
      }
    },
    concat: {
    production: {
        options: {
            stripBanners: true
        },
        files: {
            "public/dist/vendor.min.js":  defaultAssets.client.lib.js //'public/lib/**/*.js' //"<%= vendorJavaScriptFiles %>"
            }
        }
    },
    sass: {
      dist: {
        files: [{
          expand: true,
          src: defaultAssets.client.sass,
          ext: '.css',
          rename: function (base, src) {
            return src.replace('/scss/', '/css/');
          }
        }]
      }
    },
    less: {
      dist: {
        files: [{
          expand: true,
          src: defaultAssets.client.less,
          ext: '.css',
          rename: function (base, src) {
            return src.replace('/less/', '/css/');
          }
        }]
      }
    },
    'node-inspector': {
      custom: {
        options: {
          'web-port': 1337,
          'web-host': 'localhost',
          'debug-port': 5858,
          'save-live-edit': true,
          'no-preload': true,
          'stack-trace-limit': 50,
          'hidden': []
        }
      }
    },
    mochaTest: {
      src: testAssets.tests.server,
      options: {
        reporter: 'spec',
        timeout: 10000
      }
    },
    mocha_istanbul: {
      coverage: {
        src: testAssets.tests.server,
        options: {
          print: 'detail',
          coverage: true,
          require: 'test.js',
          coverageFolder: 'coverage/server',
          reportFormats: ['cobertura','lcovonly'],
          check: {
            lines: 40,
            statements: 40
          }
        }
      }
    },
    karma: {
      unit: {
        configFile: 'karma.conf.js'
      }
    },
    protractor: {
      options: {
        configFile: 'protractor.conf.js',
        noColor: false,
        webdriverManagerUpdate: true
      },
      e2e: {
        options: {
          args: {} // Target-specific arguments
        }
      }
    },
    copy: {
      localConfig: {
        src: 'config/env/local.example.js',
        dest: 'config/env/local.js',
        filter: function () {
          return !fs.existsSync('config/env/local.js');
        }
      }
    }
  });

  grunt.event.on('coverage', function(lcovFileContents, done) {
    // Set coverage config so karma-coverage knows to run coverage
    testConfig.coverage = true;
    require('coveralls').handleInput(lcovFileContents, function(err) {
      if (err) {
        return done(err);
      }
      done();
    });
  });

  // Load NPM tasks
  require('load-grunt-tasks')(grunt);
  grunt.loadNpmTasks('grunt-protractor-coverage');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-angular-templates');    
  //new code
  grunt.task.registerTask('loadConfig', 'Task that loads the config into a grunt option.', function() {
    var init = require('./modules/core/client/app/init.js')();
    var config = require('./config/config');

    grunt.config.set('vendorJavaScriptFiles', config.assets.lib.js);
    grunt.config.set('vendorCSSFiles', config.assets.lib.css);
    grunt.config.set('applicationJavaScriptFiles', config.assets.js);
    grunt.config.set('applicationCSSFiles', config.assets.css);
});
  //new code    
  // Make sure upload directory exists
  grunt.task.registerTask('mkdir:upload', 'Task that makes sure upload directory exists.', function () {
    // Get the callback
    var done = this.async();

    grunt.file.mkdir(path.normalize(__dirname + '/modules/users/client/img/profile/uploads'));

    done();
  });

  // Connect to the MongoDB instance and load the models
  grunt.task.registerTask('mongoose', 'Task that connects to the MongoDB instance and loads the application models.', function () {
    // Get the callback
    var done = this.async();

    // Use mongoose configuration
    var mongoose = require('./config/lib/mongoose.js');

    // Connect to database
    mongoose.connect(function (db) {
      done();
    });
  });

  // Drops the MongoDB database, used in e2e testing
  grunt.task.registerTask('dropdb', 'drop the database', function () {
    // async mode
    var done = this.async();

    // Use mongoose configuration
    var mongoose = require('./config/lib/mongoose.js');

    mongoose.connect(function (db) {
      db.connection.db.dropDatabase(function (err) {
        if (err) {
          console.log(err);
        } else {
          console.log('Successfully dropped db: ', db.connection.db.databaseName);
        }
        db.connection.db.close(done);
      });
    });
  });

  grunt.task.registerTask('server', 'Starting the server', function () {
    // Get the callback
    var done = this.async();

    var path = require('path');
    var app = require(path.resolve('./config/lib/app'));
    var server = app.start(function () {
      done();
    });
  });

  // Lint CSS and JavaScript files.
  grunt.registerTask('lint', ['sass', 'less', 'jshint', 'eslint', 'csslint']);

  // Lint project files and minify them into two production files.
  //grunt.registerTask('build', ['env:dev', 'lint', 'ngAnnotate', 'uglify', 'cssmin']);
  grunt.registerTask('build', ['env:build', 'lint', 'ngAnnotate', 'loadConfig', 'ngtemplates', 'uglify', 'cssmin', 'concat']);

  // Run the project tests
  grunt.registerTask('test', ['env:test', 'lint', 'mkdir:upload', 'copy:localConfig', 'server', 'mochaTest', 'karma:unit', 'protractor']);
  grunt.registerTask('test:server', ['env:test', 'lint', 'server', 'mochaTest']);
  grunt.registerTask('test:client', ['env:test', 'lint', 'karma:unit']);
  grunt.registerTask('test:e2e', ['env:test', 'lint', 'dropdb', 'server', 'protractor']);
  // Run project coverage
  grunt.registerTask('coverage', ['env:test', 'lint', 'mocha_istanbul:coverage', 'karma:unit']);

  // Run the project in development mode
  grunt.registerTask('default', ['env:dev', 'lint', 'mkdir:upload', 'copy:localConfig', 'concurrent:default']);

  // Run the project in debug mode
  grunt.registerTask('debug', ['env:dev', 'lint', 'mkdir:upload', 'copy:localConfig', 'concurrent:debug']);

  // Run the project in production mode
  grunt.registerTask('prod', ['build', 'env:prod', 'mkdir:upload', 'copy:localConfig', 'concurrent:default']);
};

I would appreciate any help, please and thank you!! :)

Upvotes: 2

Views: 765

Answers (1)

MarkusF
MarkusF

Reputation: 21

The main thing I'm seeing (compared to my own setup) is that ngAnnotate is called before loadConfig in task build. loadConfig instantiates some variables that are used later. I would reverse that order.

As for other ideas, I would first compare running grunt prod with the environment variable set to development and see if you're getting the same errors as with the production environment (e.g., 'Unable to read ".csslintrc" file', 'angular is not defined'). Then I would simplify your grunt tasks, e.g., try it without concat, without lint, etc.

Upvotes: 2

Related Questions