UNPKG

littlejsengine

Version:

LittleJS - Tiny and Fast HTML5 Game Engine

253 lines (226 loc) 7.91 kB
/** * LittleJS Build System * - Concatenates engine source files into distributable bundles * - Generates multiple output formats (standard, ES6 module, minified) * - Creates debug and release builds (with/without debug code) * - Produces TypeScript definition file (.d.ts) * - Includes plugin files in builds * - Validates code and checks for errors * - Outputs to dist/ folder */ import fs from 'node:fs'; import { execSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; import { basename, dirname, join } from 'node:path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const ROOT_DIR = join(__dirname, '..'); const ENGINE_NAME = 'littlejs'; const BUILD_FOLDER = join(ROOT_DIR, 'dist'); const SOURCE_FOLDER = join(ROOT_DIR, 'src'); const PLUGIN_FOLDER = join(ROOT_DIR, 'plugins'); const engineSourceFiles = [ `${SOURCE_FOLDER}/engineMath.js`, `${SOURCE_FOLDER}/engineUtilities.js`, `${SOURCE_FOLDER}/engineSettings.js`, `${SOURCE_FOLDER}/engineObject.js`, `${SOURCE_FOLDER}/engineDraw.js`, `${SOURCE_FOLDER}/engineInput.js`, `${SOURCE_FOLDER}/engineAudio.js`, `${SOURCE_FOLDER}/engineTileLayer.js`, `${SOURCE_FOLDER}/engineParticles.js`, `${SOURCE_FOLDER}/engineWebGL.js`, `${SOURCE_FOLDER}/engineLogo.js`, ]; const enginePluginFiles = [ `${PLUGIN_FOLDER}/medalSystem.js`, `${PLUGIN_FOLDER}/newgrounds.js`, `${PLUGIN_FOLDER}/postProcess.js`, `${PLUGIN_FOLDER}/lightSystem.js`, `${PLUGIN_FOLDER}/zzfxm.js`, `${PLUGIN_FOLDER}/uiSystem.js`, `${PLUGIN_FOLDER}/box2d.js`, `${PLUGIN_FOLDER}/drawUtilities.js`, `${PLUGIN_FOLDER}/tweenSystem.js`, `${PLUGIN_FOLDER}/pathFinder.js`, `${PLUGIN_FOLDER}/threejs.js`, ]; const engineExtraFiles = [ `${PLUGIN_FOLDER}/box2d.wasm.js`, `${PLUGIN_FOLDER}/box2d.wasm.wasm`, ]; const asciiArt =` ~~~~°°°°ooo°oOo°ooOooOooOo. __________ ________ ____'°oO. |LittleJS| |Engine| |[]|_._Y .|________|_._|______|_._|__|_|_|} OOO OOO OO OO OO=OO-oo\\ `; const license = '// LittleJS Engine - MIT License - Copyright 2021 Frank Force\n'+ '// https://github.com/KilledByAPixel/LittleJS\n\n'; console.log(asciiArt); console.log('Choo Choo... Building LittleJS Engine!'); const startTime = Date.now(); try { // Setup build folder fs.rmSync(BUILD_FOLDER, { recursive: true, force: true }); fs.mkdirSync(BUILD_FOLDER); // copy extra files to build folder for (const file of engineExtraFiles) fs.copyFileSync(file, join(BUILD_FOLDER, basename(file))); } catch (e) { handleError(e, 'Failed to create build folder!'); } // Build all versions await buildAll(); console.log(`Engine built in ${((Date.now() - startTime)/1e3).toFixed(2)} seconds! ✨`); /////////////////////////////////////////////////////////////////////////////// async function buildAll() { // Build independent base versions in parallel await Promise.all([ Build ( 'Build Engine -- all', `${BUILD_FOLDER}/${ENGINE_NAME}.js`, [ `${SOURCE_FOLDER}/engine.js`, `${SOURCE_FOLDER}/engineDebug.js`, ...engineSourceFiles, ...enginePluginFiles ], [], true ), Build ( 'Build Engine -- release', `${BUILD_FOLDER}/${ENGINE_NAME}.release.js`, [ `${SOURCE_FOLDER}/engine.js`, `${SOURCE_FOLDER}/engineRelease.js`, ...engineSourceFiles, ...enginePluginFiles ], [], true ) ]); // Build dependent versions in parallel await Promise.all([ Build ( 'Build Engine -- minified', `${BUILD_FOLDER}/${ENGINE_NAME}.min.js`, [`${BUILD_FOLDER}/${ENGINE_NAME}.release.js`], [closureCompilerStep, uglifyBuildStep, addLicenseStep] ), Build ( 'Build Engine -- ESM', `${BUILD_FOLDER}/${ENGINE_NAME}.esm.js`, [ `${BUILD_FOLDER}/${ENGINE_NAME}.js`, `${SOURCE_FOLDER}/engineExport.js`, `${PLUGIN_FOLDER}/pluginExport.js` ], [typeScriptBuildStep] ), Build ( 'Build Engine -- ESM minified release', `${BUILD_FOLDER}/${ENGINE_NAME}.esm.min.js`, [ `${BUILD_FOLDER}/${ENGINE_NAME}.release.js`, `${SOURCE_FOLDER}/engineExport.js`, `${PLUGIN_FOLDER}/pluginExport.js` ], [uglifyBuildStep, addLicenseStep] ) ]); } /////////////////////////////////////////////////////////////////////////////// // A single build with its own source files, build steps, and output file // - each build step is a callback that accepts a single filename async function Build(message, outputFile, files=[], buildSteps=[], isPrimaryBuild) { console.log(message); // copy files into a buffer let buffer = ''; if (isPrimaryBuild) { // add license and strict mode to top buffer += license; buffer += `'use strict';\n\n`; } for (const file of files) { // get file content let fileContent = fs.readFileSync(file) + '\n'; // remove first 'use strict' and surrounding new lines if (isPrimaryBuild) fileContent = fileContent.replace(/'use strict';\s*\n/g, ''); // add it to the buffer buffer += fileContent; } // output file fs.writeFileSync(outputFile, buffer, {flag: 'w+'}); // execute build steps in order for (const buildStep of buildSteps) buildStep(outputFile); } // Process with Closure Compiler to minify and check for errors function closureCompilerStep(filename) { const filenameTemp = filename + '.tmp'; fs.copyFileSync(filename, filenameTemp); try { execSync(`npx google-closure-compiler --js=${filenameTemp} --js_output_file=${filename} --jscomp_off=*`); fs.rmSync(filenameTemp); } catch (e) { handleError(e, 'Failed to run Closure Compiler step!'); } } // Process with Uglify to minify function uglifyBuildStep(filename) { try { execSync(`npx uglifyjs ${filename} -o ${filename}`); } catch (e) { handleError(e,'Failed to run Uglify minification step!'); } }; // Add license to top of file function addLicenseStep(filename) { try { // add license to top of minified file let fileContent = fs.readFileSync(filename, 'utf8'); fileContent = license + fileContent; fs.writeFileSync(filename, fileContent); } catch (e) { handleError(e, 'Failed to add license to minified file!'); } }; // Build TypeScript definitions function typeScriptBuildStep(filename) { try { const tsFilename = join(BUILD_FOLDER, `${ENGINE_NAME}.d.ts`); execSync(`npx -p typescript tsc ${filename} --declaration --allowJs --emitDeclarationOnly --outFile ${tsFilename}`); // Make declare module part use the package name littlejsengine let fileContent = fs.readFileSync(tsFilename, 'utf8'); fileContent = fileContent.replace(`${ENGINE_NAME}\.esm`, 'littlejsengine') fs.writeFileSync(tsFilename, fileContent); } catch (e) { handleError(e, 'Failed to run TypeScript build step!'); } }; // display the error and exit function handleError(e,message) { console.error(e); console.error(message); process.exit(1); }