1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-12-09 16:21:51 +00:00

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.
This commit is contained in:
Даниїл Григор'єв 2025-06-19 04:51:34 +03:00 committed by GitHub
parent ae739be484
commit 9906397170
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 94 additions and 152 deletions

View File

@ -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

View File

@ -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() {

View File

@ -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]);
}
}

View File

@ -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);

49
gulp/environment.js Normal file
View File

@ -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);

View File

@ -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"))

View File

@ -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)

View File

@ -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 {}
}

View File

@ -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);

View File

@ -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() {

View File

@ -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,
};

View File

@ -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;

2
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -1,6 +1,6 @@
{
"extends": ["@tsconfig/node-lts/tsconfig"],
"include": ["./*", "./electron/**/*", "./gulp/**/*"],
"include": ["./*", "./gulp/**/*"],
"compilerOptions": {
"allowJs": true,
"checkJs": true,