diff --git a/.gitignore b/.gitignore index efc154d4c..912eb9794 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,9 @@ validation-status.json # Sauce Labs. because it's classified... SAUCE_API_KEY.yml +# Generated file from commonjs-test.js +test/commonjs-bundle.js + # Editors / IDEs .idea diff --git a/Gruntfile.js b/Gruntfile.js index dd7265c28..ddc72372d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -9,6 +9,10 @@ module.exports = function (grunt) { var semver = require('semver'); var currentVersion = require('./package.json').version; + var fs = require('fs'); + var path = require('path'); + var commonJSBundledReferenceModule = require('./grunt/commonjs-reference-module.js'); + // Project configuration. grunt.initConfig({ // Metadata @@ -70,6 +74,13 @@ module.exports = function (grunt) { } } }, + browserify: { + commonjs: { + files: { + 'test/commonjs-bundle.js': ['test/commonjs-test.js'], + } + } + }, clean: { dist: ['dist'], zipsrc: ['dist/fuelux'],// temp folder @@ -91,51 +102,50 @@ module.exports = function (grunt) { } }, concat: { - dist: { - files: { - // manually concatenate JS files (due to dependency management) - 'dist/js/fuelux.js': [ - 'js/checkbox.js', - 'js/combobox.js', - 'js/datepicker.js', - 'js/dropdown-autoflip.js', - 'js/loader.js', - 'js/placard.js', - 'js/radio.js', - 'js/search.js', - 'js/selectlist.js', - 'js/spinbox.js', - 'js/tree.js', - 'js/wizard.js', - - //items with dependencies on other controls - 'js/infinite-scroll.js', - 'js/pillbox.js', - 'js/repeater.js', - 'js/repeater-list.js', - 'js/repeater-thumbnail.js', - 'js/scheduler.js' - ] - }, - options: { - banner: '<%= banner %>' + '\n\n' + - '// For more information on UMD visit: https://github.com/umdjs/umd/' + '\n' + - '(function (factory) {' + '\n' + - '\tif (typeof define === \'function\' && define.amd) {' + '\n' + - '\t\tdefine([\'jquery\', \'bootstrap\'], factory);' + '\n' + - '\t} else {' + '\n' + - '\t\tfactory(jQuery);' + '\n' + - '\t}' + '\n' + - '}(function (jQuery) {\n\n' + - '<%= jqueryCheck %>' + - '<%= bootstrapCheck %>', - footer: '\n}));', - process: function (source) { - source = '(function ($) {\n\n' + - source.replace(/\/\/ -- BEGIN UMD WRAPPER PREFACE --(\n|.)*\/\/ -- END UMD WRAPPER PREFACE --/g, ''); - source = source.replace(/\/\/ -- BEGIN UMD WRAPPER AFTERWORD --(\n|.)*\/\/ -- END UMD WRAPPER AFTERWORD --/g, '') + '\n})(jQuery);\n\n'; - return source; - } + // manually concatenate JS files (due to dependency management) + fuelux: { + src: [ + 'js/checkbox.js', + 'js/combobox.js', + 'js/datepicker.js', + 'js/dropdown-autoflip.js', + 'js/loader.js', + 'js/placard.js', + 'js/radio.js', + 'js/search.js', + 'js/selectlist.js', + 'js/spinbox.js', + 'js/tree.js', + 'js/wizard.js', + + //items with dependencies on other controls + 'js/infinite-scroll.js', + 'js/pillbox.js', + 'js/repeater.js', + 'js/repeater-list.js', + 'js/repeater-thumbnail.js', + 'js/scheduler.js' + ], + dest: 'dist/js/<%= pkg.name %>.js' + }, + options: { + banner: '<%= banner %>' + '\n\n' + + '// For more information on UMD visit: https://github.com/umdjs/umd/' + '\n' + + '(function (factory) {' + '\n' + + '\tif (typeof define === \'function\' && define.amd) {' + '\n' + + '\t\tdefine([\'jquery\', \'bootstrap\'], factory);' + '\n' + + '\t} else {' + '\n' + + '\t\tfactory(jQuery);' + '\n' + + '\t}' + '\n' + + '}(function (jQuery) {\n\n' + + '<%= jqueryCheck %>' + + '<%= bootstrapCheck %>', + footer: '\n}));', + process: function (source) { + source = '(function ($) {\n\n' + + source.replace(/\/\/ -- BEGIN UMD WRAPPER PREFACE --(\n|.)*\/\/ -- END UMD WRAPPER PREFACE --/g, ''); + source = source.replace(/\/\/ -- BEGIN UMD WRAPPER AFTERWORD --(\n|.)*\/\/ -- END UMD WRAPPER AFTERWORD --/g, '') + '\n})(jQuery);\n\n'; + return source; } } }, @@ -215,7 +225,8 @@ module.exports = function (grunt) { globals: { jQuery: true, define: true, - require: true + require: true, + module: true }, immed: true, latedef: true, @@ -269,7 +280,8 @@ module.exports = function (grunt) { }, dist: { options: { - urls: ['http://localhost:<%= connect.testServer.options.port %>/test/?testdist=true'] + urls: ['http://localhost:<%= connect.testServer.options.port %>/test/?testdist=true', + 'http://localhost:<%= connect.testServer.options.port %>/test/commonjs.html'] } } }, @@ -533,8 +545,16 @@ module.exports = function (grunt) { // ZIP distribution task grunt.registerTask('distzip', 'Compress and zip "dist"', ['copy:zipsrc', 'compress', 'clean:zipsrc']); + // create dist/js/npm.js + grunt.registerTask('commonjs', 'Create CommonJS "bundled reference" module in `dist`', function () { + var files = grunt.config.get('concat.fuelux.src'); + var bundledReferenceFile = 'dist/js/npm.js'; + commonJSBundledReferenceModule(grunt, files, bundledReferenceFile); + }); + // Full distribution task - grunt.registerTask('dist', 'Build "dist." Contributors: do not commit "dist."', ['clean:dist', 'distcss', 'copy:fonts', 'distjs', 'distzip']); + grunt.registerTask('dist', 'Build "dist." Contributors: do not commit "dist."', + ['clean:dist', 'distcss', 'copy:fonts', 'distjs', 'commonjs', 'distzip']); /* ------------- @@ -550,7 +570,7 @@ module.exports = function (grunt) { //If qunit:source is working but qunit:full is breaking, check to see if the dist broke the code. This would be especially useful if we start mangling our code, but, is 99.99% unlikely right now grunt.registerTask('validate-dist', 'run qunit:source, dist, and then qunit:full', - ['connect:testServer', 'qunit:source', 'dist', 'qunit:dist']); + ['connect:testServer', 'qunit:source', 'dist', 'browserify:commonjs', 'qunit:dist']); // multiple jQuery versions, then run SauceLabs VMs grunt.registerTask('releasetest', 'run jshint, build dist, all source tests, validation, and qunit on SauceLabs', diff --git a/grunt/commonjs-reference-module.js b/grunt/commonjs-reference-module.js new file mode 100644 index 000000000..f340c4244 --- /dev/null +++ b/grunt/commonjs-reference-module.js @@ -0,0 +1,34 @@ +/*! + * Bootstrap Grunt task for the CommonJS module generation + * http://getbootstrap.com + * Copyright 2014-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +'use strict'; + +var fs = require('fs'); +var path = require('path'); + +var banner = '// This file has been created by the `commonjs` Grunt task.' + + ' You can require() this file in a CommonJS environment.\n' + + 'require(\'jquery\');\n' + + 'require(\'bootstrap\');\n\n'; + 'require(\'moment\');\n\n'; + +module.exports = function createBundledReferenceModule(grunt, files, destFile) { + var destDir = path.dirname(destFile); + + function srcPathToDestRequire(files) { + var requirePath = path.relative(destDir, files).replace(/\\/g, '/').replace(/\.js$/g, ''); + return 'require(\'' + requirePath + '\');'; + } + + var moduleOutputJs = banner + files.map(srcPathToDestRequire).join('\n'); + try { + fs.writeFileSync(destFile, moduleOutputJs); + } catch (err) { + grunt.fail.warn(err); + } + grunt.log.writeln('CommonJS Bundled Reference file created: ' + destFile.cyan); +}; \ No newline at end of file diff --git a/test/commonjs-test.js b/test/commonjs-test.js new file mode 100644 index 000000000..a479caf05 --- /dev/null +++ b/test/commonjs-test.js @@ -0,0 +1,73 @@ +window.$ = window.jQuery = require('jquery'); +var bootstrap = require('bootstrap'); +var moment = require('moment'); +var fuelux = require('../dist/js/npm'); +var QUnit = require('qunitjs'); + +// In order to be be UMD compliant, modules must work with +// CommonJS. The following tests check to see if the plugin +// is on the jQuery namespace and nothing else. + +test('combobox should be defined on jQuery object', function () { + ok($().combobox, 'combobox method is defined'); +}); + +test('datepicker should be defined on the jQuery object', function () { + ok($().datepicker, 'datepicker method is defined'); +}); + +test('dropdownautoflip should be defined on the jQuery object', function () { + ok($().dropdownautoflip, 'dropdownautoflip method is defined'); +}); + +test('infinitescroll should be defined on the jQuery object', function () { + ok($().infinitescroll, 'infinitescroll method is defined'); +}); + +test('loader should be defined on the jQuery object', function () { + ok($().loader, 'loader method is defined'); +}); + +test('pillbox should be defined on jQuery object', function () { + ok($().pillbox, 'pillbox method is defined'); +}); + +test('radio should be defined on jQuery object', function () { + ok($().radio, 'radio method is defined'); +}); + +test('repeater should be defined on jQuery object', function () { + ok($().repeater, 'repeater method is defined'); +}); + +test('repeater list should be defined on jQuery object', function () { + ok($.fn.repeater.viewTypes.list, 'repeater list view is defined'); +}); + +test('repeater thumbnail should be defined on jQuery object', function () { + ok($.fn.repeater.viewTypes.thumbnail, 'repeater thumbnail view is defined'); +}); + +test('scheduler should be defined on the jQuery object', function () { + ok($().scheduler, 'scheduler method is defined'); +}); + +test('search should be defined on jQuery object', function () { + ok($().search, 'search method is defined'); +}); + +test('selectlist should be defined on jQuery object', function () { + ok($().selectlist, 'selectlist method is defined'); +}); + +test('spinbox should be defined on jQuery object', function () { + ok($().spinbox, 'spinbox method is defined'); +}); + +test('tree should be defined on jQuery object', function () { + ok($().tree, 'tree method is defined'); +}); + +test('wizard should be defined on jQuery object', function () { + ok($().wizard, 'wizard method is defined'); +}); diff --git a/test/commonjs.html b/test/commonjs.html new file mode 100644 index 000000000..9aa5ae5a6 --- /dev/null +++ b/test/commonjs.html @@ -0,0 +1,21 @@ + + + + + FuelUX Component Initialization (via CommonJS) + + + +

Fuel UX CommonJS Test Suite

+ +

+ +
+

+
    +
    + + + + + \ No newline at end of file