1- import { execSync } from 'child_process' ;
1+ import { join } from 'path' ;
2+ import { spawn } from 'cross-spawn' ;
3+
4+ import * as Constants from './util/constants' ;
5+ import { copyFileAsync , getBooleanPropertyValue , generateRandomHexString , unlinkAsync } from './util/helpers' ;
26import { BuildContext , TaskInfo } from './util/interfaces' ;
37import { fillConfigDefaults , generateContext , getUserConfigFile } from './util/config' ;
48import { Logger } from './logger/logger' ;
59import { runWorker } from './worker-client' ;
610
11+
712export function closure ( context : BuildContext , configFile ?: string ) {
813 configFile = getUserConfigFile ( context , taskInfo , configFile ) ;
914
@@ -14,33 +19,110 @@ export function closure(context: BuildContext, configFile?: string) {
1419 logger . finish ( ) ;
1520 } )
1621 . catch ( err => {
22+ console . log ( 'err: ' , err ) ;
1723 throw logger . fail ( err ) ;
1824 } ) ;
1925}
2026
2127export function closureWorker ( context : BuildContext , configFile : string ) : Promise < any > {
28+ context = generateContext ( context ) ;
29+ const tempFileName = generateRandomHexString ( 10 ) + '.js' ;
30+ const tempFilePath = join ( context . buildDir , tempFileName ) ;
31+ const closureConfig = getClosureConfig ( context , configFile ) ;
32+ const bundleFilePath = join ( context . buildDir , process . env [ Constants . ENV_OUTPUT_JS_FILE_NAME ] ) ;
33+ return runClosure ( closureConfig , bundleFilePath , tempFilePath , context . buildDir , closureConfig . debug )
34+ . then ( ( ) => {
35+ const promises : Promise < any > [ ] = [ ] ;
36+ promises . push ( copyFileAsync ( tempFilePath , bundleFilePath ) ) ;
37+ promises . push ( copyFileAsync ( tempFilePath + '.map' , bundleFilePath + '.map' ) ) ;
38+ return Promise . all ( promises ) ;
39+ } ) . then ( ( ) => {
40+ // delete the temp bundle either way
41+ const promises : Promise < any > [ ] = [ ] ;
42+ promises . push ( unlinkAsync ( tempFilePath ) ) ;
43+ promises . push ( unlinkAsync ( tempFilePath + '.map' ) ) ;
44+ return Promise . all ( promises ) ;
45+ } ) . catch ( err => {
46+ // delete the temp bundle either way
47+ unlinkAsync ( tempFilePath ) ;
48+ unlinkAsync ( tempFilePath + '.map' ) ;
49+ throw err ;
50+ } ) ;
51+ }
52+
53+ function checkIfJavaIsAvailable ( closureConfig : ClosureConfig ) {
2254 return new Promise ( ( resolve , reject ) => {
23- context = generateContext ( context ) ;
24- Logger . warn ( 'Closer Compiler unsupported at this time.' ) ;
25- resolve ( ) ;
55+ const command = spawn ( `${ closureConfig . pathToJavaExecutable } ` , [ '-version' ] ) ;
56+
57+ command . stdout . on ( 'data' , ( buffer : Buffer ) => {
58+ Logger . debug ( `[Closure]: ${ buffer . toString ( ) } ` ) ;
59+ } ) ;
60+
61+ command . stderr . on ( 'data' , ( buffer : Buffer ) => {
62+ Logger . warn ( `[Closure]: ${ buffer . toString ( ) } ` ) ;
63+ } ) ;
64+
65+ command . on ( 'close' , ( code : number ) => {
66+ if ( code === 0 ) {
67+ return resolve ( ) ;
68+ }
69+ reject ( ) ;
70+ } ) ;
2671 } ) ;
2772}
2873
74+ function runClosure ( closureConfig : ClosureConfig , nonMinifiedBundlePath : string , minifiedBundleFileName : string , outputDir : string , isDebug : boolean ) {
75+ return new Promise ( ( resolve , reject ) => {
76+ const closureArgs = [ '-jar' , `${ closureConfig . pathToClosureJar } ` ,
77+ '--js' , `${ nonMinifiedBundlePath } ` ,
78+ '--js_output_file' , `${ minifiedBundleFileName } ` ,
79+ `--language_out=${ closureConfig . languageOut } ` ,
80+ '--language_in' , `${ closureConfig . languageIn } ` ,
81+ '--compilation_level' , `${ closureConfig . optimization } ` ,
82+ `--create_source_map=%outname%.map` ,
83+ `--variable_renaming_report=${ outputDir } /variable_renaming_report` ,
84+ `--property_renaming_report=${ outputDir } /property_renaming_report` ,
85+ `--rewrite_polyfills=false` ,
86+ ] ;
2987
30- export function isClosureSupported ( context : BuildContext ) : boolean {
31- /*const config = getClosureConfig(context, '');
32- try {
33- execSync(`${config.pathToJavaExecutable} --version`);
34- return true;
35- } catch (ex) {
36- Logger.debug('[Closure] isClosureSupported: Failed to execute java command');
37- return false;
88+ if ( isDebug ) {
89+ closureArgs . push ( '--debug' ) ;
90+ }
91+ const closureCommand = spawn ( `${ closureConfig . pathToJavaExecutable } ` , closureArgs ) ;
92+
93+ closureCommand . stdout . on ( 'data' , ( buffer : Buffer ) => {
94+ Logger . debug ( `[Closure] ${ buffer . toString ( ) } ` ) ;
95+ } ) ;
96+
97+ closureCommand . stderr . on ( 'data' , ( buffer : Buffer ) => {
98+ Logger . debug ( `[Closure] ${ buffer . toString ( ) } ` ) ;
99+ } ) ;
100+
101+ closureCommand . on ( 'close' , ( code : number ) => {
102+ if ( code === 0 ) {
103+ return resolve ( ) ;
104+ }
105+ reject ( new Error ( 'Closure failed with a non-zero status code' ) ) ;
106+ } ) ;
107+ } ) ;
108+ }
109+
110+
111+ export function isClosureSupported ( context : BuildContext ) : Promise < boolean > {
112+ if ( ! getBooleanPropertyValue ( Constants . ENV_USE_EXPERIMENTAL_CLOSURE ) ) {
113+ return Promise . resolve ( false ) ;
38114 }
39- */
40- return false ;
115+ Logger . debug ( '[Closure] isClosureSupported: Checking if Closure Compiler is available' ) ;
116+ const config = getClosureConfig ( context ) ;
117+ return checkIfJavaIsAvailable ( config ) . then ( ( ) => {
118+ return Promise . resolve ( true ) ;
119+ } ) . catch ( ( ) => {
120+ Logger . warn ( `Closure Compiler support is enabled but Java cannot be started. Try running the build again with the "--debug" argument for more information.` ) ;
121+ return Promise . resolve ( false ) ;
122+ } ) ;
41123}
42124
43- function getClosureConfig ( context : BuildContext , configFile : string ) : ClosureConfig {
125+ function getClosureConfig ( context : BuildContext , configFile ? : string ) : ClosureConfig {
44126 configFile = getUserConfigFile ( context , taskInfo , configFile ) ;
45127
46128 return fillConfigDefaults ( configFile , taskInfo . defaultConfigFile ) ;
@@ -59,4 +141,8 @@ export interface ClosureConfig {
59141 // https://developers.google.com/closure/compiler/docs/gettingstarted_app
60142 pathToJavaExecutable : string ;
61143 pathToClosureJar : string ;
144+ optimization : string ;
145+ languageOut : string ;
146+ languageIn : string ;
147+ debug : boolean ;
62148}
0 commit comments