Files
fluxer/fluxer_api/scripts/build.mjs
T

88 lines
2.7 KiB
JavaScript

// SPDX-License-Identifier: AGPL-3.0-or-later
import {existsSync, readFileSync, rmSync, statSync} from 'node:fs';
import {isBuiltin} from 'node:module';
import {dirname, join, resolve} from 'node:path';
import {fileURLToPath} from 'node:url';
import {build} from 'esbuild';
const API_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const REPO_ROOT = resolve(API_ROOT, '..');
const OUT_DIR = join(API_ROOT, 'dist');
const CANDIDATE_SUFFIXES = ['', '.ts', '.tsx', '.js', '.mjs', '/index.ts', '/index.tsx', '/index.js', '/src/index.ts'];
const WORKSPACE_ROOTS = {
'@app/': join(API_ROOT, 'src'),
'@pkgs/': join(API_ROOT, 'pkgs'),
'@fluxer/': join(REPO_ROOT, 'packages'),
};
function resolveWorkspacePath(specifier) {
for (const [prefix, root] of Object.entries(WORKSPACE_ROOTS)) {
if (!specifier.startsWith(prefix)) {
continue;
}
const base = join(root, specifier.slice(prefix.length));
for (const suffix of CANDIDATE_SUFFIXES) {
const candidate = `${base}${suffix}`;
if (existsSync(candidate) && statSync(candidate).isFile()) {
return candidate;
}
}
throw new Error(`Unable to resolve workspace import ${specifier}`);
}
return null;
}
function packageNameOf(specifier) {
const segments = specifier.split('/');
return specifier.startsWith('@') ? segments.slice(0, 2).join('/') : segments[0];
}
const declaredDependencies = new Set(
Object.keys(JSON.parse(readFileSync(join(API_ROOT, 'package.json'), 'utf-8')).dependencies),
);
const undeclaredDependencies = new Set();
const workspacePlugin = {
name: 'fluxer-workspace',
setup(pluginBuild) {
pluginBuild.onResolve({filter: /^[^./]/}, (args) => {
const workspacePath = resolveWorkspacePath(args.path);
if (workspacePath) {
return {path: workspacePath};
}
const packageName = packageNameOf(args.path);
if (!isBuiltin(args.path) && !declaredDependencies.has(packageName)) {
undeclaredDependencies.add(packageName);
}
return {path: args.path, external: true};
});
},
};
rmSync(OUT_DIR, {recursive: true, force: true});
await build({
entryPoints: [join(API_ROOT, 'src/AppEntrypoint.ts'), join(API_ROOT, 'src/WorkerEntrypoint.ts')],
outdir: OUT_DIR,
bundle: true,
platform: 'node',
format: 'esm',
target: 'node24',
charset: 'utf8',
sourcemap: true,
sourcesContent: false,
logLevel: 'info',
banner: {js: '// SPDX-License-Identifier: AGPL-3.0-or-later'},
plugins: [workspacePlugin],
});
if (undeclaredDependencies.size > 0) {
const names = [...undeclaredDependencies].sort().join(', ');
throw new Error(
`The bundle imports packages that fluxer_api does not declare as dependencies: ${names}. ` +
'Workspace packages keep their own node_modules, so the bundle cannot reach them from fluxer_api.',
);
}