[coldbox-3.8.1] Workflow/Conventions for ColdBox/Javascript Apps

Folks that are developing ColdBox apps that utilize Javascript libraries/frameworks like React, Backbone, Angular and are using tools like npm, grunt, gulp, bower – how are you structuring your ColdBox apps, specifically the JS portions? For example, if using a build workflow that is “compiling” your Javascript and managing all the JS dependencies, where are you keeping it while it is uncompiled and where is it going after it is compiled?

Has anyone come up with any conventions that work well? Should my project directory look something more like this?

MyProject/

  • bower_components/

  • node_modules/

  • app/ (The “uncompiled” version)

  • Application.cfc

  • index.cfm

  • box.json

  • config/

  • handlers/

  • models/

  • includes/

  • layouts

  • views/

  • dist/ (The compiled version after the build process, used then to deploy)

  • Application.cfc

  • index.cfm

  • box.json

  • config/

  • handlers/

  • models/

  • includes/

  • layouts

  • views/

  • packages.json

  • bower.json

  • gulpfile.js

At Ortus we use the following:

  • We use a .bowerrc to define our contributed JS libs and place them under /includes/lib
  • We use the custom JS under /includes/js
  • Grunt/Gulp will compile the custom ones under /includes/js

So we don’t have two folders like you have there. Just one root and our build processes manipulates them.

My Project

  • .bowerrc
  • box.json
  • packages.json
  • bower.json
  • gulpfile.js
  • /includes
  • /lib
  • /js
  • /css
  • /i18n
  • /fonts

Luis Majano
CEO
Ortus Solutions, Corp
www.ortussolutions.com
P/F: 1-888-557-8057
Direct: (909) 248-3408

ColdBox Platform: http://www.coldbox.org

ContentBox Platform: http://www.gocontentbox.org
Linked In: http://www.linkedin.com/pub/3/731/483

Social: twitter.com/ortussolutions | twitter.com/coldbox | twitter.com/lmajano | twitter.com/gocontentbox

I do use all of those (though gulp very infrequently), however I now use Grunt to consolidate and all minify Javascript - including OS frameworks and UDFs, in addition to SASS so that nothing in the bower_components or node_modules directories is deployed (unless there’s a need for node on the server).

I .gitignore node_modules and bower_components and then have a Gruntfile.js that looks something like this:

module.exports = function(grunt) {
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        watch: {
            sass: {
                files: ['includes/sass/compile/**/*.{scss,sass}','includes/sass/include/**/*.{scss,sass}'],
                tasks: ['sass:dist']
            },
            javascript: {
                files: 'includes/javascript/lib/**/*.js',
                tasks: ['uglify:mysite']
            },
            livereload: {
                files: ['css/*.css'],
                options: {
                    livereload: false
                }
            }
        },
        sass: {
            options: {
                sourceMap: true,
                outputStyle: 'compressed'
            },
            dist: {
                files: {
                    'includes/css/styles.css': 'includes/sass/compile/styles.scss'
                }
            }
        },
        uglify: {
            mysite:{
              options: {
                //beautify: true,
                //mangle: false,
                // the banner is inserted at the top of the output
                banner: '/*! MySite Core Libraries.  Generated: <%= grunt.template.today("dd-mm-yyyy") %> */\n'
              },
              files: {
                'includes/javascript/mysite.js': ['includes/javascript/_globals.js','includes/javascript/lib/**/*.js']
              }
            },
            libraries:{
                options:{
                    preserveComments: true,
                    banner: '/*! MySite Consolidated Open Source Libraries. Generated: <%= grunt.template.today("dd-mm-yyyy") %> */\n\n'
                },
                files: {
                    'mysite/javascript/lib.js':
                    [
                        'bower_components/jquery/dist/jquery.min.js',
                        'bower_components/bootstrap/dist/js/bootstrap.min.js',
                        'bower_components/jQuery.mmenu/src/js/jquery.mmenu.min.js',
                        'bower_components/arrive/src/arrive.js',
                        'bower_components/angular/angular.min.js',
                        'bower_components/angular-sanitize/angular-sanitize.min.js',
                        'js/media.js',
                        'includes/javascript/provider/gmaps.3.8.js',
                        'includes/javascript/provider/gmaps.infobubble.js',
                        'includes/javascript/provider/jquery.scrollto.js'    
                    ]
                }

            }

           
        }

    });
    grunt.registerTask('default', ['sass:dist', 'uglify', 'watch']);
    grunt.loadNpmTasks('grunt-sass');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-watch');
};

You can then publish your core javascript (don’t forget to retain the licensing comments!) and css files in directories that work with your conventions (I tend to use the Coldbox directory conventions for includes) and use npm and grunt only in development.

My SCSS file include the bower *-sass packages (i.e - bootstrap-sass and font-awesome-sass), though I do need to copy the FA font files over to the appropriate directory.

As Luis said, you can also configure .bowerrc to use a custom location. I tend to prefer the above because it keeps all of the dev packages completely separate from anything I plan to ship.

HTH,

Jon

Well that’s very clever and interesting. So while you’re working in, say, CFBuilder your project directory/structure looks sorta like below?

Are you saying you still place your pre-build custom JS files in /includes/js and grunt/gulp just builds/compiles them in place, adding/mixing in all the vendor/contrib stuff from /includes/lib? Thanks for your help, this is really interesting stuff.

MyProject/

  • /includes

  • /lib ← “vendor” libraries, stuff from other people on the net

  • /bower_components

  • /jquery

  • /react

  • /bootstrap

  • /node_modules

  • /gulp

  • /jshint-stylish

  • /browser-sync

  • /js ← Javascript custom code PLUS post-build vendor/contrib – all, compiled, linted, minified…etc

  • /css <- post-build CSS, compiled, minified

  • /config

  • /handlers

  • /models

  • /layouts

  • /views

  • Application.cfc

  • index.cfm

  • box.json

  • packages.json

  • bower.json

  • gulpfile.js

@Jon @Luis Super helpful, I really appreciate your time and thoughts right there.

Any chance to get one of those template on forgebox?

@Luis & @JClausen are you using Browserify, RequireJS or some other technology for JS dependency management? I’m trying to put all these helpful pieces in place before I am buried under a mountain of my own special spaghetti code.

For me the biggest purpose of minifying all of the JS in to two core files is primarily keep http calls for scripts down to 2 - 1 for third-party libs and one for application-specific libraries. Using Browserify or RequireJS would defeat that purpose as you’re now back to loading loading additional dependencies at runtime using document writes. I can see where that would be handy for when you need a specific library for only a segment of an application, though.

Between NPM’s package.json, bower.json, and box.json, I can pretty much have all my dependencies handled and, when I update the libraries, I just restart Grunt, and everything is recompiled in to those two core files anew. The Gruntfile handles the load order of those libraries by specifying the order in which they are minified.

That’s just my preference, though.

Jon,

Would you be interested in doing a ColdBox Connection on this topic. I think this is a fantastic topic to share? Nothing fancy, just practical. We can do something this or next week? Thoughts?

Luis Majano
CEO
Ortus Solutions, Corp
www.ortussolutions.com
P/F: 1-888-557-8057
Direct: (909) 248-3408

ColdBox Platform: http://www.coldbox.org

ContentBox Platform: http://www.gocontentbox.org
Linked In: http://www.linkedin.com/pub/3/731/483

Social: twitter.com/ortussolutions | twitter.com/coldbox | twitter.com/lmajano | twitter.com/gocontentbox

Sure, Luis. Be happy to. Just let me know when and I’ll be there.

Thanks,
Jon

Brad, let’s try to organize this.

Luis Majano
CEO
Ortus Solutions, Corp
www.ortussolutions.com
P/F: 1-888-557-8057
Direct: (909) 248-3408

ColdBox Platform: http://www.coldbox.org

ContentBox Platform: http://www.gocontentbox.org
Linked In: http://www.linkedin.com/pub/3/731/483

Social: twitter.com/ortussolutions | twitter.com/coldbox | twitter.com/lmajano | twitter.com/gocontentbox

Jon’s presentation on the topic: http://experts.adobeconnect.com/p9mdfocrbzs/

Thanks, Jon!

My pleasure. Thanks for letting me debug NPM for a couple of minutes while I kept you all waiting… Oops! :slight_smile:

Jon