diff --git a/bin/v1/init.sh b/bin/v1/init.sh new file mode 100644 index 00000000..76d3b905 --- /dev/null +++ b/bin/v1/init.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +# Exit immediately if a command exits with a non-zero status. +set -e + +# Install root NPM dependencies +npm install + +# Clone missing repositories +./bin/clone-missing-repos.sh + +# Checkout the desired branch TODO: Change to phetsims-v1 +./bin/checkout-branch.sh main + +# Install NPM dependencies in 'perennial-alias' +cd ../perennial-alias +npm install + +# Install NPM dependencies in 'chipper' +cd ../chipper +npm install + +# Start transpiler and HTTP server concurrently +# Using & to run them in the background +../perennial-alias/bin/sage run js/grunt/tasks/transpile.ts --live & # Start transpiler + +# TODO: change to perennial +cd ../perennial-alias +npx http-server ../ -p 80 -c --silent & # Start HTTP server + +echo "######################################################" +echo "# Ready! Open http://localhost/phetmarks in your browser. Transpiler will output below." +echo "######################################################" + +# Wait for both background processes to keep the script running +wait \ No newline at end of file diff --git a/js/scripts/init-v1.ts b/js/scripts/init-v1.ts deleted file mode 100644 index eb3e2042..00000000 --- a/js/scripts/init-v1.ts +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright 2024, University of Colorado Boulder - -/** - * Script to clone repositories, install dependencies, transpile code, and start an HTTP server. - * - * The script performs the following steps: - * 1. Clones any missing repositories. - * 2. Installs NPM dependencies in specified directories. - * 3. Starts the transpiler (`grunt transpile --live`) and monitors its output. - * 4. Once initial transpiling is complete, starts the HTTP server (`http-server -p 80 -c`). - * 5. Handles process lifecycle to keep both the transpiler and HTTP server running. - * - * TODO: https://github.com/phetsims/chipper/issues/1345 - * "update-v1": "npm install && bash bin/sage run js/scripts/update-v1.ts && npm run start-v1", - * "start-v1": "npm install && bash bin/sage run js/scripts/start-v1.ts", - * - * @author Sam Reid (PhET Interactive Simulations) - */ - -import { ChildProcess, spawn } from 'child_process'; -import path from 'path'; -import cloneMissingRepos from '../common/cloneMissingRepos.js'; -import execute from '../common/execute.js'; -import npmCommand from '../common/npmCommand.js'; - -// Log initial messages -console.log( 'hello' ); -console.log( 'done cloning' ); - -// Configuration -const phetsimsDirectory = path.join( __dirname, '../../../' ); -const chipperDir = path.join( phetsimsDirectory, 'chipper' ); -const perennialAliasDir = path.join( phetsimsDirectory, 'perennial-alias' ); -const transpileCwd = path.join( phetsimsDirectory, 'chipper' ); - -// State variables to track transpiling progress -let totalChunks = 0; -let successfulChunks = 0; -let httpServerStarted = false; - -// References to child processes for graceful shutdown -let transpileProcess: ChildProcess | null = null; -let httpServerProcess: ChildProcess | null = null; - -/** - * Starts the HTTP server using `http-server`. - */ -/** - * Starts the HTTP server using `http-server` and ensures custom messages are printed last. - */ -function startHttpServer(): void { - console.log( '\nStarting http-server...\n' ); - - httpServerProcess = spawn( 'http-server', [ '..', '-p', '80', '-c' ], { - shell: true, - stdio: [ 'ignore', 'pipe', 'pipe' ] // Use 'pipe' to capture stdout and stderr - } ); - - // Listen to stdout data - if ( httpServerProcess.stdout ) { - httpServerProcess.stdout.on( 'data', data => { - const output = data.toString(); - - // Check if the server has started by looking for the specific message - if ( data.includes( 'Hit CTRL-C to stop the server' ) ) { - - process.stdout.write( output ); // Pipe to parent stdout - - // Print the custom message after the server has fully started - console.log( 'Open http://localhost/phetmarks in your browser to view the sims.' ); - } - } ); - } - - // Listen to stderr data and pipe to parent stderr - if ( httpServerProcess.stderr ) { - httpServerProcess.stderr.on( 'data', data => { - const errorOutput = data.toString(); - process.stderr.write( errorOutput ); - } ); - } - - // Handle HTTP server process events - httpServerProcess.on( 'error', error => { - console.error( 'HTTP server process error:', error ); - process.exit( 1 ); - } ); - - httpServerProcess.on( 'exit', ( code, signal ) => { - if ( code !== null ) { - console.log( `HTTP server exited with code ${code}` ); - process.exit( code ); - } - else { - console.log( `HTTP server was killed by signal ${signal}` ); - process.exit( 1 ); - } - } ); - - httpServerStarted = true; - - console.log( 'http server started' ); - // Remove the immediate console.log to prevent it from appearing before server messages - // console.log('Open http://localhost/phetmarks in your browser to view the sims.'); -} - -/** - * Starts the transpiler using `grunt transpile --live` and monitors its output. - */ -function startTranspiler(): void { - console.log( '\nStarting the transpiler...\n' ); - - transpileProcess = spawn( 'bash', [ '../perennial/bin/sage', 'run', 'js/grunt/tasks/transpile.ts', '--live' ], { - cwd: transpileCwd, - shell: true, - stdio: [ 'ignore', 'pipe', 'pipe' ] // Pipe stdout and stderr for monitoring - } ); - - // Handle transpiler process events - transpileProcess.on( 'error', error => { - console.error( 'Transpiler process error:', error ); - process.exit( 1 ); - } ); - - transpileProcess?.stdout?.on( 'data', data => { - const output = data.toString(); - process.stdout.write( `transpile: ${output}` ); - - // Parse the number of chunks - const splitMatch = output.match( /split into (\d+) chunks/ ); - if ( splitMatch && splitMatch[ 1 ] ) { - totalChunks = parseInt( splitMatch[ 1 ], 10 ); - console.log( `Detected ${totalChunks} chunks for transpiling.` ); - } - - // Parse successful compilations - const successMatch = output.includes( 'Watching' ); - if ( successMatch ) { - successfulChunks += 1; - console.log( `Chunk ${successfulChunks} compiled successfully.` ); - - // If all chunks are compiled, start the HTTP server - if ( totalChunks > 0 && successfulChunks === totalChunks && !httpServerStarted ) { - console.log( 'All chunks compiled successfully. Starting HTTP server...' ); - startHttpServer(); - } - } - } ); - - transpileProcess?.stderr?.on( 'data', data => { - const errorOutput = data.toString(); - process.stderr.write( `transpile stderr: ${errorOutput}` ); - } ); - - transpileProcess.on( 'exit', ( code, signal ) => { - if ( code !== 0 ) { - console.error( `Transpiler exited with code ${code} and signal ${signal}` ); - process.exit( code ); - } - else { - console.log( 'Transpiler exited successfully.' ); - process.exit( 0 ); - } - } ); -} - -/** - * Handles graceful shutdown of child processes upon receiving termination signals. - */ -function setupGracefulShutdown(): void { - const shutdown = () => { - console.log( '\nShutting down gracefully...' ); - - if ( transpileProcess ) { - transpileProcess.kill(); - } - - if ( httpServerProcess ) { - httpServerProcess.kill(); - } - - process.exit( 0 ); - }; - - // Listen for termination signals - process.on( 'SIGINT', shutdown ); - process.on( 'SIGTERM', shutdown ); -} - -/** - * Main asynchronous function to orchestrate cloning, installing, transpiling, and serving. - */ -( async () => { - try { - setupGracefulShutdown(); - - // Clone missing repositories - console.log( 'Cloning missing repositories...' ); - const cloned = await cloneMissingRepos( true ); - console.log( 'Cloned repositories:', cloned ); - - // Install NPM dependencies in ../chipper - console.log( '\nInstalling npm dependencies for chipper...' ); - await execute( npmCommand, [ 'install' ], chipperDir ); - console.log( 'NPM dependencies for chipper installed successfully.' ); - - // Install NPM dependencies in ../perennial-alias - console.log( '\nInstalling npm dependencies for perennial-alias...' ); - await execute( npmCommand, [ 'install' ], perennialAliasDir ); - console.log( 'NPM dependencies for perennial-alias installed successfully.' ); - - // Start the transpiler and monitor its output - startTranspiler(); - - // Keep the main process alive - await new Promise( () => { - // Do nothing, the process will be kept alive by the transpiler and HTTP server - } ); - } - catch( error ) { - console.error( 'An error occurred:', error ); - process.exit( 1 ); - } -} )(); \ No newline at end of file diff --git a/package.json b/package.json index 6777cc56..118c094f 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "type-check-all": "grunt type-check --all --clean", "lint-all": "grunt lint --all --clean", "scenerystack-test": "bash bin/sage run js/scripts/scenerystack-test.ts", - "init-v1": "npm install && bash bin/sage run js/scripts/init-v1.ts && npm run start-v1" + "init-v1": "bash bin/v1/init.sh" }, "devDependencies": { "@octokit/rest": "~16.33.1", @@ -46,6 +46,7 @@ "graceful-fs": "~4.1.11", "grunt": "~1.5.3", "html-differ": "~1.4.0", + "http-server": "^14.1.1", "lodash": "~4.17.10", "mimelib": "~0.2.19", "minimist": "~1.2.8",