Wplace-BlueMarble/build/build.js
2025-07-27 10:19:52 -04:00

93 lines
No EOL
3.6 KiB
JavaScript

/** Builds the userscript using esbuild.
* This will:
* 1. Update the package version across the entire project
* 2. Bundle the JS files into one file (esbuild)
* 3. Bundle the CSS files into one file (esbuild)
* 4. Compress & obfuscate the bundled JS file (terner)
* 5. Create a sourcemap
* @since 0.0.6
*/
// ES Module imports
import esbuild from 'esbuild';
import fs from 'fs';
import { execSync } from 'child_process';
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
// CommonJS imports (require)
const terser = require('terser');
const isGitHub = !!process.env.GITHUB_ACTIONS; // Is this running in a GitHub Action Workflow?
// Tries to bump the version
try {
const update = execSync('node build/update-version.js', { stdio: 'inherit' });
console.log('Version updated in meta file successfully');
} catch (error) {
console.error('Failed to update version number:', error);
process.exit(1);
}
// Fetches the userscript metadata banner
const metaContent = fs.readFileSync('src/BlueMarble.meta.js', 'utf8');
// Compiles a string array of all CSS files
const cssFiles = fs.readdirSync('src/')
.filter(file => file.endsWith('.css'))
.map(file => `src/${file}`);
// Compiles the CSS files
esbuild.build({
entryPoints: cssFiles,
bundle: true,
outfile: 'dist/BlueMarble.user.css',
minify: true
});
// Compiles the JS files
const resultEsbuild = await esbuild.build({
entryPoints: ['src/main.js'], // "Infect" the files from this point (it spreads from this "patient 0")
bundle: true, // Should the code be bundled?
outfile: 'dist/BlueMarble.user.js', // The file the bundled code is exported to
format: 'iife', // What format the bundler bundles the code into
target: 'es2020', // What is the minimum version/year that should be supported? When omited, it attempts to support backwards compatability with legacy browsers
platform: 'browser', // The platform the bundled code will be operating on
legalComments: 'inline', // What level of legal comments are preserved? (Hard: none, Soft: inline)
minify: false, // Should the code be minified?
write: false, // Should we write the outfile?
sourcemap: true,
}).catch(() => process.exit(1));
// Retrieves the JS file and map file
const resultEsbuildJS = resultEsbuild.outputFiles.find(file => file.path.endsWith('.js'));
const resultEsbuildMap = resultEsbuild.outputFiles.find(file => file.path.endsWith('.map'));
// Obfuscates the JS file
let resultTerser = await terser.minify(resultEsbuildJS.text, {
sourceMap: {
//content: resultEsbuildMap.text, // The esbundle sourcemap
filename: 'BlueMarble.user.js', // The file to make a sourcemap for
url: ' ' // (This value is intentional) The sourcemap url to point to.
},
mangle: {
toplevel: true, // Obfuscate top-level class/function names
keep_classnames: false, // Should class names be preserved?
keep_fnames: false, // Should function names be preserved?
reserved: [], // List of keywords to preserve
properties: {
// regex: /.*/, // Yes, I am aware I should be using a RegEx. Yes, like you, I am also suprised the userscript still functions
keep_quoted: true, // Should names in quotes be preserved?
reserved: [] // What properties should be preserved?
},
},
format: {
comments: 'some' // Save legal comments
}
});
// Creates the sourcemap file
fs.writeFileSync('dist/BlueMarble.user.js.map', resultTerser.map.replace(`"sources":["0"]`, `"sources":["BlueMarble.user.js"]`), 'utf8');
// Adds the banner
fs.writeFileSync('dist/BlueMarble.user.js', metaContent + resultTerser.code, 'utf8');