@soleil-se/build-app
Version:
Script for building WebApps, RESTApps, Widgets and MCP Servers with Svelte in Sitevision.
164 lines (151 loc) • 5.47 kB
JavaScript
import fse from 'fs-extra';
import args from '@soleil-se/build-utils/args';
import runTasks from '@soleil-se/build-utils/runTasks';
import task from '@soleil-se/build-utils/task';
import watch from '@soleil-se/build-utils/watch';
import { logError, logStartup, logTimestamp, logEnvironment } from '@soleil-se/build-utils/log';
import createChecksumChecker from '@soleil-se/build-utils/createChecksumChecker';
import { env, rollup } from '@soleil-se/build-config';
import { globSync } from 'glob';
import picomatch from 'picomatch';
import { readManifest } from './manifest.js';
import { clean, copy, files, zip, eslint } from './utils/index.js';
import { client, server } from './rollup/index.js';
import { activate, upload, sign } from './requests/index.js';
import config from './config/index.js';
/**
* Get the watch options based on the command line arguments and environment variables.
* @returns {Object} The watch options.
*/
function getWatchOptions() {
const paths = ['.'].concat(args['append-watch'] || args['append-watch-path'] || []);
const ignored = picomatch(
[
'**/node_modules',
'**/dist',
'**/.*',
'**/*.md',
'**/package-lock.json',
'**/pnpm-lock.yaml',
'**/yarn.lock',
'**/*.log',
'**/.env',
'**/*config*.*',
].concat(args['ignore-watch'] || []),
{ dot: true },
);
return { paths, ignored };
}
/**
* Get the minimum Sitevision version based on the @sitevision/api package version.
* @returns {Promise<string>} The minimum Sitevision version.
*/
async function getMinimumSitevisionVersion() {
const packageJson = await fse.readJSON('./package.json');
return (packageJson.dependencies['@sitevision/api'] || '2025.4.1').replace(/^[\^~]/, '');
}
/** @type {string|undefined} The last activated version of the addon */
let lastActivatedVersion;
/**
* Check if the addon should be activated by comparing the current version in the manifest with the last activated version.
* @returns {Promise<boolean>} True if the addon should be activated, false otherwise.
*/
async function shouldActivate() {
const manifest = await readManifest();
if (manifest.version === lastActivatedVersion) return false;
lastActivatedVersion = manifest.version;
return true;
}
async function main() {
const manifest = await readManifest();
const minimumSitevisionVersion = await getMinimumSitevisionVersion();
const zipPath = `./dist/${manifest.id}-${manifest.version}.zip`;
logTimestamp(`${manifest.name} (${manifest.id})`);
logStartup(import.meta.url);
if (!manifest.bundled) {
logError('WebApps 1 is no longer supported. To use WebApps 2 set bundled to true in manifest.json.');
process.exit(1);
}
if (!args.project && args.sync && env) {
logEnvironment(env);
}
const tasks = [
task('clean', clean({ dir: './dist' })),
args.eslint && task('eslint', eslint({ src: ['./**/*.{js,ts,svelte}'] })),
task('copy', [
copy({ src: ['./manifest.json', './i18n/*.json', './appDataDefaults.json'], dest: './dist/src' }),
copy({ src: ['./src/manifest.json', './src/appDataDefaults.json', './src/i18n/*.json', './src/config', './src/resource'], dest: './dist' }),
]),
task('server', server({
input: './src/index.{js,ts}',
output: './dist/src/index.js',
debug: args.debug,
cache: args.cache,
extractCss: true,
}), () => globSync('./src/index.{js,ts}').length),
task('client', client({
input: './src/main.{js,ts}',
output: './dist/src/main.js',
globals: rollup?.client?.globals,
debug: args.debug,
cache: args.cache,
extractCss: true,
}), () => globSync('./src/main.{js,ts}').length),
task('headless', server({
input: './src/headless.{js,ts}',
output: './dist/src/headless.js',
debug: args.debug,
cache: args.cache,
extractCss: true,
}), () => globSync('./src/headless.{js,ts}').length),
task('hooks', server({
input: './src/hooks.{js,ts}',
output: './dist/src/hooks.js',
debug: args.debug,
cache: args.cache,
extractCss: true,
}), () => globSync('./src/hooks.{js,ts}').length),
task('config', config({
src: './config',
dest: './dist/src/config',
cache: args.cache,
debug: args.debug,
}), () => fse.existsSync('./config')),
task('globalConfig', config({
src: './config_global',
dest: './dist/src/config/global',
cache: args.cache,
}), () => fse.existsSync('./config_global')),
task('files', files({ manifest, minimumSitevisionVersion, dest: './dist' })),
task('zip', zip({ src: './dist/src', dest: zipPath })),
];
if (args.sign ?? env?.sign ?? env?.production) {
tasks.push(task('sign', sign({ src: zipPath })));
}
if (args.sync) {
tasks.push(task('upload', upload({
src: zipPath,
force: args.force || !env?.production,
})));
if (args.activate) {
tasks.push(task('activate', activate(), shouldActivate));
}
}
if (args.watch) {
const { paths, ignored } = getWatchOptions(args);
watch(paths, () => runTasks(tasks), {
message: 'Watching for changes...',
ignored,
});
if (!args.project) createChecksumChecker();
} else {
await runTasks(tasks);
}
if (args.build) await runTasks(tasks);
}
main().catch((e) => {
logError(e.message);
logError(e.stack);
process.exit(1);
});
process.on('unhandledRejection', () => {});