1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-12-14 02:31:51 +00:00

Merge pull request #27 from tobspr-games/refactor/gulp

Refactor gulp setup; switch from webpack watch to gulp.watch exclusively
This commit is contained in:
Даниїл Григор'єв 2024-04-26 22:42:00 +03:00 committed by GitHub
commit 7aeb687d14
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 1059 additions and 1030 deletions

View File

@ -57,8 +57,7 @@ and does not intend to provide compatibility for older clients.
### Prerequisites
- [ffmpeg](https://www.ffmpeg.org/download.html)
- [Node.js 16](https://nodejs.org/en/about/previous-releases)
(not 17+, see <https://github.com/tobspr-games/shapez.io/issues/1473>)
- [Node.js](https://nodejs.org)
- [Yarn 1](https://classic.yarnpkg.com/en/docs/install) (not 2, we haven't migrated yet)
- [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

44
gulp/config.js Normal file
View File

@ -0,0 +1,44 @@
import path from "path/posix";
import BrowserSync from "browser-sync";
export const baseDir = path.resolve("..");
export const buildFolder = path.join(baseDir, "build");
export const buildOutputFolder = path.join(baseDir, "build_output");
// Globs for atlas resources
export const rawImageResourcesGlobs = ["../res_raw/atlas.json", "../res_raw/**/*.png"];
// Globs for non-ui resources
export const nonImageResourcesGlobs = ["../res/**/*.woff2", "../res/*.ico", "../res/**/*.webm"];
// Globs for ui resources
export const imageResourcesGlobs = [
"../res/**/*.png",
"../res/**/*.svg",
"../res/**/*.jpg",
"../res/**/*.gif",
];
export const browserSync = BrowserSync.create();
// Check environment variables
const envVars = [
"SHAPEZ_CLI_SERVER_HOST",
"SHAPEZ_CLI_ALPHA_FTP_USER",
"SHAPEZ_CLI_ALPHA_FTP_PW",
"SHAPEZ_CLI_STAGING_FTP_USER",
"SHAPEZ_CLI_STAGING_FTP_PW",
"SHAPEZ_CLI_LIVE_FTP_USER",
"SHAPEZ_CLI_LIVE_FTP_PW",
"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,5 +1,7 @@
import path from "path/posix";
import gulp from "gulp";
import { getRevision } from "./buildutils.js";
import { buildFolder } from "./config.js";
import gulpPostcss from "gulp-postcss";
import postcssAssets from "postcss-assets";
@ -13,7 +15,6 @@ import gulpDartSass from "gulp-dart-sass";
import gulpPlumber from "gulp-plumber";
import gulpRename from "gulp-rename";
export default function gulptasksCSS(gulp, buildFolder, browserSync) {
// The assets plugin copies the files
const commitHash = getRevision();
const postcssAssetsPlugin = postcssAssets({
@ -55,13 +56,13 @@ export default function gulptasksCSS(gulp, buildFolder, browserSync) {
};
// Performs linting on css
gulp.task("css.lint", () => {
export function lint() {
return gulp
.src(["../src/css/**/*.scss"])
.pipe(gulpSassLint({ configFile: ".sasslint.yml" }))
.pipe(gulpSassLint.format())
.pipe(gulpSassLint.failOnError());
});
}
function resourcesTask({ isProd }) {
return gulp
@ -77,19 +78,16 @@ export default function gulptasksCSS(gulp, buildFolder, browserSync) {
)
.pipe(gulpRename("async-resources.css"))
.pipe(gulpPostcss(postcssPlugins(isProd)))
.pipe(gulp.dest(buildFolder))
.pipe(browserSync.stream());
.pipe(gulp.dest(buildFolder));
}
export const resources = {
// Builds the css resources
gulp.task("css.resources.dev", () => {
return resourcesTask({ isProd: false });
});
dev: () => resourcesTask({ isProd: false }),
// Builds the css resources in prod (=minified)
gulp.task("css.resources.prod", () => {
return resourcesTask({ isProd: true });
});
prod: () => resourcesTask({ isProd: true }),
};
function mainTask({ isProd }) {
return gulp
@ -105,20 +103,16 @@ export default function gulptasksCSS(gulp, buildFolder, browserSync) {
])
)
.pipe(gulpPostcss(postcssPlugins(isProd)))
.pipe(gulp.dest(buildFolder))
.pipe(browserSync.stream());
.pipe(gulp.dest(buildFolder));
}
export const main = {
// Builds the css main
gulp.task("css.main.dev", () => {
return mainTask({ isProd: false });
});
dev: () => mainTask({ isProd: false }),
// Builds the css main in prod (=minified)
gulp.task("css.main.prod", () => {
return mainTask({ isProd: true });
});
prod: () => mainTask({ isProd: true }),
};
gulp.task("css.dev", gulp.parallel("css.main.dev", "css.resources.dev"));
gulp.task("css.prod", gulp.parallel("css.main.prod", "css.resources.prod"));
}
export const dev = gulp.parallel(main.dev, resources.dev);
export const prod = gulp.parallel(main.prod, resources.prod);

View File

@ -1,11 +1,11 @@
import path from "path/posix";
import fs from "fs";
import fs from "fs/promises";
import gulp from "gulp";
import gulpRename from "gulp-rename";
import stripJsonComments from "strip-json-comments";
export default function gulptasksDocs(gulp, buildFolder) {
gulp.task("docs.convertJsToTs", () => {
export function convertJsToTs() {
return gulp
.src(path.join("..", "src", "js", "**", "*.js"))
.pipe(
@ -14,10 +14,10 @@ export default function gulptasksDocs(gulp, buildFolder) {
})
)
.pipe(gulp.dest(path.join("..", "tsc_temp")));
});
}
gulp.task("docs.copyTsconfigForHints", cb => {
const src = fs.readFileSync(path.join("..", "src", "js", "tsconfig.json")).toString();
export async function copyTsconfigForHints() {
const src = (await fs.readFile(path.join("..", "src", "js", "tsconfig.json"))).toString();
const baseConfig = JSON.parse(stripJsonComments(src));
baseConfig.allowJs = false;
@ -30,9 +30,7 @@ export default function gulptasksDocs(gulp, buildFolder) {
baseConfig.alwaysStrict = false;
baseConfig.composite = true;
baseConfig.outFile = "bundled-ts.js";
fs.writeFileSync(path.join("..", "tsc_temp", "tsconfig.json"), JSON.stringify(baseConfig));
cb();
});
gulp.task("main.prepareDocs", gulp.series("docs.convertJsToTs", "docs.copyTsconfigForHints"));
await fs.writeFile(path.join("..", "tsc_temp", "tsconfig.json"), JSON.stringify(baseConfig));
}
export const prepareDocs = gulp.series(convertJsToTs, copyTsconfigForHints);

View File

@ -1,17 +1,18 @@
import path from "path/posix";
import fs from "fs";
import fs from "fs/promises";
import gulp from "gulp";
import { buildFolder } from "./config.js";
import { getRevision, getVersion } from "./buildutils.js";
import gulpRename from "gulp-rename";
import gulpSftp from "gulp-sftp";
export default function gulptasksFTP(gulp, buildFolder) {
const commitHash = getRevision();
const additionalFolder = path.join("additional_build_files");
const additionalFiles = [
const additionalGlobs = [
path.join(additionalFolder, "*"),
path.join(additionalFolder, "*.*"),
path.join(additionalFolder, ".*"),
@ -36,8 +37,8 @@ export default function gulptasksFTP(gulp, buildFolder) {
};
// Write the "commit.txt" file
gulp.task("ftp.writeVersion", cb => {
fs.writeFileSync(
export async function writeVersion() {
await fs.writeFile(
path.join(buildFolder, "version.json"),
JSON.stringify(
{
@ -49,8 +50,7 @@ export default function gulptasksFTP(gulp, buildFolder) {
4
)
);
cb();
});
}
const gameSrcGlobs = [
path.join(buildFolder, "**/*.*"),
@ -59,10 +59,11 @@ export default function gulptasksFTP(gulp, buildFolder) {
path.join(buildFolder, "!**/index.html"),
];
for (const deployEnv of ["alpha", "prod", "staging"]) {
export const upload = Object.fromEntries(
["alpha", "prod", "staging"].map(deployEnv => {
const deployCredentials = credentials[deployEnv];
gulp.task(`ftp.upload.${deployEnv}.game`, () => {
function game() {
return gulp
.src(gameSrcGlobs, { base: buildFolder })
.pipe(
@ -71,30 +72,28 @@ export default function gulptasksFTP(gulp, buildFolder) {
})
)
.pipe(gulpSftp(deployCredentials));
});
}
gulp.task(`ftp.upload.${deployEnv}.indexHtml`, () => {
function indexHtml() {
return gulp
.src([path.join(buildFolder, "index.html"), path.join(buildFolder, "version.json")], {
base: buildFolder,
})
.pipe(gulpSftp(deployCredentials));
});
}
gulp.task(`ftp.upload.${deployEnv}.additionalFiles`, () => {
return gulp
.src(additionalFiles, { base: additionalFolder }) //
.pipe(gulpSftp(deployCredentials));
});
function additionalFiles() {
return gulp.src(additionalGlobs, { base: additionalFolder }).pipe(gulpSftp(deployCredentials));
}
gulp.task(
`ftp.upload.${deployEnv}`,
gulp.series(
"ftp.writeVersion",
`ftp.upload.${deployEnv}.game`,
`ftp.upload.${deployEnv}.indexHtml`,
`ftp.upload.${deployEnv}.additionalFiles`
)
return [
deployEnv,
{
game,
indexHtml,
additionalFiles,
all: gulp.series(writeVersion, game, indexHtml, additionalFiles),
},
];
})
);
}
}

View File

@ -1,303 +1,23 @@
import gulp from "gulp";
import BrowserSync from "browser-sync";
const browserSync = BrowserSync.create({});
import path from "path/posix";
import pathNative from "path";
import deleteEmpty from "delete-empty";
import { execSync } from "child_process";
// Load other plugins
import gulpClean from "gulp-clean";
import gulpWebserver from "gulp-webserver";
// Check environment variables
const envVars = [
"SHAPEZ_CLI_SERVER_HOST",
"SHAPEZ_CLI_ALPHA_FTP_USER",
"SHAPEZ_CLI_ALPHA_FTP_PW",
"SHAPEZ_CLI_STAGING_FTP_USER",
"SHAPEZ_CLI_STAGING_FTP_PW",
"SHAPEZ_CLI_LIVE_FTP_USER",
"SHAPEZ_CLI_LIVE_FTP_PW",
"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]);
}
}
const baseDir = path.resolve("..");
const buildFolder = path.join(baseDir, "build");
const buildOuptutFolder = path.join(baseDir, "build_output");
import gulptasksImageResources, * as imgres from "./image-resources.js";
gulptasksImageResources(gulp, buildFolder);
import gulptasksCSS from "./css.js";
gulptasksCSS(gulp, buildFolder, browserSync);
import gulptasksSounds from "./sounds.js";
gulptasksSounds(gulp, buildFolder);
import gulptasksLocalConfig from "./local-config.js";
gulptasksLocalConfig(gulp);
import gulptasksJS from "./js.js";
gulptasksJS(gulp, buildFolder, browserSync);
import gulptasksHTML from "./html.js";
gulptasksHTML(gulp, buildFolder);
import gulptasksFTP from "./ftp.js";
gulptasksFTP(gulp, buildFolder);
import gulptasksDocs from "./docs.js";
gulptasksDocs(gulp, buildFolder);
import gulptasksStandalone from "./standalone.js";
gulptasksStandalone(gulp);
import gulptasksTranslations from "./translations.js";
import { BUILD_VARIANTS } from "./build_variants.js";
gulptasksTranslations(gulp);
///////////////////// BUILD TASKS /////////////////////
// Cleans up everything
gulp.task("utils.cleanBuildFolder", () => {
return gulp.src(buildFolder, { read: false, allowEmpty: true }).pipe(gulpClean({ force: true }));
});
gulp.task("utils.cleanBuildOutputFolder", () => {
return gulp.src(buildOuptutFolder, { read: false, allowEmpty: true }).pipe(gulpClean({ force: true }));
});
gulp.task("utils.cleanBuildTempFolder", () => {
return gulp
.src(path.join("..", "src", "js", "built-temp"), { read: false, allowEmpty: true })
.pipe(gulpClean({ force: true }));
});
gulp.task("utils.cleanImageBuildFolder", () => {
return gulp
.src(path.join("res_built"), { read: false, allowEmpty: true })
.pipe(gulpClean({ force: true }));
});
gulp.task(
"utils.cleanup",
gulp.series("utils.cleanBuildFolder", "utils.cleanImageBuildFolder", "utils.cleanBuildTempFolder")
);
// Requires no uncomitted files
gulp.task("utils.requireCleanWorkingTree", cb => {
let output = execSync("git status -su").toString("ascii").trim().replace(/\r/gi, "").split("\n");
// Filter files which are OK to be untracked
output = output
.map(x => x.replace(/[\r\n]+/gi, ""))
.filter(x => x.indexOf(".local.js") < 0)
.filter(x => x.length > 0);
if (output.length > 0) {
console.error("\n\nYou have unstaged changes, please commit everything first!");
console.error("Unstaged files:");
console.error(output.map(x => "'" + x + "'").join("\n"));
process.exit(1);
}
cb();
});
gulp.task("utils.copyAdditionalBuildFiles", cb => {
const additionalFolder = path.join("additional_build_files");
const additionalSrcGlobs = [
path.join(additionalFolder, "**/*.*"),
path.join(additionalFolder, "**/.*"),
path.join(additionalFolder, "**/*"),
];
return gulp.src(additionalSrcGlobs).pipe(gulp.dest(buildFolder));
});
// Starts a webserver on the built directory (useful for testing prod build)
gulp.task("main.webserver", () => {
return gulp.src(buildFolder).pipe(
gulpWebserver({
livereload: {
enable: true,
},
directoryListing: false,
open: true,
port: 3005,
})
);
});
import * as tasks from "./tasks.js";
/**
*
* @param {object} param0
* @param {keyof typeof BUILD_VARIANTS} param0.version
* @typedef {import("gulp").TaskFunction} TaskFunction
* @typedef {TaskFunction | { [k: string]: Tasks }} Tasks
*/
function serveHTML({ version = "web-dev" }) {
browserSync.init({
server: [buildFolder, path.join(baseDir, "mod_examples")],
port: 3005,
ghostMode: {
clicks: false,
scroll: false,
location: false,
forms: false,
},
logLevel: "info",
logPrefix: "BS",
online: false,
xip: false,
notify: false,
reloadDebounce: 100,
reloadOnRestart: true,
watchEvents: ["add", "change"],
});
// Watch .scss files, those trigger a css rebuild
gulp.watch(["../src/**/*.scss"], gulp.series("css.dev"));
// Watch .html files, those trigger a html rebuild
gulp.watch("../src/**/*.html", gulp.series("html.dev"));
gulp.watch("./preloader/*.*", gulp.series("html.dev"));
// Watch translations
gulp.watch("../translations/**/*.yaml", gulp.series("translations.convertToJson"));
gulp.watch(
["../res_raw/sounds/sfx/*.mp3", "../res_raw/sounds/sfx/*.wav"],
gulp.series("sounds.sfx", "sounds.copy")
);
gulp.watch(
["../res_raw/sounds/music/*.mp3", "../res_raw/sounds/music/*.wav"],
gulp.series("sounds.music", "sounds.copy")
);
// Watch resource files and copy them on change
gulp.watch(imgres.rawImageResourcesGlobs, gulp.series("imgres.buildAtlas"));
gulp.watch(imgres.nonImageResourcesGlobs, gulp.series("imgres.copyNonImageResources"));
gulp.watch(imgres.imageResourcesGlobs, gulp.series("imgres.copyImageResources"));
// Watch .atlas files and recompile the atlas on change
gulp.watch("../res_built/atlas/*.atlas", gulp.series("imgres.atlasToJson"));
gulp.watch("../res_built/atlas/*.json", gulp.series("imgres.atlas"));
// Watch the build folder and reload when anything changed
const extensions = ["html", "js", "png", "gif", "jpg", "svg", "mp3", "ico", "woff2", "json"];
gulp.watch(extensions.map(ext => path.join(buildFolder, "**", "*." + ext))).on("change", function (p) {
return gulp
.src(pathNative.resolve(p).replaceAll(pathNative.sep, path.sep))
.pipe(browserSync.reload({ stream: true }));
});
gulp.watch("../src/js/built-temp/*.json").on("change", function (p) {
return gulp
.src(pathNative.resolve(p).replaceAll(pathNative.sep, path.sep))
.pipe(browserSync.reload({ stream: true }));
});
gulp.series("js." + version + ".dev.watch")(() => true);
/**
* @param {Tasks} tasks
* @param {string=} prefix
*/
function register(tasks, prefix) {
if (tasks instanceof Function) {
gulp.task(prefix, tasks);
return;
}
// Pre and postbuild
gulp.task("step.baseResources", gulp.series("imgres.allOptimized"));
gulp.task("step.deleteEmpty", cb => {
deleteEmpty.sync(buildFolder);
cb();
});
gulp.task("step.postbuild", gulp.series("imgres.cleanupUnusedCssInlineImages", "step.deleteEmpty"));
///////////////////// RUNNABLE TASKS /////////////////////
// Builds everything (dev)
gulp.task(
"build.prepare.dev",
gulp.series(
"utils.cleanup",
"utils.copyAdditionalBuildFiles",
"localConfig.findOrCreate",
"imgres.buildAtlas",
"imgres.atlasToJson",
"imgres.atlas",
"sounds.dev",
"imgres.copyImageResources",
"imgres.copyNonImageResources",
"translations.fullBuild",
"css.dev"
)
);
// Builds everything for every variant
for (const variant in BUILD_VARIANTS) {
const data = BUILD_VARIANTS[variant];
const buildName = "build." + variant;
// build
gulp.task(
buildName + ".code",
gulp.series(
data.standalone ? "sounds.fullbuildHQ" : "sounds.fullbuild",
"translations.fullBuild",
"js." + variant + ".prod"
)
);
gulp.task(buildName + ".resourcesAndCode", gulp.parallel("step.baseResources", buildName + ".code"));
gulp.task(buildName + ".all", gulp.series(buildName + ".resourcesAndCode", "css.prod", "html.prod"));
gulp.task(buildName, gulp.series("utils.cleanup", buildName + ".all", "step.postbuild"));
// Tasks for creating packages. These packages are already distributable, but usually can be further
// wrapped in a different format (an installer for Windows, tarball for Linux, DMG for macOS).
if (data.standalone) {
const packageTasks = [
"win32-x64",
"win32-arm64",
"linux-x64",
"linux-arm64",
"darwin-x64",
"darwin-arm64",
"all",
];
for (const task of packageTasks) {
gulp.task(
`package.${variant}.${task}`,
gulp.series(
"localConfig.findOrCreate",
`build.${variant}`,
"utils.cleanBuildOutputFolder",
`standalone.${variant}.prepare`,
`standalone.${variant}.package.${task}`
)
);
for (const [k, v] of Object.entries(tasks)) {
register(v, prefix == null ? k : `${prefix}.${k}`);
}
}
// serve
gulp.task(
"serve." + variant,
gulp.series("build.prepare.dev", "html.dev", () => serveHTML({ version: variant }))
);
}
// Deploying!
gulp.task(
"deploy.staging",
gulp.series("utils.requireCleanWorkingTree", "build.web-shapezio-beta", "ftp.upload.staging")
);
gulp.task(
"deploy.prod",
gulp.series("utils.requireCleanWorkingTree", "build.web-shapezio", "ftp.upload.prod")
);
// Default task (dev, localhost)
gulp.task("default", gulp.series("serve.standalone-steam"));
register(tasks);

View File

@ -2,6 +2,8 @@ import { getRevision } from "./buildutils.js";
import fs from "fs";
import path from "path/posix";
import crypto from "crypto";
import gulp from "gulp";
import { buildFolder } from "./config.js";
import gulpDom from "gulp-dom";
import gulpHtmlmin from "gulp-htmlmin";
@ -20,7 +22,6 @@ function computeIntegrityHash(fullPath, algorithm = "sha256") {
* html.dev
* html.prod
*/
export default function gulptasksHTML(gulp, buildFolder) {
const commitHash = getRevision();
async function buildHtml({ integrity = true }) {
return gulp
@ -62,9 +63,7 @@ export default function gulptasksHTML(gulp, buildFolder) {
style.textContent = loadingCss;
document.head.appendChild(style);
let bodyContent = fs
.readFileSync(path.join("preloader", "preloader.html"))
.toString();
let bodyContent = fs.readFileSync(path.join("preloader", "preloader.html")).toString();
const bundleScript = document.createElement("script");
bundleScript.type = "text/javascript";
@ -99,14 +98,11 @@ export default function gulptasksHTML(gulp, buildFolder) {
.pipe(gulp.dest(buildFolder));
}
gulp.task("html.dev", () => {
return buildHtml({
export const dev = () =>
buildHtml({
integrity: false,
});
});
gulp.task("html.prod", () => {
return buildHtml({
export const prod = () =>
buildHtml({
integrity: true,
});
});
}

View File

@ -1,12 +1,19 @@
import fs from "fs";
import fs from "fs/promises";
import path from "path/posix";
import atlasToJson from "./atlas2json.js";
import gulp from "gulp";
import { buildFolder } from "./config.js";
import atlas2Json from "./atlas2json.js";
import { execSync } from "child_process";
const execute = command =>
execSync(command, {
import childProcess from "child_process";
import { promisify } from "util";
const exec = promisify(childProcess.exec);
const execute = command => {
const promise = exec(command, {
encoding: "utf-8",
});
promise.child.stderr.pipe(process.stderr);
return promise;
};
import gulpImagemin from "gulp-imagemin";
import imageminJpegtran from "imagemin-jpegtran";
@ -15,26 +22,12 @@ import imageminPngquant from "imagemin-pngquant";
import gulpIf from "gulp-if";
import gulpCached from "gulp-cached";
import gulpClean from "gulp-clean";
// Globs for atlas resources
export const rawImageResourcesGlobs = ["../res_raw/atlas.json", "../res_raw/**/*.png"];
// Globs for non-ui resources
export const nonImageResourcesGlobs = ["../res/**/*.woff2", "../res/*.ico", "../res/**/*.webm"];
// Globs for ui resources
export const imageResourcesGlobs = [
"../res/**/*.png",
"../res/**/*.svg",
"../res/**/*.jpg",
"../res/**/*.gif",
];
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";
export default function gulptasksImageResources(gulp, buildFolder) {
// Lossless options
const minifyImagesOptsLossless = () => [
imageminJpegtran({
@ -86,16 +79,18 @@ export default function gulptasksImageResources(gulp, buildFolder) {
/////////////// ATLAS /////////////////////
gulp.task("imgres.buildAtlas", cb => {
export async function buildAtlas() {
const config = JSON.stringify("../res_raw/atlas.json");
const source = JSON.stringify("../res_raw");
const dest = JSON.stringify("../res_built/atlas");
try {
// First check whether Java is installed
execute("java -version");
await execute("java -version");
// Now check and try downloading runnable-texturepacker.jar (22MB)
if (!fs.existsSync("./runnable-texturepacker.jar")) {
try {
await fs.access("./runnable-texturepacker.jar");
} catch {
const escapedLink = JSON.stringify(runnableTPSource);
try {
@ -105,26 +100,24 @@ export default function gulptasksImageResources(gulp, buildFolder) {
}
}
execute(`java -jar runnable-texturepacker.jar ${source} ${dest} atlas0 ${config}`);
await execute(`java -jar runnable-texturepacker.jar ${source} ${dest} atlas0 ${config}`);
} catch {
console.warn("Building atlas failed. Java not found / unsupported version?");
}
cb();
});
}
// Converts .atlas LibGDX files to JSON
gulp.task("imgres.atlasToJson", cb => {
atlasToJson("../res_built/atlas");
cb();
});
export async function atlasToJson() {
atlas2Json("../res_built/atlas");
}
// Copies the atlas to the final destination
gulp.task("imgres.atlas", () => {
export function atlas() {
return gulp.src(["../res_built/atlas/*.png"]).pipe(gulp.dest(resourcesDestFolder));
});
}
// Copies the atlas to the final destination after optimizing it (lossy compression)
gulp.task("imgres.atlasOptimized", () => {
export function atlasOptimized() {
return gulp
.src(["../res_built/atlas/*.png"])
.pipe(
@ -135,26 +128,25 @@ export default function gulptasksImageResources(gulp, buildFolder) {
)
)
.pipe(gulp.dest(resourcesDestFolder));
});
}
//////////////////// RESOURCES //////////////////////
// Copies all resources which are no ui resources
gulp.task("imgres.copyNonImageResources", () => {
export function copyNonImageResources() {
return gulp.src(nonImageResourcesGlobs).pipe(gulp.dest(resourcesDestFolder));
});
}
// Copies all ui resources
gulp.task("imgres.copyImageResources", () => {
export function copyImageResources() {
return gulp
.src(imageResourcesGlobs)
.pipe(gulpCached("imgres.copyImageResources"))
.pipe(gulp.dest(path.join(resourcesDestFolder)));
});
}
// Copies all ui resources and optimizes them
gulp.task("imgres.copyImageResourcesOptimized", () => {
export function copyImageResourcesOptimized() {
return gulp
.src(imageResourcesGlobs)
.pipe(
@ -165,22 +157,17 @@ export default function gulptasksImageResources(gulp, buildFolder) {
)
)
.pipe(gulp.dest(path.join(resourcesDestFolder)));
});
}
// Copies all resources and optimizes them
gulp.task(
"imgres.allOptimized",
gulp.parallel(
"imgres.buildAtlas",
"imgres.atlasToJson",
"imgres.atlasOptimized",
"imgres.copyNonImageResources",
"imgres.copyImageResourcesOptimized"
)
export const allOptimized = gulp.parallel(
gulp.series(buildAtlas, atlasToJson, atlasOptimized),
copyNonImageResources,
copyImageResourcesOptimized
);
// Cleans up unused images which are instead inline into the css
gulp.task("imgres.cleanupUnusedCssInlineImages", () => {
export function cleanupUnusedCssInlineImages() {
return gulp
.src(
[
@ -192,5 +179,4 @@ export default function gulptasksImageResources(gulp, buildFolder) {
{ read: false }
)
.pipe(gulpIf(fname => fname.history[0].indexOf("noinline") < 0, gulpClean({ force: true })));
});
}

View File

@ -1,4 +1,7 @@
import gulp from "gulp";
import webpack from "webpack";
import { BUILD_VARIANTS } from "./build_variants.js";
import { buildFolder } from "./config.js";
import webpackConfig from "./webpack.config.js";
import webpackProductionConfig from "./webpack.production.config.js";
@ -15,64 +18,60 @@ import gulpRename from "gulp-rename";
*
*/
export default function gulptasksJS(gulp, buildFolder, browserSync) {
//// DEV
for (const variant in BUILD_VARIANTS) {
const data = BUILD_VARIANTS[variant];
export default Object.fromEntries(
Object.entries(BUILD_VARIANTS).map(([variant, data]) => {
function build() {
return gulp
.src("../src/js/main.js")
.pipe(webpackStream(webpackConfig, webpack))
.pipe(gulp.dest(buildFolder));
}
gulp.task("js." + variant + ".dev.watch", () => {
gulp.src("../src/js/main.js")
.pipe(webpackStream(webpackConfig))
.pipe(gulp.dest(buildFolder))
.pipe(browserSync.stream());
});
const dev = {
build,
};
let prod;
if (!data.standalone) {
// WEB
gulp.task("js." + variant + ".dev", () => {
function transpiled() {
return gulp
.src("../src/js/main.js")
.pipe(webpackStream(webpackConfig))
.pipe(gulp.dest(buildFolder));
});
gulp.task("js." + variant + ".prod.transpiled", () => {
return gulp
.src("../src/js/main.js")
.pipe(webpackStream(webpackProductionConfig))
.pipe(webpackStream(webpackProductionConfig, webpack))
.pipe(gulpRename("bundle-transpiled.js"))
.pipe(gulp.dest(buildFolder));
});
}
gulp.task("js." + variant + ".prod.es6", () => {
function es6() {
return gulp
.src("../src/js/main.js")
.pipe(webpackStream(webpackProductionConfig))
.pipe(webpackStream(webpackProductionConfig, webpack))
.pipe(gulp.dest(buildFolder));
});
gulp.task(
"js." + variant + ".prod",
}
prod = {
transpiled,
es6,
build:
// transpiled currently not used
// gulp.parallel("js." + variant + ".prod.transpiled", "js." + variant + ".prod.es6")
gulp.parallel("js." + variant + ".prod.es6")
);
es6,
};
} else {
// STANDALONE
gulp.task("js." + variant + ".dev", () => {
function build() {
return gulp
.src("../src/js/main.js")
.pipe(webpackStream(webpackConfig))
.pipe(webpackStream(webpackProductionConfig, webpack))
.pipe(gulp.dest(buildFolder));
});
gulp.task("js." + variant + ".prod", () => {
return gulp
.src("../src/js/main.js")
.pipe(webpackStream(webpackProductionConfig))
.pipe(gulp.dest(buildFolder));
});
}
}
prod = { build };
}
return [variant, { dev, prod }];
})
);

View File

@ -1,14 +1,10 @@
import fs from "fs";
import fs from "fs/promises";
const configTemplatePath = "../src/js/core/config.local.template.js";
const configPath = "../src/js/core/config.local.js";
export default function gulptasksLocalConfig(gulp) {
gulp.task("localConfig.findOrCreate", cb => {
if (!fs.existsSync(configPath)) {
fs.copyFileSync(configTemplatePath, configPath);
}
cb();
});
export async function findOrCreate() {
try {
await fs.copyFile(configTemplatePath, configPath, fs.constants.COPYFILE_EXCL);
} catch {}
}

View File

@ -1,19 +1,20 @@
import path from "path/posix";
import audiosprite from "gulp-audiosprite";
import gulp from "gulp";
import { buildFolder } from "./config.js";
import gulpAudiosprite from "gulp-audiosprite";
import gulpClean from "gulp-clean";
import gulpCache from "gulp-cache";
import gulpPlumber from "gulp-plumber";
import gulpFluentFfmpeg from "gulp-fluent-ffmpeg";
export default function gulptasksSounds(gulp, buildFolder) {
// Gather some basic infos
const soundsDir = path.join("..", "res_raw", "sounds");
const builtSoundsDir = path.join("..", "res_built", "sounds");
gulp.task("sounds.clear", () => {
export function clear() {
return gulp.src(builtSoundsDir, { read: false, allowEmpty: true }).pipe(gulpClean({ force: true }));
});
}
const filters = ["volume=0.2"];
@ -28,7 +29,7 @@ export default function gulptasksSounds(gulp, buildFolder) {
}
// Encodes the game music
gulp.task("sounds.music", () => {
export function music() {
return gulp
.src([path.join(soundsDir, "music", "**", "*.wav"), path.join(soundsDir, "music", "**", "*.mp3")])
.pipe(gulpPlumber())
@ -50,10 +51,10 @@ export default function gulptasksSounds(gulp, buildFolder) {
)
)
.pipe(gulp.dest(path.join(builtSoundsDir, "music")));
});
}
// Encodes the game music in high quality for the standalone
gulp.task("sounds.musicHQ", () => {
export function musicHQ() {
return gulp
.src([path.join(soundsDir, "music", "**", "*.wav"), path.join(soundsDir, "music", "**", "*.mp3")])
.pipe(gulpPlumber())
@ -75,15 +76,15 @@ export default function gulptasksSounds(gulp, buildFolder) {
)
)
.pipe(gulp.dest(path.join(builtSoundsDir, "music")));
});
}
// Encodes the ui sounds
gulp.task("sounds.sfxGenerateSprites", () => {
export function sfxGenerateSprites() {
return gulp
.src([path.join(soundsDir, "sfx", "**", "*.wav"), path.join(soundsDir, "sfx", "**", "*.mp3")])
.pipe(gulpPlumber())
.pipe(
audiosprite({
gulpAudiosprite({
format: "howler",
output: "sfx",
gap: 0.1,
@ -91,8 +92,8 @@ export default function gulptasksSounds(gulp, buildFolder) {
})
)
.pipe(gulp.dest(path.join(builtSoundsDir)));
});
gulp.task("sounds.sfxOptimize", () => {
}
export function sfxOptimize() {
return gulp
.src([path.join(builtSoundsDir, "sfx.mp3")])
.pipe(gulpPlumber())
@ -107,29 +108,25 @@ export default function gulptasksSounds(gulp, buildFolder) {
})
)
.pipe(gulp.dest(path.join(builtSoundsDir)));
});
gulp.task("sounds.sfxCopyAtlas", () => {
}
export function sfxCopyAtlas() {
return gulp
.src([path.join(builtSoundsDir, "sfx.json")])
.pipe(gulp.dest(path.join("..", "src", "js", "built-temp")));
});
}
gulp.task(
"sounds.sfx",
gulp.series("sounds.sfxGenerateSprites", "sounds.sfxOptimize", "sounds.sfxCopyAtlas")
);
export const sfx = gulp.series(sfxGenerateSprites, sfxOptimize, sfxCopyAtlas);
gulp.task("sounds.copy", () => {
export function copy() {
return gulp
.src(path.join(builtSoundsDir, "**", "*.mp3"))
.pipe(gulpPlumber())
.pipe(gulp.dest(path.join(buildFolder, "res", "sounds")));
});
gulp.task("sounds.buildall", gulp.parallel("sounds.music", "sounds.sfx"));
gulp.task("sounds.buildallHQ", gulp.parallel("sounds.musicHQ", "sounds.sfx"));
gulp.task("sounds.fullbuild", gulp.series("sounds.clear", "sounds.buildall", "sounds.copy"));
gulp.task("sounds.fullbuildHQ", gulp.series("sounds.clear", "sounds.buildallHQ", "sounds.copy"));
gulp.task("sounds.dev", gulp.series("sounds.buildall", "sounds.copy"));
}
export const buildall = gulp.parallel(music, sfx);
export const buildallHQ = gulp.parallel(musicHQ, sfx);
export const fullbuild = gulp.series(clear, buildall, copy);
export const fullbuildHQ = gulp.series(clear, buildallHQ, copy);
export const dev = gulp.series(buildall, copy);

View File

@ -2,8 +2,11 @@ import packager from "electron-packager";
import pj from "../electron/package.json" assert { type: "json" };
import path from "path/posix";
import { getVersion } from "./buildutils.js";
import fs from "fs";
import { execSync } from "child_process";
import fs from "fs/promises";
import childProcess from "child_process";
import { promisify } from "util";
const exec = promisify(childProcess.exec);
import gulp from "gulp";
import { BUILD_VARIANTS } from "./build_variants.js";
import gulpClean from "gulp-clean";
@ -11,31 +14,30 @@ import gulpClean from "gulp-clean";
const platforms = /** @type {const} */ (["win32", "linux", "darwin"]);
const architectures = /** @type {const} */ (["x64", "arm64"]);
export default function gulptasksStandalone(gulp) {
for (const variant in BUILD_VARIANTS) {
const variantData = BUILD_VARIANTS[variant];
if (!variantData.standalone) {
continue;
}
export default Object.fromEntries(
Object.entries(BUILD_VARIANTS)
.filter(([variant, variantData]) => variantData.standalone)
.map(([variant, variantData]) => {
const tempDestDir = path.join("..", "build_output", variant);
const taskPrefix = "standalone." + variant;
const electronBaseDir = path.join("..", "electron");
const tempDestBuildDir = path.join(tempDestDir, "built");
gulp.task(taskPrefix + ".prepare.cleanup", () => {
return gulp.src(tempDestDir, { read: false, allowEmpty: true }).pipe(gulpClean({ force: true }));
});
function cleanup() {
return gulp
.src(tempDestDir, { read: false, allowEmpty: true })
.pipe(gulpClean({ force: true }));
}
gulp.task(taskPrefix + ".prepare.copyPrefab", () => {
function copyPrefab() {
const requiredFiles = [
path.join(electronBaseDir, "node_modules", "**", "*.*"),
path.join(electronBaseDir, "node_modules", "**", ".*"),
path.join(electronBaseDir, "favicon*"),
];
return gulp.src(requiredFiles, { base: electronBaseDir }).pipe(gulp.dest(tempDestBuildDir));
});
}
gulp.task(taskPrefix + ".prepare.writePackageJson", cb => {
async function writePackageJson() {
const packageJsonString = JSON.stringify(
{
scripts: {
@ -49,47 +51,47 @@ export default function gulptasksStandalone(gulp) {
4
);
fs.writeFileSync(path.join(tempDestBuildDir, "package.json"), packageJsonString);
await fs.writeFile(path.join(tempDestBuildDir, "package.json"), packageJsonString);
}
cb();
});
gulp.task(taskPrefix + ".prepare.minifyCode", () => {
function minifyCode() {
return gulp.src(path.join(electronBaseDir, "*.js")).pipe(gulp.dest(tempDestBuildDir));
});
}
gulp.task(taskPrefix + ".prepare.copyGamefiles", () => {
function copyGamefiles() {
return gulp.src("../build/**/*.*", { base: "../build" }).pipe(gulp.dest(tempDestBuildDir));
});
}
gulp.task(taskPrefix + ".killRunningInstances", cb => {
async function killRunningInstances() {
try {
execSync("taskkill /F /IM shapezio.exe");
await exec("taskkill /F /IM shapezio.exe");
} catch (ex) {
console.warn("Failed to kill running instances, maybe none are up.");
}
cb();
});
}
gulp.task(
taskPrefix + ".prepare",
gulp.series(
taskPrefix + ".killRunningInstances",
taskPrefix + ".prepare.cleanup",
taskPrefix + ".prepare.copyPrefab",
taskPrefix + ".prepare.writePackageJson",
taskPrefix + ".prepare.minifyCode",
taskPrefix + ".prepare.copyGamefiles"
)
);
const prepare = {
cleanup,
copyPrefab,
writePackageJson,
minifyCode,
copyGamefiles,
all: gulp.series(
killRunningInstances,
cleanup,
copyPrefab,
writePackageJson,
minifyCode,
copyGamefiles
),
};
/**
*
* @param {typeof platforms[number] | (typeof platforms[number])[]} platform
* @param {typeof architectures[number] | (typeof architectures[number])[]} arch
* @param {function():void} cb
*/
async function packageStandalone(platform, arch, cb) {
async function packageStandalone(platform, arch) {
const appPaths = await packager({
dir: tempDestBuildDir,
appCopyright: "tobspr Games",
@ -108,24 +110,36 @@ export default function gulptasksStandalone(gulp) {
});
console.log("Packages created:", appPaths);
for (const appPath of appPaths) {
fs.writeFileSync(path.join(appPath, "LICENSE"), fs.readFileSync(path.join("..", "LICENSE")));
}
cb();
}
for (const platform of platforms) {
for (const arch of architectures) {
gulp.task(taskPrefix + `.package.${platform}-${arch}`, cb =>
packageStandalone(platform, arch, cb)
await Promise.all(
appPaths.map(async appPath => {
await fs.writeFile(
path.join(appPath, "LICENSE"),
await fs.readFile(path.join("..", "LICENSE"))
);
})
);
}
}
const pack = {
...Object.fromEntries(
platforms.flatMap(platform =>
architectures.map(arch => [
`${platform}-${arch}`,
() => packageStandalone(platform, arch),
])
)
),
// TODO: Review this hack forced by readonly types
gulp.task(taskPrefix + ".package.all", cb =>
packageStandalone([...platforms], [...architectures], cb)
all: () => packageStandalone([...platforms], [...architectures]),
};
return [
variant,
{
killRunningInstances,
prepare,
package: pack,
},
];
})
);
}
}

289
gulp/tasks.js Normal file
View File

@ -0,0 +1,289 @@
import gulp from "gulp";
import path from "path/posix";
import pathNative from "path";
import delEmpty from "delete-empty";
import childProcess from "child_process";
import { promisify } from "util";
const exec = promisify(childProcess.exec);
import { BUILD_VARIANTS } from "./build_variants.js";
import {
baseDir,
buildFolder,
buildOutputFolder,
browserSync,
rawImageResourcesGlobs,
nonImageResourcesGlobs,
imageResourcesGlobs,
} from "./config.js";
// Load other plugins
import gulpClean from "gulp-clean";
import gulpWebserver from "gulp-webserver";
import * as imgres from "./image-resources.js";
import * as css from "./css.js";
import * as sounds from "./sounds.js";
import * as localConfig from "./local-config.js";
import js from "./js.js";
import * as html from "./html.js";
import * as ftp from "./ftp.js";
import * as docs from "./docs.js";
import standalone from "./standalone.js";
import * as translations from "./translations.js";
export { imgres, css, sounds, localConfig, js, html, ftp, docs, standalone, translations };
///////////////////// BUILD TASKS /////////////////////
// Cleans up everything
function cleanBuildFolder() {
return gulp.src(buildFolder, { read: false, allowEmpty: true }).pipe(gulpClean({ force: true }));
}
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 }));
}
function cleanImageBuildFolder() {
return gulp
.src(path.join("res_built"), { read: false, allowEmpty: true })
.pipe(gulpClean({ force: true }));
}
const cleanup = gulp.parallel(cleanBuildFolder, cleanImageBuildFolder, cleanBuildTempFolder);
// Requires no uncomitted files
async function requireCleanWorkingTree() {
let output = (await exec("git status -su", { encoding: "buffer" })).stdout
.toString("ascii")
.trim()
.replace(/\r/gi, "")
.split("\n");
// Filter files which are OK to be untracked
output = output
.map(x => x.replace(/[\r\n]+/gi, ""))
.filter(x => x.indexOf(".local.js") < 0)
.filter(x => x.length > 0);
if (output.length > 0) {
console.error("\n\nYou have unstaged changes, please commit everything first!");
console.error("Unstaged files:");
console.error(output.map(x => "'" + x + "'").join("\n"));
process.exit(1);
}
}
function copyAdditionalBuildFiles() {
const additionalFolder = path.join("additional_build_files");
const additionalSrcGlobs = [
path.join(additionalFolder, "**/*.*"),
path.join(additionalFolder, "**/.*"),
path.join(additionalFolder, "**/*"),
];
return gulp.src(additionalSrcGlobs).pipe(gulp.dest(buildFolder));
}
export const utils = {
cleanBuildFolder,
cleanBuildOutputFolder,
cleanBuildTempFolder,
cleanImageBuildFolder,
cleanup,
requireCleanWorkingTree,
copyAdditionalBuildFiles,
};
// Starts a webserver on the built directory (useful for testing prod build)
function webserver() {
return gulp.src(buildFolder).pipe(
gulpWebserver({
livereload: {
enable: true,
},
directoryListing: false,
open: true,
port: 3005,
})
);
}
/**
*
* @param {object} param0
* @param {keyof typeof BUILD_VARIANTS} param0.version
*/
async function serveHTML({ version = "web-dev" }) {
browserSync.init({
server: [buildFolder, path.join(baseDir, "mod_examples")],
port: 3005,
ghostMode: false,
logLevel: "info",
logPrefix: "BS",
online: false,
notify: false,
reloadDebounce: 100,
watchEvents: ["add", "change"],
open: false,
});
gulp.watch("../src/js/**", js[version].dev.build);
// Watch .scss files, those trigger a css rebuild
gulp.watch("../src/css/**", css.dev);
// Watch .html files, those trigger a html rebuild
gulp.watch(["../src/html/**", "./preloader/*"], html.dev);
// Watch translations
gulp.watch("../translations/*.yaml", translations.convertToJson);
gulp.watch(
["../res_raw/sounds/sfx/**/*.mp3", "../res_raw/sounds/sfx/**/*.wav"],
gulp.series(sounds.sfx, sounds.copy)
);
gulp.watch(
["../res_raw/sounds/music/**/*.mp3", "../res_raw/sounds/music/**/*.wav"],
gulp.series(sounds.music, sounds.copy)
);
// Watch resource files and copy them on change
gulp.watch(rawImageResourcesGlobs, imgres.buildAtlas);
gulp.watch(nonImageResourcesGlobs, imgres.copyNonImageResources);
gulp.watch(imageResourcesGlobs, imgres.copyImageResources);
// Watch .atlas files and recompile the atlas on change
gulp.watch("../res_built/atlas/*.atlas", imgres.atlasToJson);
gulp.watch("../res_built/atlas/*.json", imgres.atlas);
// Watch the build folder and reload when anything changed
gulp.watch(path.join(buildFolder, "**")).on("change", p =>
gulp.src(pathNative.resolve(p).replaceAll(pathNative.sep, path.sep)).pipe(browserSync.stream())
);
}
// Pre and postbuild
const baseResources = imgres.allOptimized;
async function deleteEmpty() {
await delEmpty(buildFolder);
}
const postbuild = gulp.series(imgres.cleanupUnusedCssInlineImages, deleteEmpty);
export const step = {
baseResources,
deleteEmpty,
postbuild,
};
///////////////////// RUNNABLE TASKS /////////////////////
// Builds everything (dev)
const prepare = {
dev: variant =>
gulp.series(
utils.cleanup,
localConfig.findOrCreate,
gulp.parallel(
utils.copyAdditionalBuildFiles,
gulp.series(imgres.buildAtlas, gulp.parallel(imgres.atlasToJson, imgres.atlas)),
gulp.series(imgres.copyImageResources, css.dev),
imgres.copyNonImageResources,
html.dev,
gulp.series(gulp.parallel(sounds.dev, translations.fullBuild), js[variant].dev.build)
)
),
};
/**
* @typedef {import("gulp").TaskFunction} TaskFunction
*/
export const build =
/**
* @type {Record<string, {
* code: TaskFunction,
* resourcesAndCode: TaskFunction,
* all: TaskFunction,
* full: TaskFunction,
* }> & { prepare: typeof prepare }}
*/
({
prepare,
});
/**
* @type {Record<string, Record<string, TaskFunction>>}
*/
const pack = {};
export { pack as package };
/** @type {Record<string, TaskFunction>} */
export const serve = {};
// Builds everything for every variant
for (const variant in BUILD_VARIANTS) {
const data = BUILD_VARIANTS[variant];
// build
const code = gulp.series(
data.standalone ? sounds.fullbuildHQ : sounds.fullbuild,
translations.fullBuild,
js[variant].prod.build
);
const resourcesAndCode = gulp.parallel(step.baseResources, code);
const all = gulp.series(resourcesAndCode, css.prod, html.prod);
const full = gulp.series(utils.cleanup, all, step.postbuild);
build[variant] = { code, resourcesAndCode, all, full };
// Tasks for creating packages. These packages are already distributable, but usually can be further
// wrapped in a different format (an installer for Windows, tarball for Linux, DMG for macOS).
if (data.standalone) {
const packageTasks = [
"win32-x64",
"win32-arm64",
"linux-x64",
"linux-arm64",
"darwin-x64",
"darwin-arm64",
"all",
];
pack[variant] = {};
for (const task of packageTasks) {
pack[variant][task] = gulp.series(
localConfig.findOrCreate,
full,
utils.cleanBuildOutputFolder,
standalone[variant].prepare.all,
standalone[variant].package[task]
);
}
}
// serve
serve[variant] = gulp.series(build.prepare.dev(variant), () => serveHTML({ version: variant }));
}
// Deploying!
export const deploy = {
staging: gulp.series(
utils.requireCleanWorkingTree,
build["web-shapezio-beta"].full,
ftp.upload.staging.all
),
prod: gulp.series(utils.requireCleanWorkingTree, build["web-shapezio"].full, ftp.upload.prod.all),
};
export const main = {
prepareDocs: docs.prepareDocs,
webserver,
};
// Default task (dev, localhost)
export default gulp.series(serve["standalone-steam"]);

View File

@ -1,21 +1,20 @@
import path from "path/posix";
import fs from "fs";
import gulpYaml from "gulp-yaml";
import fs from "fs/promises";
import YAML from "yaml";
import gulp from "gulp";
import gulpPlumber from "gulp-plumber";
import gulpYaml from "gulp-yaml";
const translationsSourceDir = path.join("..", "translations");
const translationsJsonDir = path.join("..", "src", "js", "built-temp");
export default function gulptasksTranslations(gulp) {
gulp.task("translations.convertToJson", () => {
export function convertToJson() {
return gulp
.src(path.join(translationsSourceDir, "*.yaml"))
.pipe(gulpPlumber())
.pipe(gulpYaml({ space: 2, safe: true }))
.pipe(gulp.dest(translationsJsonDir));
});
gulp.task("translations.fullBuild", gulp.series("translations.convertToJson"));
}
export const fullBuild = convertToJson;

View File

@ -95,7 +95,6 @@ export default {
extensions: [".ts", ".js", ".tsx", ".jsx"],
},
devtool: "cheap-source-map",
watch: true,
cache: false,
plugins: [
new webpack.DefinePlugin(globalDefs),