docs: function outputFinalJsAsync(projectOptions, outDirs, jsModules) {
    // If it exists, will prepend the virtual base module to all root modules.
    var virtualBaseModuleFile = getVirtualBaseModuleFile(outDirs, jsModules);
    var tasks = [];
  
    jsModules.forEach(function(jsModule) {
      var outputFilePath = path.join(outDirs.build, jsModule.name + '.js');
  
      // The virtual base module is special. Check if we need to prepend any
      // uncompiled JS to it.
      if (jsModule.name == jsModuleManager.VIRTUAL_BASE_MODULE) {
        if (jsModule.dontCompileInputFiles.length == 0) {
          return;  // Nothing to do (virtualBaseModuleFile already complete).
        }
        outputFilePath = virtualBaseModuleFile;
      }
  
      // Write virtual base module (if needed), uncompiled JS files, and then
      // compiled JS (if any) to the final module output JS file.
      var inputFiles = isRootModuleWithVirtualBase(jsModule) ?
          [virtualBaseModuleFile] : [];
      inputFiles = inputFiles.concat(jsModule.dontCompileInputFiles);
      if (jsModule.compiledInputFiles.length > 0) {
        inputFiles.push(getModuleCompiledJsFile(jsModule.name, outDirs));
      }
  
      tasks.push(writeFinalModuleJsFile(inputFiles, outputFilePath));
    });
  
    return kew.all(tasks);
  }