diff --git a/README.md b/README.md index a3abd25..5577ce1 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ A simple Typescript Boilerplate that builds incredibly fast using the [SWC Libra - Auto Download Resources - Single Resource Code Support - Fastest Auto Reconnect Time on Recompile +- Compile Multiple Resources at Once - Built-in React for WebViews # Installation @@ -92,3 +93,7 @@ Use the key combination `ctrl + c` to kill your server in your terminal, command ## How to Add Mods, and New Resources Always add your already compiled resources & mods into the `resources` folder. + +## How to ignore specific resources from compiling + +Add file name `.nocompile` to the resource folder you want to ignore from compiling. diff --git a/package.json b/package.json index db8025d..add630a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "altv-quickstart-ts", - "version": "5.0.1", + "version": "5.2.1", "description": "TypeScript with alt:V Made Easy", "scripts": { "[-] Server Deployment Commands (They All Do Different Things)": "", @@ -43,9 +43,11 @@ }, "type": "module", "dependencies": { - "vite": "^4.3.1" + "vite": "^4.3.1", + "fkill": "^8.1.0", + "toml": "^3.0.0" }, "engines": { "node": ">=18" } -} \ No newline at end of file +} diff --git a/scripts/compiler.js b/scripts/compiler.js index b80dec4..1ae6cd5 100644 --- a/scripts/compiler.js +++ b/scripts/compiler.js @@ -1,7 +1,7 @@ import fs from 'fs-extra' import * as glob from 'glob'; import swc from '@swc/core' -import { normalizeFilePath } from './shared.js'; +import { getResources, normalizeFilePath } from './shared.js'; const SWC_CONFIG = { jsc: { @@ -19,21 +19,27 @@ const SWC_CONFIG = { sourceMaps: false, }; -const startTime = Date.now(); -const filesToCompile = glob.sync('./src/core/**/*.ts'); -if (fs.existsSync('resources/core')) { - fs.rmSync('resources/core', { force: true, recursive: true }); -} +async function buildTargetResource(name) { + const startTime = Date.now(); + + if (fs.existsSync(`resources/${name}`)) { + fs.rmSync(`resources/${name}`, { force: true, recursive: true }); + } + const filesToCompile = glob.sync(`./src/${name}/**/*.ts`); + let compileCount = 0; + for (let i = 0; i < filesToCompile.length; i++) { + const filePath = normalizeFilePath(filesToCompile[i]); + const finalPath = filePath.replace('src/', 'resources/').replace('.ts', '.js'); + const compiled = swc.transformFileSync(filePath, SWC_CONFIG); + fs.outputFileSync(finalPath, compiled.code, { encoding: 'utf-8' }); + compileCount += 1; + } -let compileCount = 0; -for (let i = 0; i < filesToCompile.length; i++) { - const filePath = normalizeFilePath(filesToCompile[i]); - const finalPath = filePath.replace('src/', 'resources/').replace('.ts', '.js'); - const compiled = swc.transformFileSync(filePath, SWC_CONFIG); - fs.outputFileSync(finalPath, compiled.code, { encoding: 'utf-8' }); - compileCount += 1; + console.log(`[${name}] Has built ${compileCount} files in ${Date.now() - startTime}ms`) } -console.log(`${compileCount} Files Built | ${Date.now() - startTime}ms`);; +for (let resource of getResources()) { + buildTargetResource(resource); +} diff --git a/scripts/copy.js b/scripts/copy.js index 7409fcc..586f80f 100644 --- a/scripts/copy.js +++ b/scripts/copy.js @@ -1,25 +1,31 @@ import fs from 'fs-extra' import * as glob from 'glob'; -import { normalizeFilePath } from './shared.js'; +import { getResources, normalizeFilePath } from './shared.js'; -const startTime = Date.now(); -const files = glob.sync(['src/core/**/*.!(ts)', 'src-webviews/**/*.toml']) +async function copyResourceAssets(name) { + const startTime = Date.now(); + const files = glob.sync([`./src/${name}/**/*.!(ts)`, './src-webviews/**/*.toml']); -let filesCopied = 0; -for (let file of files) { - const filePath = normalizeFilePath(file); + let filesCopied = 0; + for (let file of files) { + const filePath = normalizeFilePath(file); - if (filePath.includes('src/')) { - const finalPath = filePath.replace('src/', 'resources/'); - fs.copySync(filePath, finalPath, { overwrite: true }); - } + if(filePath.includes('src/')) { + const finalPath = filePath.replace('src/', 'resources/'); + fs.copySync(filePath, finalPath, {overwrite: true}); + } + + if (filePath.includes('src-webviews')) { + const finalPath = filePath.replace('src-webviews/', 'resources/webviews/'); + fs.copySync(filePath, finalPath, { overwrite: true }); + } - if (filePath.includes('src-webviews')) { - const finalPath = filePath.replace('src-webviews/', 'resources/webviews/'); - fs.copySync(filePath, finalPath, { overwrite: true }); + filesCopied += 1; } - filesCopied += 1; + console.log(`[${name}] | ${filesCopied} Files Moved | ${Date.now() - startTime}ms`); } -console.log(`${filesCopied} Files Moved | ${Date.now() - startTime}ms`); \ No newline at end of file +for (let resource of getResources()) { + copyResourceAssets(resource); +} diff --git a/scripts/shared.js b/scripts/shared.js index 266d224..5a1b14a 100644 --- a/scripts/shared.js +++ b/scripts/shared.js @@ -1,4 +1,5 @@ import fs from 'fs-extra'; +import toml from 'toml'; export function normalizeFilePath(filePath) { return filePath.replace(/\\/gm, '/'); @@ -12,4 +13,24 @@ export async function sleep(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }) -} \ No newline at end of file +} + +function shouldCompileResource(name) { + const path = `./src/${name}`; + if (!fs.existsSync(path)) { + return false; + } + return !fs.existsSync(`${path}/.nocompile`); +} + +let serverConfigPath = './server.toml'; +export function getResources() { + if (!fs.existsSync(serverConfigPath)) { + console.log('server.toml does not exist, please create one.'); + return []; + } + const fileContents = fs.readFileSync(serverConfigPath, { encoding: 'utf-8' }); + const serverConfig = toml.parse(fileContents); + serverConfig.resources = serverConfig.resources.filter(shouldCompileResource); + return serverConfig.resources; +} diff --git a/scripts/transform.js b/scripts/transform.js index 6b9146b..59fb259 100644 --- a/scripts/transform.js +++ b/scripts/transform.js @@ -1,6 +1,7 @@ import path from 'path'; import * as glob from 'glob'; import fs from 'fs'; +import { getResources } from './shared.js'; /** * What does this do? @@ -8,9 +9,6 @@ import fs from 'fs'; * This is required for alt:V */ -const resourcePath = path.join(process.cwd(), 'resources/core/**/*.js').replace(/\\/gm, '/'); -const filePaths = glob.sync(resourcePath); - const funcsToIgnore = [ // 'export function', @@ -20,63 +18,72 @@ const funcsToIgnore = [ '=>', ]; -for (let filePath of filePaths) { - const fileContents = fs.readFileSync(filePath, { encoding: 'utf-8' }); - const splitContents = fileContents.split(/\r?\n/); +async function transformResource(name) { + const resourcePath = path.join(process.cwd(), `resources/${name}/**/*.js`).replace(/\\/gm, '/'); + const filePaths = glob.sync(resourcePath); - const filePathing = filePath.split('/'); - filePathing.pop(); - const directoryPath = filePathing.join('/'); + for (let filePath of filePaths) { + const fileContents = fs.readFileSync(filePath, { encoding: 'utf-8' }); + const splitContents = fileContents.split(/\r?\n/); - let wasModified = false; - for (let i = 0; i < splitContents.length; i++) { - if (!splitContents[i].includes('import') && !splitContents[i].includes('export')) { - continue; - } + const filePathing = filePath.split('/'); + filePathing.pop(); + const directoryPath = filePathing.join('/'); - let shouldSkip = false; - for (let funcToIgnore of funcsToIgnore) { - if (splitContents[i].includes(funcToIgnore)) { - shouldSkip = true; - break; + let wasModified = false; + for (let i = 0; i < splitContents.length; i++) { + if (!splitContents[i].includes('import') && !splitContents[i].includes('export')) { + continue; } - } - if (shouldSkip) { - continue; - } + let shouldSkip = false; + for (let funcToIgnore of funcsToIgnore) { + if (splitContents[i].includes(funcToIgnore)) { + shouldSkip = true; + break; + } + } - const filePathReg = new RegExp(/('|").*.('|")/g); - const extractions = splitContents[i].match(filePathReg); - if (extractions === null || !extractions) { - continue; - } + if (shouldSkip) { + continue; + } - const relativeFilePath = extractions[0].replace(/'/gm, '').replace(/"/gm, ''); - if (relativeFilePath.charAt(0) !== '.' && relativeFilePath.charAt(0) !== '/') { - continue; - } + const filePathReg = new RegExp(/('|").*.('|")/g); + const extractions = splitContents[i].match(filePathReg); + if (extractions === null || !extractions) { + continue; + } - const actualFilePath = path.join(directoryPath, relativeFilePath).replace(/\\/gm, '/'); - if (fs.existsSync(actualFilePath)) { - const barrelFileTest = fs.statSync(actualFilePath); - if (barrelFileTest.isDirectory()) { - splitContents[i] = splitContents[i].replace(relativeFilePath, `${relativeFilePath}/index.js`); - wasModified = true; + const relativeFilePath = extractions[0].replace(/'/gm, '').replace(/"/gm, ''); + if (relativeFilePath.charAt(0) !== '.' && relativeFilePath.charAt(0) !== '/') { continue; } + + const actualFilePath = path.join(directoryPath, relativeFilePath).replace(/\\/gm, '/'); + if (fs.existsSync(actualFilePath)) { + const barrelFileTest = fs.statSync(actualFilePath); + if (barrelFileTest.isDirectory()) { + splitContents[i] = splitContents[i].replace(relativeFilePath, `${relativeFilePath}/index.js`); + wasModified = true; + continue; + } + } + + if (!splitContents[i].includes('.js')) { + splitContents[i] = splitContents[i].replace(relativeFilePath, `${relativeFilePath}.js`); + wasModified = true; + } } - if (!splitContents[i].includes('.js')) { - splitContents[i] = splitContents[i].replace(relativeFilePath, `${relativeFilePath}.js`); - wasModified = true; + if (!wasModified) { + continue; } - } - if (!wasModified) { - continue; + const finalFile = splitContents.join('\r\n'); + fs.writeFileSync(filePath, finalFile, { encoding: 'utf-8' }); } +} - const finalFile = splitContents.join('\r\n'); - fs.writeFileSync(filePath, finalFile, { encoding: 'utf-8' }); -} \ No newline at end of file +for (let resource of getResources()) { + transformResource(resource); +} diff --git a/scripts/watch.js b/scripts/watch.js index f30e793..c676dd7 100644 --- a/scripts/watch.js +++ b/scripts/watch.js @@ -1,7 +1,7 @@ - import { spawnSync, spawn, ChildProcess } from 'node:child_process' import Watcher from 'watcher'; import { writeToIpc, sleep } from './shared.js'; +import fkill from 'fkill' const fileWatcher = new Watcher(['./src', './src-webviews'], { recursive: true, renameDetection: true }); const isWindows = process.platform === "win32"; @@ -9,7 +9,6 @@ const altvProcessName = isWindows ? './altv-server.exe' : './altv-server' /** @type {ChildProcess} */ let childProcess = undefined -let rebootDebounce = Date.now() + 0; async function compiler() { console.log(`Starting Compile`) @@ -27,30 +26,16 @@ async function compiler() { } async function reboot() { - if (rebootDebounce > Date.now()) { - return; - } - - rebootDebounce = Date.now() + 1000; writeToIpc('kick-all'); await sleep(250); if (childProcess) { - try { - childProcess.kill(); - } catch (err) { } - - await new Promise((resolve) => { - const interval = setInterval(() => { - if (!childProcess.killed) { - childProcess.kill(); - return; - } + await fkill(':7788') - childProcess = undefined - clearInterval(interval); - resolve(); - }, 100); - }) + if (!childProcess.killed) { + try { + childProcess.kill(); + } catch (err) { } + } } await compiler(); @@ -62,4 +47,4 @@ function start() { reboot(); } -start(); \ No newline at end of file +start();