From 9906397170d7f7067cc8936d494d58e99f59a7d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D1=97=D0=BB=20=D0=93=D1=80=D0=B8?= =?UTF-8?q?=D0=B3=D0=BE=D1=80=27=D1=94=D0=B2?= Date: Thu, 19 Jun 2025 04:51:34 +0300 Subject: [PATCH] Build tools cleanup pass (#81) * Fix tsconfig scopes affecting html.js Since it's quite hard to use a DOM library type there, remove the type entirely. * Remove environment variables check Nothing is using them anymore. It can be added back if needed later. * Refactor Texture Packer downloading Refactor local-config.js tasks file into a generic "environment" category consisting of checking if Java is installed, downloading the runnable Texture Packer if it's not yet downloaded and copying the local configuration template; update README accordingly. * Prepare environment only at postinstall Remove environment.prepare task from default build pipelines, add a postinstall script that calls the task, using environment.js as the gulpfile to speed it up. * Remove "docs" tasks and types generation script Remove tasks from docs.js as they are unlikely to do anything meaningful nowadays. Also remove the buildTypes script as it doesn't work anymore. A better solution will be provided in the future. * Simplify some globs Use additional gulp.src options instead of specifying more or complex globs. * Extract built-temp location to a variable Add the src/js/built-temp directory as a new variable in config.js, replace all existing references to built-temp with this variable. --- README.md | 9 +++----- gulp/buildutils.js | 19 +++++++--------- gulp/config.js | 17 +------------- gulp/docs.js | 36 ------------------------------ gulp/environment.js | 49 +++++++++++++++++++++++++++++++++++++++++ gulp/html.js | 17 +++++--------- gulp/image-resources.js | 38 ++++++++------------------------ gulp/local-config.js | 10 --------- gulp/sounds.js | 12 +++++----- gulp/standalone.js | 11 ++++----- gulp/tasks.js | 13 ++++------- gulp/translations.js | 8 +++---- package-lock.json | 2 +- package.json | 3 +-- tsconfig.json | 2 +- 15 files changed, 94 insertions(+), 152 deletions(-) delete mode 100644 gulp/docs.js create mode 100644 gulp/environment.js delete mode 100644 gulp/local-config.js diff --git a/README.md b/README.md index b449a4c7..e5109242 100644 --- a/README.md +++ b/README.md @@ -56,20 +56,17 @@ and does not intend to provide compatibility for older clients. ### Prerequisites -- [ffmpeg](https://www.ffmpeg.org/download.html) - [Node.js](https://nodejs.org) +- [ffmpeg](https://www.ffmpeg.org/download.html) for audio transcoding - [Java](https://www.oracle.com/java/technologies/downloads/) (or [OpenJDK](https://openjdk.org/)) to run the texture packer -- [cURL](https://curl.se/download.html)[^1] to download the texture packer - -[^1]: cURL is already installed on most Windows, Linux and macOS systems. ### Development - Run `npm i` in the root folder and in `electron/`. - Run `npm run gulp` in the root folder to build and serve files. If a new browser tab opens, ignore it. -- Open a new terminal and run `npm run start` in `electron/` to open an Electron window. - - Use `npm run start -- --dev` to run in development mode. +- Open a new terminal and run `npm start` in `electron/` to open an Electron window. + - Use `npm start -- --dev` to run in development mode. - Tip: If you open the Electron window too early, you can reload it when focused on DevTools. ### Release diff --git a/gulp/buildutils.js b/gulp/buildutils.js index 85101b2f..f2900df1 100644 --- a/gulp/buildutils.js +++ b/gulp/buildutils.js @@ -3,20 +3,17 @@ import fs from "fs"; export function getRevision(useLast = false) { const commitHash = execSync("git rev-parse --short " + (useLast ? "HEAD^1" : "HEAD")).toString("ascii"); - return commitHash.replace(/^\s+|\s+$/g, ""); + return commitHash.trim(); } export function getAllResourceImages() { - return fs - .globSync("res/**/*.@(png|svg|jpg)", { cwd: ".." }) - .map(f => f.replace(/^res\//gi, "")) - .filter(f => { - if (f.indexOf("ui") >= 0) { - // We drop all ui images except for the noinline ones - return f.indexOf("noinline") >= 0; - } - return true; - }); + return fs.globSync("./**/*.@(png|svg|jpg)", { cwd: "../res" }).filter(f => { + if (f.indexOf("ui") >= 0) { + // We drop all ui images except for the noinline ones + return f.indexOf("noinline") >= 0; + } + return true; + }); } export function getVersion() { diff --git a/gulp/config.js b/gulp/config.js index bd9204a2..5555de69 100644 --- a/gulp/config.js +++ b/gulp/config.js @@ -4,6 +4,7 @@ import path from "path/posix"; export const baseDir = path.resolve(".."); export const buildFolder = path.join(baseDir, "build"); export const buildOutputFolder = path.join(baseDir, "build_output"); +export const generatedCodeFolder = path.join(baseDir, "src/js/built-temp"); // Globs for atlas resources export const rawImageResourcesGlobs = ["../res_raw/atlas.json", "../res_raw/**/*.png"]; @@ -20,19 +21,3 @@ export const imageResourcesGlobs = [ ]; export const browserSync = BrowserSync.create(); - -// Check environment variables - -const envVars = [ - "SHAPEZ_CLI_SERVER_HOST", - "SHAPEZ_CLI_APPLE_ID", - "SHAPEZ_CLI_APPLE_CERT_NAME", - "SHAPEZ_CLI_GITHUB_USER", - "SHAPEZ_CLI_GITHUB_TOKEN", -]; - -for (let i = 0; i < envVars.length; ++i) { - if (!process.env[envVars[i]]) { - console.warn("Unset environment variable, might cause issues:", envVars[i]); - } -} diff --git a/gulp/docs.js b/gulp/docs.js deleted file mode 100644 index 821133c4..00000000 --- a/gulp/docs.js +++ /dev/null @@ -1,36 +0,0 @@ -import path from "path/posix"; -import fs from "fs/promises"; -import gulp from "gulp"; - -import gulpRename from "gulp-rename"; -import stripJsonComments from "strip-json-comments"; - -export function convertJsToTs() { - return gulp - .src(path.join("..", "src", "js", "**", "*.js")) - .pipe( - gulpRename(path => { - path.extname = ".ts"; - }) - ) - .pipe(gulp.dest(path.join("..", "tsc_temp"))); -} - -export async function copyTsconfigForHints() { - const src = (await fs.readFile(path.join("..", "src", "tsconfig.json"))).toString(); - const baseConfig = JSON.parse(stripJsonComments(src)); - - baseConfig.allowJs = false; - baseConfig.checkJs = false; - baseConfig.declaration = true; - baseConfig.noEmit = false; - baseConfig.strict = false; - baseConfig.strictFunctionTypes = false; - baseConfig.strictBindCallApply = false; - baseConfig.alwaysStrict = false; - baseConfig.composite = true; - baseConfig.outFile = "bundled-ts.js"; - await fs.writeFile(path.join("..", "tsc_temp", "tsconfig.json"), JSON.stringify(baseConfig)); -} - -export const prepareDocs = gulp.series(convertJsToTs, copyTsconfigForHints); diff --git a/gulp/environment.js b/gulp/environment.js new file mode 100644 index 00000000..f5ab22b0 --- /dev/null +++ b/gulp/environment.js @@ -0,0 +1,49 @@ +import { exec } from "child_process"; +import fs from "fs/promises"; +import gulp from "gulp"; +import { promisify } from "util"; + +const texturePackerUrl = + "https://libgdx-nightlies.s3.amazonaws.com/libgdx-runnables/runnable-texturepacker.jar"; + +const configTemplatePath = "../src/js/core/config.local.template.js"; +const configPath = "../src/js/core/config.local.js"; + +export async function checkJava() { + try { + const { stderr } = await promisify(exec)("java -version"); + console.log(`Found Java:`, stderr); + } catch { + throw new Error("Java is required to build the texture atlas, but was not found"); + } +} + +export async function downloadTexturePacker() { + const destination = "./runnable-texturepacker.jar"; + + try { + // If the file exists already, we're done + await fs.access(destination); + return; + } catch { + // File does not exist, need to download + } + + console.log(`Downloading ${destination}...`); + const response = await fetch(texturePackerUrl); + if (!response.ok) { + throw new Error(`Failed to download Texture Packer: ${response.statusText}`); + } + + await fs.writeFile(destination, response.body); +} + +export async function createLocalConfig() { + try { + await fs.copyFile(configTemplatePath, configPath, fs.constants.COPYFILE_EXCL); + } catch { + // The file is already there + } +} + +export const prepare = gulp.parallel(gulp.series(checkJava, downloadTexturePacker), createLocalConfig); diff --git a/gulp/html.js b/gulp/html.js index e00c5d1b..62074891 100644 --- a/gulp/html.js +++ b/gulp/html.js @@ -17,17 +17,11 @@ async function buildHtml() { return gulp .src("../src/html/index.html") .pipe( - gulpDom( - /** @this {Document} **/ function () { - const document = this; - - let loadingCss = fs.readFileSync(path.join("preloader", "preloader.css")).toString(); - - const style = document.createElement("style"); - style.textContent = loadingCss; - document.head.appendChild(style); - } - ) + gulpDom(function () { + const style = this.createElement("style"); + style.textContent = fs.readFileSync(path.join("preloader", "preloader.css"), "utf-8"); + this.head.appendChild(style); + }) ) .pipe( gulpHtmlmin({ @@ -39,7 +33,6 @@ async function buildHtml() { minifyJS: true, minifyCSS: true, quoteCharacter: '"', - useShortDoctype: true, }) ) .pipe(gulpRename("index.html")) diff --git a/gulp/image-resources.js b/gulp/image-resources.js index d3431bab..507e1f94 100644 --- a/gulp/image-resources.js +++ b/gulp/image-resources.js @@ -1,8 +1,7 @@ -import fs from "fs/promises"; -import path from "path/posix"; import gulp from "gulp"; -import { buildFolder } from "./config.js"; +import path from "path/posix"; import atlas2Json from "./atlas2json.js"; +import { buildFolder } from "./config.js"; import childProcess from "child_process"; import { promisify } from "util"; @@ -15,18 +14,14 @@ const execute = command => { return promise; }; -import gulpImagemin from "gulp-imagemin"; -import imageminJpegtran from "imagemin-jpegtran"; -import imageminGifsicle from "imagemin-gifsicle"; -import imageminPngquant from "imagemin-pngquant"; -import gulpIf from "gulp-if"; import gulpCached from "gulp-cached"; import gulpClean from "gulp-clean"; -import { nonImageResourcesGlobs, imageResourcesGlobs } from "./config.js"; - -// Link to download LibGDX runnable-texturepacker.jar -const runnableTPSource = - "https://libgdx-nightlies.s3.eu-central-1.amazonaws.com/libgdx-runnables/runnable-texturepacker.jar"; +import gulpIf from "gulp-if"; +import gulpImagemin from "gulp-imagemin"; +import imageminGifsicle from "imagemin-gifsicle"; +import imageminJpegtran from "imagemin-jpegtran"; +import imageminPngquant from "imagemin-pngquant"; +import { imageResourcesGlobs, nonImageResourcesGlobs } from "./config.js"; // Lossless options const minifyImagesOptsLossless = () => [ @@ -85,21 +80,6 @@ export async function buildAtlas() { const dest = JSON.stringify("../res_built/atlas"); try { - // First check whether Java is installed - await execute("java -version"); - // Now check and try downloading runnable-texturepacker.jar (22MB) - try { - await fs.access("./runnable-texturepacker.jar"); - } catch { - const escapedLink = JSON.stringify(runnableTPSource); - - try { - await execute(`curl -o runnable-texturepacker.jar ${escapedLink}`); - } catch { - throw new Error("Failed to download runnable-texturepacker.jar!"); - } - } - await execute(`java -jar runnable-texturepacker.jar ${source} ${dest} atlas0 ${config}`); } catch { console.warn("Building atlas failed. Java not found / unsupported version?"); @@ -113,7 +93,7 @@ export async function atlasToJson() { // Copies the atlas to the final destination export function atlas() { - return gulp.src(["../res_built/atlas/*.png"]).pipe(gulp.dest(resourcesDestFolder)); + return gulp.src("../res_built/atlas/*.png").pipe(gulp.dest(resourcesDestFolder)); } // Copies the atlas to the final destination after optimizing it (lossy compression) diff --git a/gulp/local-config.js b/gulp/local-config.js deleted file mode 100644 index 365abce8..00000000 --- a/gulp/local-config.js +++ /dev/null @@ -1,10 +0,0 @@ -import fs from "fs/promises"; - -const configTemplatePath = "../src/js/core/config.local.template.js"; -const configPath = "../src/js/core/config.local.js"; - -export async function findOrCreate() { - try { - await fs.copyFile(configTemplatePath, configPath, fs.constants.COPYFILE_EXCL); - } catch {} -} diff --git a/gulp/sounds.js b/gulp/sounds.js index 184a424a..be0bd3ba 100644 --- a/gulp/sounds.js +++ b/gulp/sounds.js @@ -1,12 +1,12 @@ -import path from "path/posix"; import gulp from "gulp"; -import { buildFolder } from "./config.js"; +import path from "path/posix"; +import { buildFolder, generatedCodeFolder } from "./config.js"; import gulpAudiosprite from "gulp-audiosprite"; -import gulpClean from "gulp-clean"; import gulpCache from "gulp-cache"; -import gulpPlumber from "gulp-plumber"; +import gulpClean from "gulp-clean"; import gulpFluentFfmpeg from "gulp-fluent-ffmpeg"; +import gulpPlumber from "gulp-plumber"; // Gather some basic infos const soundsDir = path.join("..", "res_raw", "sounds"); @@ -110,9 +110,7 @@ export function sfxOptimize() { .pipe(gulp.dest(path.join(builtSoundsDir))); } export function sfxCopyAtlas() { - return gulp - .src([path.join(builtSoundsDir, "sfx.json")]) - .pipe(gulp.dest(path.join("..", "src", "js", "built-temp"))); + return gulp.src([path.join(builtSoundsDir, "sfx.json")]).pipe(gulp.dest(generatedCodeFolder)); } export const sfx = gulp.series(sfxGenerateSprites, sfxOptimize, sfxCopyAtlas); diff --git a/gulp/standalone.js b/gulp/standalone.js index af6ea75e..038916cb 100644 --- a/gulp/standalone.js +++ b/gulp/standalone.js @@ -27,13 +27,10 @@ export default Object.fromEntries( } function copyPrefab() { - const requiredFiles = [ - path.join(electronBaseDir, "preload.cjs"), - path.join(electronBaseDir, "node_modules", "**", "*.*"), - path.join(electronBaseDir, "node_modules", "**", ".*"), - path.join(electronBaseDir, "favicon*"), - ]; - return gulp.src(requiredFiles, { base: electronBaseDir }).pipe(gulp.dest(tempDestBuildDir)); + const requiredFiles = ["preload.cjs", "node_modules/**/*", "favicon*"]; + return gulp + .src(requiredFiles, { cwd: electronBaseDir, cwdbase: true, dot: true }) + .pipe(gulp.dest(tempDestBuildDir)); } async function transpileTypeScript() { diff --git a/gulp/tasks.js b/gulp/tasks.js index f613a6b4..a378c68e 100644 --- a/gulp/tasks.js +++ b/gulp/tasks.js @@ -9,6 +9,7 @@ import { browserSync, buildFolder, buildOutputFolder, + generatedCodeFolder, imageResourcesGlobs, nonImageResourcesGlobs, rawImageResourcesGlobs, @@ -20,16 +21,15 @@ import gulpClean from "gulp-clean"; import gulpWebserver from "gulp-webserver"; import * as css from "./css.js"; -import * as docs from "./docs.js"; +import * as environment from "./environment.js"; import html from "./html.js"; import * as imgres from "./image-resources.js"; import js from "./js.js"; -import * as localConfig from "./local-config.js"; import * as sounds from "./sounds.js"; import standalone from "./standalone.js"; import * as translations from "./translations.js"; -export { css, docs, html, imgres, js, localConfig, sounds, standalone, translations }; +export { css, environment, html, imgres, js, sounds, standalone, translations }; ///////////////////// BUILD TASKS ///////////////////// @@ -41,9 +41,7 @@ function cleanBuildOutputFolder() { return gulp.src(buildOutputFolder, { read: false, allowEmpty: true }).pipe(gulpClean({ force: true })); } function cleanBuildTempFolder() { - return gulp - .src(path.join("..", "src", "js", "built-temp"), { read: false, allowEmpty: true }) - .pipe(gulpClean({ force: true })); + return gulp.src(generatedCodeFolder, { read: false, allowEmpty: true }).pipe(gulpClean({ force: true })); } function cleanImageBuildFolder() { return gulp @@ -184,7 +182,6 @@ const prepare = { dev: variant => gulp.series( utils.cleanup, - localConfig.findOrCreate, gulp.parallel( utils.copyAdditionalBuildFiles, gulp.series(imgres.buildAtlas, gulp.parallel(imgres.atlasToJson, imgres.atlas)), @@ -255,7 +252,6 @@ for (const variant in BUILD_VARIANTS) { pack[variant] = {}; for (const task of packageTasks) { pack[variant][task] = gulp.series( - localConfig.findOrCreate, full, utils.cleanBuildOutputFolder, standalone[variant].prepare.all, @@ -269,7 +265,6 @@ for (const variant in BUILD_VARIANTS) { } export const main = { - prepareDocs: docs.prepareDocs, webserver, }; diff --git a/gulp/translations.js b/gulp/translations.js index 1df37812..8813a069 100644 --- a/gulp/translations.js +++ b/gulp/translations.js @@ -1,20 +1,18 @@ -import path from "path/posix"; -import fs from "fs/promises"; -import YAML from "yaml"; import gulp from "gulp"; +import path from "path/posix"; import gulpPlumber from "gulp-plumber"; import gulpYaml from "gulp-yaml"; +import { generatedCodeFolder } from "./config.js"; const translationsSourceDir = path.join("..", "translations"); -const translationsJsonDir = path.join("..", "src", "js", "built-temp"); export function convertToJson() { return gulp .src(path.join(translationsSourceDir, "*.yaml")) .pipe(gulpPlumber()) .pipe(gulpYaml({ space: 2, safe: true })) - .pipe(gulp.dest(translationsJsonDir)); + .pipe(gulp.dest(generatedCodeFolder)); } export const fullBuild = convertToJson; diff --git a/package-lock.json b/package-lock.json index 140698e8..c6757666 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "shapez", "version": "1.6.0", + "hasInstallScript": true, "license": "GPL-3.0-or-later", "dependencies": { "@msgpack/msgpack": "^3.1.2", @@ -59,7 +60,6 @@ "postcss-preset-env": "^6.5.0", "postcss-round-subpixels": "^1.2.0", "prettier": "^3.3.2", - "strip-json-comments": "^3.0.1", "terser-webpack-plugin": "^5.3.6", "ts-loader": "^9.4.2", "typescript": "^5.8.2", diff --git a/package.json b/package.json index 19a218ad..779bfd9d 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,10 @@ "private": true, "type": "module", "scripts": { + "postinstall": "gulp -f gulp/environment.js prepare", "gulp": "gulp --cwd gulp", "lint": "eslint .", "prettier-all": "prettier --write .", - "buildTypes": "tsc src/js/application.js --declaration --allowJs --emitDeclarationOnly --skipLibCheck --out types.js", "package-win32-x64": "gulp --cwd gulp package.standalone.win32-x64", "package-win32-arm64": "gulp --cwd gulp package.standalone.win32-arm64", "package-linux-x64": "gulp --cwd gulp package.standalone.linux-x64", @@ -71,7 +71,6 @@ "postcss-preset-env": "^6.5.0", "postcss-round-subpixels": "^1.2.0", "prettier": "^3.3.2", - "strip-json-comments": "^3.0.1", "terser-webpack-plugin": "^5.3.6", "ts-loader": "^9.4.2", "typescript": "^5.8.2", diff --git a/tsconfig.json b/tsconfig.json index be25a52b..b0862a22 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "extends": ["@tsconfig/node-lts/tsconfig"], - "include": ["./*", "./electron/**/*", "./gulp/**/*"], + "include": ["./*", "./gulp/**/*"], "compilerOptions": { "allowJs": true, "checkJs": true,