build.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /**
  2. * @fileOverview 负责合并amd modules为一个单文件。
  3. */
  4. 'use strict';
  5. var requirejs = require('requirejs'),
  6. fs = require('fs'),
  7. path = require('path');
  8. // convert relative path to absolute path.
  9. function convert( name, _path, contents ) {
  10. var rDefine = /(define\s*\(\s*('|").*?\2\s*,\s*\[)([\s\S]*?)\]/ig,
  11. rDeps = /('|")(.*?)\1/g,
  12. root = _path.substr( 0, _path.length - name.length - 3 ),
  13. dir = path.dirname( _path ),
  14. m, m2, deps, dep, _path2;
  15. contents = contents.replace( rDefine, function( m, m1, m2, m3 ) {
  16. return m1 + m3.replace( rDeps, function( m, m1, m2 ) {
  17. m2 = path.join( dir, m2 );
  18. m2 = path.relative( root, m2 );
  19. m2 = m2.replace(/\\/g, '/');
  20. return m1 + m2 + m1;
  21. }) + ']';
  22. });
  23. return contents;
  24. }
  25. module.exports = function( grunt ) {
  26. grunt.registerMultiTask( 'build', '合并amd modules为一个单文件', function() {
  27. var done = this.async(),
  28. options = this.options({
  29. banner: '',
  30. footer: '',
  31. process: null,
  32. builtin: {
  33. dollar: false,
  34. promise: false
  35. }
  36. }),
  37. pkg = grunt.config.get('pkg'),
  38. dest = this.data.dest,
  39. config, flag, custom;
  40. config = {
  41. baseUrl: 'src',
  42. name: '',
  43. out: '',
  44. // We have multiple minify steps
  45. optimize: 'none',
  46. // Include dependencies loaded with require
  47. findNestedDependencies: true,
  48. // Avoid breaking semicolons inserted by r.js
  49. skipSemiColonInsertion: true,
  50. wrap: {
  51. startFile: 'build/intro.js',
  52. endFile: 'build/outro.js'
  53. },
  54. rawText: {},
  55. onBuildWrite: function( name, _path ) {
  56. var compiled = convert.apply( null, arguments );
  57. if ( options.process ) {
  58. compiled = options.process( compiled, _path );
  59. }
  60. // 调整缩进
  61. compiled = compiled.replace( /(^|\r\n|\r|\n)/g, '$1 ');
  62. compiled = compiled.replace(/@version@/g, function() {
  63. return pkg.version;
  64. });
  65. return compiled;
  66. },
  67. paths: [],
  68. include: []
  69. };
  70. options = grunt.util._.extend( options, this.data );
  71. config.name = 'webuploader';
  72. if ( options.builtin.dollar ) {
  73. config.rawText.dollar = 'define([\n' +
  74. ' \'./dollar-builtin\'\n' +
  75. '], function( $ ) {\n' +
  76. ' return $;\n' +
  77. '});';
  78. }
  79. if ( options.builtin.promise ) {
  80. config.rawText.promise = 'define([\n' +
  81. ' \'./promise-builtin\'\n' +
  82. '], function( $ ) {\n' +
  83. ' return $;\n' +
  84. '});';
  85. }
  86. if ( this.data.preset === 'custom' ) {
  87. custom = [];
  88. this.files.forEach(function( file ) {
  89. var files = file.src,
  90. cwd = file.cwd || '';
  91. files.filter(function( filepath ) {
  92. filepath = path.join( cwd, filepath );
  93. // Warn on and remove invalid source files (if nonull was set).
  94. if (!grunt.file.exists(filepath)) {
  95. grunt.log.warn('Source file "' + filepath + '" not found.');
  96. return false;
  97. } else {
  98. return true;
  99. }
  100. }).forEach(function( filepath ) {
  101. custom.push( '\'' + filepath.replace( /\.\w+$/, '' ) + '\'' );
  102. });
  103. });
  104. custom.unshift('\'./base\'');
  105. custom = 'define([\n ' + custom.join(',\n ') + '\n], function( Base ) {\n return Base;\n});';
  106. config.rawText.webuploader = custom;
  107. } else if (this.data.preset) {
  108. config.rawText.webuploader = 'define([\n ' + ['\'./preset/' +
  109. this.data.preset +'\''].join(',\n ') +
  110. '\n], function( preset ) {\n return preset;\n});';
  111. } else {
  112. config.name = this.data.name;
  113. }
  114. // 处理最终输出
  115. config.out = function( compiled ) {
  116. var arr = [],
  117. banner = grunt.template.process(options.banner),
  118. footer = grunt.template.process(options.footer),
  119. sep = '\n\n';
  120. banner && arr.push( banner );
  121. if ( options.builtin.dollar ) {
  122. compiled = compiled.replace('define([ \'jquery\' ], exports );', 'define([], exports);');
  123. }
  124. arr.push(compiled);
  125. footer && arr.push( footer );
  126. // Write concatenated source to file
  127. grunt.file.write( dest, arr.join( sep ) );
  128. process.nextTick(function() {
  129. // requirejs有bug, callback不一定会执行,目前调试的结果是
  130. // prim的promise实现有问题。
  131. if ( flag ) return;
  132. grunt.log.ok( "File '" + dest + "' created." );
  133. done();
  134. flag = true;
  135. });
  136. };
  137. if (options.fis) {
  138. config.wrap = {
  139. startFile: 'build/fis/intro.js',
  140. endFile: 'build/fis/outro.js'
  141. }
  142. }
  143. requirejs.optimize( config, function( response ) {
  144. // requirejs有bug, callback不一定会执行,目前调试的结果是
  145. // prim的promise实现有问题。
  146. if ( flag ) return;
  147. grunt.verbose.writeln( response );
  148. grunt.log.ok( "File '" + name + "' created." );
  149. done();
  150. flag = true;
  151. }, function( err ) {
  152. done( err );
  153. });
  154. });
  155. };