import * as fs from "fs"; import * as path from "path"; import { RJLog } from "../log/RJLog"; import { spawn } from "child_process"; export class PagesInfo { pages:string[] = []; } export class PHPServerSettings { phpPaths:string[] = [ "D:\\apps\\php\\php.exe", "C:\\apps\\php\\php.exe" ]; relativeWebPath:string; routerPath:string; port:number = 8081; } export class PHPPagesBuilder { inputDir:string; outputDir:string; static hasServer = false; constructor( source:string, build:string, settings:PHPServerSettings ) { this.inputDir = source; this.outputDir = build; this.startServer( settings ); } startServer( settings:PHPServerSettings ) { if ( settings == null ) { return; } if ( PHPPagesBuilder.hasServer ) { return; } PHPPagesBuilder.hasServer = true; let phpPath = PHPPagesBuilder.getPHPPath( settings ); if ( ! phpPath ) { RJLog.error( "PHP was not found!"); RJLog.error( "Ensure PHP is installed and the paths in the settings are configured correctly."); RJLog.log( "PHP paths from settings of '" + process.argv[ 2 ] + "': "); RJLog.log( '"' + settings.phpPaths.join( ", " ) + '"' ); return; } let workdingDir = process.cwd(); let webPath = path.join( workdingDir, settings.relativeWebPath ); let routerPath = path.join( webPath, "_router_.php" ); let port = settings.port; let spawnedProcess = spawn( phpPath,["-S", "0.0.0.0:" + port, routerPath, "-t", webPath ] ); spawnedProcess.stdout.on( "data", data => { console.log( data + "" ); } ); spawnedProcess.stderr.on( "data", data => { console.log( data + "" ); } ); spawnedProcess.on( 'error', (error) => { console.log(`error: ${error.message}`); }); spawnedProcess.on( "close", code => { console.log(`child process exited with code ${code}`); }); } static getPHPPath( settings:PHPServerSettings ) { for ( let path of settings.phpPaths ) { let exists = fs.existsSync( path ); if ( exists ) { RJLog.log( "Starting php server from:", path ); return path; } } return null; } filterFiles( fileName:string ) { if ( fileName.startsWith( "__" ) ) { return false; } return fileName.endsWith( ".html" ); } modify( content:string ) { return `\n${content}`; } apply( compiler:any ) { compiler.hooks.afterCompile.tapAsync( "PHPPagesBuilder", ( compilation:any, callback:any ) => { if ( fs.existsSync( this.inputDir ) ) { fs.readdirSync( this.inputDir ) .filter( this.filterFiles ) .forEach( ( file ) => { let fullPath = path.join(this.inputDir, file); compilation.fileDependencies.add(fullPath); // Mark for watching } ); } callback(); } ); compiler.hooks.emit.tapAsync( "PHPPagesBuilder", ( compilation:any, callback:any ) => { fs.readdir( this.inputDir, ( err, files ) => { if ( err ) { RJLog.log( "Error", this.inputDir ); return callback( err ); } let pages = new PagesInfo(); files.filter( this.filterFiles ).forEach( ( file ) => { let filePath = path.join( this.inputDir, file ); let content = fs.readFileSync( filePath, "utf-8" ); let modifiedContent = this.modify( content ); let phpFileName = file.replace( ".html", ".php" ); let outputFileName = path.join( this.outputDir, phpFileName ); pages.pages.push( phpFileName ); compilation.assets[ outputFileName ] = { source: () => modifiedContent, size: () => modifiedContent.length, }; } ); let pagesPath = path.join( this.outputDir, "pages.json" ); let pagesJSON = JSON.stringify( pages, null, " " ); compilation.assets[ pagesPath ] = { source: () => pagesJSON, size: () => pagesJSON.length, }; callback(); } ); } ); } }