I watched Paul Irish's talk announcing Yeoman (www.yeoman.io), and I'm hooked on the concept of running a continuous build environment. Not content to wait for a Yeoman invite, I tried Grunt and Brunch. Both install easily, and I can get new projects up and running with minimal effort.
I don't understand how one would migrate an existing project into either platform. My project uses a single namespace and uses two conventions for modules (one for instancing another for utility), each of which are wrapped in self-executing anonymous functions which export to the instance or the namespace.
I have at least 200 modules and many more simple, helper function exports to the namespace; so it is not at all efficient to use the console to create these in a grunt/brunch project and then manually import each module individually. Further, I'm using at least 15 different 3rd-party JavaScript tools. It is not clear to me how to bring these in.
What is the most efficient way to take a large, existing project and migrate it into Grunt/Brunch with the least amount of refactoring and support for arbitrary 3rd party tools?
Update: of the two, I've found Brunch a bit easier to cope with. If you use the stock "skeleton" (that is "template"--from the command line {in the folder you want the change to occur} execute "brunch new [project_name] --skeleton git://github.com/brunch/simple-js-skeleton.git") for pure JS, you get a new folder structure which is actually quite responsive. Anything you drop into to 'app' (your own code) or 'vendor' (3rd-party) folders will get automatically recompiled for you on file edit (when you run "brunch watch").
This is great, except. According the documentation, you control the order vendor scripts are compiled and concatenated together from the Brunch config.coffee file (JSON text file). Changes to this file seem to have no effect, thus you end up with 3rd party race conditions from plugins expecting other plugins.
Further, when you drop your own code into the auto-created 'app' folder you do get an auto-compiled, real-time, as-you-edit version of your code; but it's not accessible. Brunch obfuscates the window object, so my initial namespace declaration to window.myNameSpace fails and all subsequent library calls to the namespace fail as well. This has something to do with Brunch's module system, for which I can find no documentation.
I solved this by placing my namespace class in the 'vendor' folder, which ensured that it attached to the window object; however, now there is a race condition: my namespace isn't always available for all of my modules.
The problem is now this:
Once you have copied all of your internal and external libraries into a Brunch project, how do you configure the app to load them in a sane order?
This is a bit of an opus, but I finally figured it out. When I started with Brunch, it was not obvious how to make the first step: import my directory structure. It took me a few passes over the documentation, before it became obvious:
brunch new MyAppName -s https://github.com/damassi/Javascript-App-Skeleton
, which will generate a skeleton folder structure and config.coffee filefiles:
javascripts:
defaultExtension: 'js'
joinTo:
'javascripts/app.js': /^app/
'javascripts/vendor.js': /^vendor/
order:
before: [
'vendor/scripts/console-helper.js',
'vendor/scripts/jquery-1.7.1.min.js'
]
While Brunch is better out of the box than Grunt at the ease of using step 6, where it failed for me is the nature of compilation in Brunch. Every JavaScript file gets wrapped in a CommonJS module and the module name is based on the relative path and file name ('lib/core/ajax', etc.). The CommonJS philosophy is not for me, and the work involved in refactoring my library to use CommonJS is huge.
So, back to Grunt. Once I understood how to import a project into Brunch, importing into Grunt was a snap. I'm on windows, so all grunt calls use grunt.cmd.
grunt init:jquery
(this can be anywhere, I moved the created directory structure into my existing project folder)concat: {
dist: {
src: ['<config:lint.files>'],
dest: 'dist/<%= pkg.name %>.js'
}
},
min: {
dist: {
src: ['<banner:meta.banner>', '<config:concat.dist.dest>'],
dest: 'dist/<%= pkg.name %>.min.js'
}
},
qunit: {
files: ['test/**/*.html']
},
lint: {
files: ['grunt.js', 'src/**/*.js', 'test/**/*.js']
},
watch: {
files: '<config:lint.files>',
tasks: 'lint qunit'
}
grunt.registerTask('dev', 'server watch qunit');
and call grunt dev to get a server running with real-time, continuous build.<object/>
don't work, as they insert the content (in my case various <script/>
and <link/>
elements) into an Iframe, which of course breaks my module pattern (My namespace is in a different window object than the window object of the iframes). Fortunately, grunt's concat object is a multitask and it can concatenate anything. So I added my HTML files to concat, and my single-page app was ready to go.Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: X-Requested-With, X-Prototype-Version, Content-Type, Origin, Allow
Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS
Access-Control-Allow-Origin: http://localhost:88
xhrFields: {
withCredentials: true
}
Once I figured all of this out, Grunt seems to be working pretty well. I have not yet had a chance to begin testing the actual process of development in this new continuous build environment; but this is what it took to get to being able to start.
config.coffee
isn't really json rather than real js / coffeescript, but the order editing should work. Can you open an issue in brunch bugtracker with exact config order?
I don't think there's a fast way of rewriting your app to use modules rather than global window
variables. Globals are considered as a bad taste, by the way. But your solution could work, yep.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With