import * as TypeScript from 'typescript' ; import webpack = require ( "webpack" ) ; import chalk = require ( "chalk" ) ; import { Shout } from "../Shout" ; import { VoiceAssistant } from "../VoiceAssistant" ; import { prettyBytes , prettyMilliseconds } from "../PrettyUnits" ; import { BuildVariables } from "../variables-factory/BuildVariables" ; import { PathFinder } from "../variables-factory/PathFinder" ; export class InstapackBuildPlugin { variables : BuildVariables ; finder : PathFinder ; private va : VoiceAssistant ; languageTarget : TypeScript . ScriptTarget ; constructor ( variables , languageTarget ) { this . variables = variables ; this . finder = new PathFinder ( variables ) ; this . va = new VoiceAssistant ( variables . mute ) ; this . languageTarget = languageTarget ; } apply ( compiler ) { const t = TypeScript . ScriptTarget [ this . languageTarget ] . toUpperCase ( ) ; compiler . hooks . compile . tap ( 'typescript-compile-start' , ( ) => { Shout . timed ( 'Compiling' , chalk . cyanBright ( 'index.ts' ) , '>>' , chalk . yellowBright ( t ) , chalk . grey ( 'in ' + this . finder . jsInputFolder + '/' ) ) ; } ) ; if ( this . variables . production ) { compiler . hooks . compilation . tap ( 'typescript-minify-notify' , compilation => { compilation . hooks . afterHash . tap ( 'typescript-minify-notify' , ( ) => { Shout . timed ( 'TypeScript compilation finished! Minifying bundles...' ) ; } ) ; } ) ; } compiler . hooks . done . tapPromise ( 'display-build-results' , async ( stats ) => { const statsObject = stats . toJson ( this . statsSerializeEssentialOption ) ; this . displayBuildResults ( statsObject ) ; if ( statsObject . time ) { const t = prettyMilliseconds ( statsObject . time ) ; Shout . timed ( 'Finished JS build after' , chalk . greenBright ( t ) ) ; } else { Shout . timed ( 'Finished JS build.' ) ; } } ) ; } /**
     * Get stat objects required for instapack build logs.
     */ get statsSerializeEssentialOption ( ) : WebpackStatsOptions { return { assets : true , cached : false , cachedAssets : false , children : false , chunkModules : false , chunkOrigins : false , chunks : false , depth : false , entrypoints : false , env : false , errors : true , errorDetails : false , hash : false , modules : false , moduleTrace : true , publicPath : false , reasons : false , source : false , timings : true , version : false , warnings : true , usedExports : false , performance : false , providedExports : false } ; } formatError ( error ) { if ( typeof error === 'object' && error . stack ) { return `${ error . moduleId } (${ error . loc })\n ${ error . stack }` ; } else { return error ?. toString ( ) ; } } param stats displayBuildResults ( stats ) { if ( stats ?. errors ?. length ) { const errorMessage = stats . errors . map ( Q => this . formatError ( Q ) ) . join ( '\n\n' ) + '\n' ; Shout . error ( 'during JS build:' ) ; console . error ( chalk . redBright ( errorMessage ) ) ; this . va . speak ( `JAVA SCRIPT BUILD: ${ stats . errors . length } ERROR!` ) ; } else { this . va . rewind ( ) ; } if ( stats ?. warnings ?. length ) { const warningMessage = stats . warnings . map ( Q => this . formatError ( Q ) ) . join ( '\n\n' ) + '\n' ; Shout . warning ( 'during JS build:' ) ; console . warn ( chalk . yellowBright ( warningMessage ) ) ; } if ( stats . assets ) { for ( const asset of stats . assets ) { if ( asset . emitted ) { const kb = prettyBytes ( asset . size ) ; const where = `in ${ this . finder . jsOutputFolder }` ; Shout . timed ( chalk . blueBright ( asset . name ) , chalk . magentaBright ( kb ) , chalk . grey ( where ) ) ; } } } } }