diff --git a/README.md b/README.md index 4de0cd8..0b21bb5 100644 --- a/README.md +++ b/README.md @@ -234,6 +234,38 @@ grunt.initConfig({ }); ``` +## Module Code Splitting + +Closure Compiler can split the output of a compilation into multiple files to support dynamic loading. This process uses the `--chunk` flag (before June 2018 it was named `--module`). See [how do I split my javascript into modules](https://stackoverflow.com/questions/10395810/how-do-i-split-my-javascript-into-modules-using-googles-closure-compiler/10401030#10401030) + +Modules can be stitched together without a module loading logic enabling to achieve optimal compression and optimization with the ability to load modules selectively. + +Source: https://github.com/google/closure-compiler/wiki/JS-Modules#code-splitting-output-modules + +```javascript +grunt.initConfig({ + 'closure-compiler': { + frontend: { + closurePath: '/src/to/closure-compiler', + modules: { + "module-name": { + src: ['js/source.js', 'js/other-source.js'] + }, + "extra-module": { + src: ['js/extra-module.js'], + dep: ['module-name'] + } + }, + moduleOutputPath: 'static/js/', + maxBuffer: 500, + options: { + compilation_level: 'ADVANCED_OPTIMIZATIONS', + language_in: 'ECMASCRIPT5_STRICT' + } + } + } +}); +``` ## Note diff --git a/tasks/closure-compiler.js b/tasks/closure-compiler.js index 17bc38e..2b407b8 100644 --- a/tasks/closure-compiler.js +++ b/tasks/closure-compiler.js @@ -36,25 +36,34 @@ module.exports = function(grunt) { var command = 'java -jar "' + closurePath + '/build/compiler.jar"'; data.cwd = data.cwd || './'; + + var output_mode; + + // --module mode + if ("modules" in data) { + output_mode = 'modules'; + } else { // --js mode + output_mode = 'js'; + + data.js = grunt.file.expand({cwd: data.cwd}, data.js); + + // Sanitize options passed. + if (!data.js.length) { + // This task requires a minima an input file. + grunt.warn('Missing js property.'); + return false; + } - data.js = grunt.file.expand({cwd: data.cwd}, data.js); - - // Sanitize options passed. - if (!data.js.length) { - // This task requires a minima an input file. - grunt.warn('Missing js property.'); - return false; - } - - // Build command line. - command += ' --js "' + data.js.join('" --js "') + '"'; + // Build command line. + command += ' --js "' + data.js.join('" --js "') + '"'; - if (data.jsOutputFile) { - if (!grunt.file.isPathAbsolute(data.jsOutputFile)) { - data.jsOutputFile = path.resolve('./') + '/' + data.jsOutputFile; + if (data.jsOutputFile) { + if (!grunt.file.isPathAbsolute(data.jsOutputFile)) { + data.jsOutputFile = path.resolve('./') + '/' + data.jsOutputFile; + } + command += ' --js_output_file "' + data.jsOutputFile + '"'; + reportFile = data.reportFile || data.jsOutputFile + '.report.txt'; } - command += ' --js_output_file "' + data.jsOutputFile + '"'; - reportFile = data.reportFile || data.jsOutputFile + '.report.txt'; } if (data.externs) { @@ -84,8 +93,34 @@ module.exports = function(grunt) { } } - // because closure compiler does not create dirs. - grunt.file.write(data.jsOutputFile, ''); + if (output_mode === 'js') { + // because closure compiler does not create dirs. + grunt.file.write(data.jsOutputFile, ''); + } else { // modules + + for (var module in data.modules) { + + // @todo add --define option for modules + //command += '" --define="DEBUG=false"'; + + data.modules[module].src.forEach(function(src) { + command += ' --js "' + src + '"'; + }); + + command += ' --chunk "' + module + ':' + data.modules[module].src.length + ':'; + + // add dependency + if (data.modules[module].dep) { + command += data.modules[module].dep.join(','); + command += ':'; + } + command += '"'; + } + + // module output directory + command += ' --module_output_path_prefix ' + data.moduleOutputPath; + + } // Minify WebGraph class. exec(command, { maxBuffer: data.maxBuffer * 1024, cwd: data.cwd }, function(err, stdout, stderr) {