build.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. var fs = require("fs");
  2. var path = require("path");
  3. var argparse = require( "argparse" );
  4. var uglify = require("uglify-js");
  5. var spawn = require('child_process').spawn;
  6. var scriptDir = __dirname;
  7. var baseDir = path.resolve( scriptDir, '../..' );
  8. var includesDir = path.resolve( scriptDir, 'includes' );
  9. var externsDir = path.resolve( scriptDir, 'externs' );
  10. var compilerDir = path.resolve( scriptDir, 'compiler' );
  11. var defaultBuildDir = path.resolve( baseDir, 'build' );
  12. var amdPrefix = [
  13. 'function ( root, factory ) {',
  14. '\tif ( typeof define === \'function\' && define.amd ) {',
  15. '\t\tdefine( [ \'exports\' ], factory );',
  16. '\t} else if ( typeof exports === \'object\' ) {',
  17. '\t\tfactory( exports );',
  18. '\t} else {',
  19. '\t\tfactory( root );',
  20. '\t}',
  21. '}( this, function ( exports ) {',
  22. ''
  23. ].join('\n\n');
  24. var amdSuffix = 'exports.THREE = THREE;\n\n} ) );';
  25. function getMinifiedOutputPath( outputPath ) {
  26. var dir = path.dirname( outputPath );
  27. var ext = path.extname( outputPath );
  28. var basename = path.basename( outputPath, ext );
  29. var result = path.join( dir, basename + '.min' + ext );
  30. return result;
  31. }
  32. function main() {
  33. "use strict";
  34. var parser = new argparse.ArgumentParser();
  35. parser.addArgument( ['--include'], { action: 'append', required: true } );
  36. parser.addArgument( ['--externs'], { action: 'append', defaultValue: [ path.resolve( externsDir, 'common.js' ) ] } );
  37. parser.addArgument( ['--amd'], { action: 'storeTrue', defaultValue: false } );
  38. parser.addArgument( ['--minify'], { action: 'storeTrue', defaultValue: false } );
  39. parser.addArgument( ['--output'], { defaultValue: path.resolve( defaultBuildDir, 'three.js' ) } );
  40. parser.addArgument( ['--minifiedoutput'] );
  41. parser.addArgument( ['--sourcemaps'], { action: 'storeTrue', defaultValue: true } );
  42. var args = parser.parseArgs();
  43. var outputPath = args.output;
  44. var minifiedOutputPath = args.minifiedoutput ? args.minifiedoutput : getMinifiedOutputPath( outputPath );
  45. console.log('Building ' + outputPath + ':');
  46. var startMS = Date.now();
  47. var sourcemapPath = '';
  48. var sourcemapping = '';
  49. if ( args.sourcemaps ){
  50. sourcemapPath = minifiedOutputPath + '.map';
  51. sourcemapping = '\n//# sourceMappingURL=' + path.basename( minifiedOutputPath ) + '.map';
  52. }
  53. var buffer = [];
  54. var sources = []; // used for source maps with minification
  55. if ( args.amd ){
  56. buffer.push( amdPrefix );
  57. };
  58. console.log( ' Collecting source files.' );
  59. for ( var i = 0; i < args.include.length; i ++ ){
  60. var includeFile = args.include[i] + '.json';
  61. var contents = fs.readFileSync( path.resolve( includesDir, includeFile ), 'utf8' );
  62. var files = JSON.parse( contents );
  63. for ( var j = 0; j < files.length; j ++ ){
  64. var file = path.resolve( baseDir, files[ j ] );
  65. buffer.push('// File:' + files[ j ]);
  66. buffer.push('\n\n');
  67. contents = fs.readFileSync( file, 'utf8' );
  68. if( file.indexOf( '.glsl') >= 0 ) {
  69. contents = 'THREE.ShaderChunk[ \'' +
  70. path.basename( file, '.glsl' ) + '\' ] =' +
  71. JSON.stringify( contents ) + ';\n';
  72. }
  73. sources.push( { file: file, contents: contents } );
  74. buffer.push( contents );
  75. buffer.push( '\n' );
  76. }
  77. }
  78. if ( args.amd ){
  79. buffer.push( amdSuffix );
  80. };
  81. var temp = buffer.join( '' );
  82. // Write un-minified output
  83. console.log( ' Writing un-minified output: ' + outputPath );
  84. fs.writeFileSync( outputPath, temp, 'utf8' );
  85. if ( args.minify ) {
  86. console.log( ' Uglyifying.' );
  87. var LICENSE = "threejs.org/license";
  88. // Parsing
  89. var toplevel = null;
  90. toplevel = uglify.parse( '// ' + LICENSE + '\n' );
  91. sources.forEach( function( source ) {
  92. toplevel = uglify.parse( source.contents, {
  93. filename: source.file,
  94. toplevel: toplevel
  95. } );
  96. } );
  97. // Compression
  98. toplevel.figure_out_scope();
  99. var compressor = uglify.Compressor( {} );
  100. var compressed_ast = toplevel.transform( compressor );
  101. // Mangling
  102. compressed_ast.figure_out_scope();
  103. compressed_ast.compute_char_frequency();
  104. compressed_ast.mangle_names();
  105. // output file
  106. var source_map_options = {
  107. file: path.basename(minifiedOutputPath),
  108. root: 'src'
  109. };
  110. var source_map = uglify.SourceMap( source_map_options )
  111. var stream = uglify.OutputStream( {
  112. source_map: source_map,
  113. comments: new RegExp( LICENSE )
  114. } );
  115. compressed_ast.print( stream );
  116. var code = stream.toString();
  117. console.log( ' Writing minified output: ' + minifiedOutputPath );
  118. fs.writeFileSync( minifiedOutputPath, code + sourcemapping, 'utf8' );
  119. if ( args.sourcemaps ) {
  120. console.log( ' Writing source map.' );
  121. fs.writeFileSync( sourcemapPath, source_map.toString(), 'utf8' );
  122. }
  123. }
  124. var deltaMS = Date.now() - startMS;
  125. console.log( " --- Build time: " + ( deltaMS / 1000 ) + "s" );
  126. }
  127. main();