Skip to content
This repository has been archived by the owner on Apr 7, 2023. It is now read-only.

ESBuild builder resource #189

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions resources/[system]/[builders]/esbuild/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/node_modules/
60 changes: 60 additions & 0 deletions resources/[system]/[builders]/esbuild/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
## Esbuilder

What is [esbuild](https://esbuild.github.io/)?
----
"esbuild - An extremely fast JavaScript bundler"
esbuild claims that the current build tools are 10-100x slower than what they really could be. They want to create a simple build API and lead the way for the new build tool era

Why [esbuild](https://esbuild.github.io/)?
----
- Because its extremly fast.
- Easy to use api
- Builtin TypeScript support (no need for an extra plugin)

Why not to use esbuild?
----
- In early development (some features may be buggy)
- Has a small community, therefore it is more difficult to find helpful resources if you ever get stuck

How-to use this resource
====
Using external .js files as configs
----
#### **fxmanifest.lua**
```lua
fx_version 'cerulean'
game 'common'


client_script 'dist/index.js'

esbuild_config 'build.js'
```
#### **build.js**
```js
module.exports = {
entryPoints: [ 'src/main.ts' ],
bundle: true,
minify: true,
outputFile: 'dist/index.js',
}
```

Embedding the config inside the fxmanifest
----
```lua
fx_version 'cerulean'
game 'common'


client_script 'dist/index.js'

esbuild 'label here' {
entryPoints = { 'src/main.ts' },
bundle = true,
minify = true,
outputFile = 'dist/index.js',
}
```

### For more information visit the [esbuild website](https://esbuild.github.io/) and check out the [documentation](https://esbuild.github.io/api/)
63 changes: 63 additions & 0 deletions resources/[system]/[builders]/esbuild/esbuilder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
const fs = require('fs');
const path = require('path');
const workerFarm = require('worker-farm');
const { getResourceConfigs, getFileStat } = require('./util');

let esbuild_configs = {};

const esbuildTask = {
shouldBuild(resourceName) {
let resourceConfigs = getResourceConfigs(resourceName);
// Filter out all the configs that doesn't need to be built, based on the cache
resourceConfigs = resourceConfigs.filter(config => {
let cacheFile = path.resolve('cache/esbuild', resourceName, `cache_${config.label.toLowerCase().replace(/\//g, '-')}_config.json`);
if (!fs.existsSync(cacheFile)) return true;
let cache = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));

// Check the cache for file changes
if(Array.isArray(cache)) {
return cache.some(file => {
let fileStat = getFileStat(file.path);
return fileStat.mtime != file.stat.mtime ||
fileStat.inode != file.stat.inode ||
fileStat.size != file.stat.size;
});
}
return false;
});

if (!resourceConfigs.length) return false;
esbuild_configs[resourceName] = resourceConfigs;
return true;
},

build(resourceName, cb) {
(async () => {
const promises = [];

esbuild_configs[resourceName].forEach(config => {
let promise = new Promise((resolve, reject) => {
const worker = workerFarm(require.resolve('./esbuilder_runner'));
worker({
config,
resourcePath: path.resolve(GetResourcePath(resourceName)),
cachePath: path.resolve('cache/esbuild', resourceName, `cache_${config.label.toLowerCase().replace(/\//g, '-')}_config.json`),
}, function(error, result) {
workerFarm.end(worker);
if (error) reject(error);
if (result) resolve(result);
return;
});
});
promises.push(promise);
});

await Promise.all(promises);

})()
.then(()=>cb(true))
.catch(()=>cb(false));
}
}

RegisterResourceBuildTaskFactory('esbuilder', ()=>esbuildTask);
66 changes: 66 additions & 0 deletions resources/[system]/[builders]/esbuild/esbuilder_runner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const esbuild = require('esbuild');
const fs = require('fs-extra');

function getFileStat(path) {
try {
const stat = fs.statSync(path);
return stat ? {
mtime: stat.mtimeMs,
size: stat.size,
inode: stat.ino,
} : null;
} catch {
return null;
}
}


let cache = [];

class EsbuilderCache {
constructor(inp) {
this.name = "cfx-esbuilder-cache";
// Update the cache
cache.push({
path:inp.config.path,
stat:getFileStat(inp.config.path),
});
}

setup(build) {
build.onLoad({filter:/.*/s}, args => {
cache.push({
path:args.path,
stat:getFileStat(args.path),
});
});
}
}



module.exports = async (input, cb) => {

const {config, resourcePath, cachePath} = input;
const {value:options} = config;

// Disable file watching
options.watch = false;
// Set the working directory to the resourcePath
options.absWorkingDir = resourcePath;

// Add the cache plugin
if (!Array.isArray(options.plugins)) options.plugins = [];
const plugin = new EsbuilderCache(input);
options.plugins.push(plugin);

// Run the build configuration
try {
let result = await esbuild.build(options);
fs.outputFileSync(cachePath, JSON.stringify(cache));
cb(null, result);
} catch(e) {
console.log(e);
cb(e);
}
}
9 changes: 9 additions & 0 deletions resources/[system]/[builders]/esbuild/fxmanifest.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
fx_version 'cerulean'
game 'common'

version '1.0.0'
author 'Aleksander Evensen | github.com/AleksanderEvensen'
description 'Builds resources using esbuild: https://esbuild.github.io/'

server_script 'esbuilder.js'
dependency 'yarn'
11 changes: 11 additions & 0 deletions resources/[system]/[builders]/esbuild/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "esbuild_builder",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"esbuild": "^0.12.28",
"fs-extra": "^10.0.0",
"worker-farm": "^1.7.0"
}
}
71 changes: 71 additions & 0 deletions resources/[system]/[builders]/esbuild/util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
function DebugPrint(label, message, resource) {
switch(label.toLowerCase()) {
case 'error':
label = `^1${label}^7`;
break;
case 'warning':
label = `^3${label}^7`;
break;
case 'info':
label = `^4${label}^7`;
break;
}
console.log(`[^5esbuilder^7] [${resource ? `${resource}:` : ''}${label}] ${message}^7`)
}

// Get the path or internal config from a resource fxmanifest.lua file
function getResourceConfigs(resourceName) {
let configs = [];
let resourcePath = GetResourcePath(resourceName);
// Get embedded configs
for(let i = 0; i < GetNumResourceMetadata(resourceName, 'esbuild'); i++) {
let embeddedConfig = JSON.parse(GetResourceMetadata(resourceName, 'esbuild_extra', i));
if(embeddedConfig != null) {
configs.push({
label: GetResourceMetadata(resourceName, 'esbuild', i),
type:'embedded',
path: path.resolve(resourcePath, 'fxmanifest.lua'),
value: embeddedConfig
});
}
}
// Get the config paths
for(let i = 0; i < GetNumResourceMetadata(resourceName, 'esbuild_config'); i++) {

let configPath = GetResourceMetadata(resourceName, 'esbuild_config', i);
if (fs.existsSync(path.resolve(resourcePath,configPath))) {
try {
let configData = require(path.resolve(resourcePath,configPath));
if(!!configData) {
configs.push({
label:configPath,
type:'external',
path: path.resolve(resourcePath,configPath),
value:configData
});
}
} catch(e) {
console.log(e);
}
} else {
DebugPrint('error', `Could not find the build config file: ${configPath}`, resourceName);
}
}
return configs;
}

function getFileStat(path) {
try {
const stat = fs.statSync(path);

return stat ? {
mtime: stat.mtimeMs,
size: stat.size,
inode: stat.ino,
} : null;
} catch {
return null;
}
}

module.exports = {DebugPrint, getResourceConfigs, getFileStat};
55 changes: 55 additions & 0 deletions resources/[system]/[builders]/esbuild/yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


errno@~0.1.7:
version "0.1.8"
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f"
integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==
dependencies:
prr "~1.0.1"

esbuild@^0.12.28:
version "0.12.28"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.12.28.tgz#84da0d2a0d0dee181281545271e0d65cf6fab1ef"
integrity sha512-pZ0FrWZXlvQOATlp14lRSk1N9GkeJ3vLIwOcUoo3ICQn9WNR4rWoNi81pbn6sC1iYUy7QPqNzI3+AEzokwyVcA==

fs-extra@^10.0.0:
version "10.0.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1"
integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^2.0.0"

graceful-fs@^4.1.6, graceful-fs@^4.2.0:
version "4.2.8"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a"
integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==

jsonfile@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
dependencies:
universalify "^2.0.0"
optionalDependencies:
graceful-fs "^4.1.6"

prr@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=

universalify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==

worker-farm@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8"
integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==
dependencies:
errno "~0.1.7"