137 lines
4.3 KiB
JavaScript
Executable File
137 lines
4.3 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import os from 'node:os';
|
|
|
|
import copy from 'esbuild-plugin-copy';
|
|
|
|
import { cleanPlugin } from './pkg/lib/esbuild-cleanup-plugin.js';
|
|
import { cockpitCompressPlugin } from './pkg/lib/esbuild-compress-plugin.js';
|
|
import { cockpitPoEsbuildPlugin } from './pkg/lib/cockpit-po-plugin.js';
|
|
import { cockpitRsyncEsbuildPlugin } from './pkg/lib/cockpit-rsync-plugin.js';
|
|
import { esbuildStylesPlugins } from './pkg/lib/esbuild-common.js';
|
|
import { eslintPlugin } from './pkg/lib/esbuild-eslint-plugin.js';
|
|
import { stylelintPlugin } from './pkg/lib/esbuild-stylelint-plugin.js';
|
|
|
|
const useWasm = os.arch() !== 'x64';
|
|
const esbuild = (await import(useWasm ? 'esbuild-wasm' : 'esbuild')).default;
|
|
|
|
const production = process.env.NODE_ENV === 'production';
|
|
const watchMode = process.env.ESBUILD_WATCH === "true";
|
|
// linters dominate the build time, so disable them for production builds by default, but enable in watch mode
|
|
const lint = process.env.LINT ? (process.env.LINT !== 0) : (watchMode || !production);
|
|
// List of directories to use when using import statements
|
|
const nodePaths = ['pkg/lib'];
|
|
const outdir = 'dist';
|
|
|
|
// Obtain package name from package.json
|
|
const packageJson = JSON.parse(fs.readFileSync('package.json'));
|
|
|
|
function notifyEndPlugin() {
|
|
return {
|
|
name: 'notify-end',
|
|
setup(build) {
|
|
let startTime;
|
|
|
|
build.onStart(() => {
|
|
startTime = new Date();
|
|
});
|
|
|
|
build.onEnd(() => {
|
|
const endTime = new Date();
|
|
const timeStamp = endTime.toTimeString().split(' ')[0];
|
|
console.log(`${timeStamp}: Build finished in ${endTime - startTime} ms`);
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
const cwd = process.cwd();
|
|
|
|
// similar to fs.watch(), but recursively watches all subdirectories
|
|
function watch_dirs(dir, on_change) {
|
|
const callback = (ev, dir, fname) => {
|
|
// only listen for "change" events, as renames are noisy
|
|
// ignore hidden files
|
|
const isHidden = /^\./.test(fname);
|
|
if (ev !== "change" || isHidden) {
|
|
return;
|
|
}
|
|
on_change(path.join(dir, fname));
|
|
};
|
|
|
|
fs.watch(dir, {}, (ev, path) => callback(ev, dir, path));
|
|
|
|
// watch all subdirectories in dir
|
|
const d = fs.opendirSync(dir);
|
|
let dirent;
|
|
|
|
while ((dirent = d.readSync()) !== null) {
|
|
if (dirent.isDirectory())
|
|
watch_dirs(path.join(dir, dirent.name), on_change);
|
|
}
|
|
d.closeSync();
|
|
}
|
|
|
|
const context = await esbuild.context({
|
|
...!production ? { sourcemap: "linked" } : {},
|
|
bundle: true,
|
|
entryPoints: ['./src/index.js'],
|
|
external: ['*.woff', '*.woff2', '*.jpg', '*.svg', '../../assets*'], // Allow external font files which live in ../../static/fonts
|
|
legalComments: 'external', // Move all legal comments to a .LEGAL.txt file
|
|
loader: { ".js": "jsx" },
|
|
minify: production,
|
|
nodePaths,
|
|
outdir,
|
|
target: ['es2020'],
|
|
plugins: [
|
|
cleanPlugin(),
|
|
...lint
|
|
? [
|
|
stylelintPlugin({ filter: new RegExp(cwd + '\/src\/.*\.(css?|scss?)$') }),
|
|
eslintPlugin({ filter: new RegExp(cwd + '\/src\/.*\.(jsx?|js?)$') })
|
|
]
|
|
: [],
|
|
// Esbuild will only copy assets that are explicitly imported and used
|
|
// in the code. This is a problem for index.html and manifest.json which are not imported
|
|
copy({
|
|
assets: [
|
|
{ from: ['./src/manifest.json'], to: ['./manifest.json'] },
|
|
{ from: ['./src/index.html'], to: ['./index.html'] },
|
|
]
|
|
}),
|
|
...esbuildStylesPlugins,
|
|
cockpitPoEsbuildPlugin(),
|
|
...production ? [cockpitCompressPlugin()] : [],
|
|
cockpitRsyncEsbuildPlugin({ dest: packageJson.name }),
|
|
notifyEndPlugin(),
|
|
]
|
|
});
|
|
|
|
try {
|
|
await context.rebuild();
|
|
} catch (e) {
|
|
if (!watchMode)
|
|
process.exit(1);
|
|
// ignore errors in watch mode
|
|
}
|
|
|
|
if (watchMode) {
|
|
const on_change = async path => {
|
|
console.log("change detected:", path);
|
|
await context.cancel();
|
|
|
|
try {
|
|
await context.rebuild();
|
|
} catch (e) {} // ignore in watch mode
|
|
};
|
|
|
|
watch_dirs('src', on_change);
|
|
|
|
// wait forever until Control-C
|
|
await new Promise(() => {});
|
|
}
|
|
|
|
context.dispose();
|