285 lines
8.6 KiB
TypeScript
285 lines
8.6 KiB
TypeScript
import { DefinePlugin, IgnorePlugin, type Configuration } from "webpack";
|
|
import { findNatives } from "./src/meta/pack/natives.ts";
|
|
import { existingSources } from "./src/meta/pack/sources.ts";
|
|
import CopyPlugin from "copy-webpack-plugin";
|
|
import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer";
|
|
import { readdir } from "node:fs/promises";
|
|
|
|
const self = new URL(import.meta.url).pathname;
|
|
function file(path: string): string {
|
|
return new URL(path, import.meta.url).pathname;
|
|
}
|
|
|
|
export default async (): Promise<Configuration[]> => {
|
|
// global webpack config options
|
|
const defines: Record<string, string> = {};
|
|
const copies: CopyPlugin.Pattern[] = [];
|
|
const aliases: Record<string, string> = {};
|
|
const compiledSources: string[] = [];
|
|
|
|
// read environment to configure the build
|
|
const env =
|
|
process.env.NODE_ENV === "production" ? "production" : "development";
|
|
|
|
const dbSources =
|
|
process.env.DB_SOURCES === "dynamic"
|
|
? "dynamic"
|
|
: process.env.DB_SOURCES === "static"
|
|
? "static"
|
|
: "shared";
|
|
|
|
let disableDbSqlite = process.env.DISABLE_DB_SQLITE === "1";
|
|
let disableBs3 = disableDbSqlite || process.env.DISABLE_BS3 === "1";
|
|
let disableNodeSqlite =
|
|
disableDbSqlite || process.env.DISABLE_NODE_SQLITE === "1";
|
|
|
|
const disableDbApi = process.env.DISABLE_DB_API === "1";
|
|
|
|
// find natives and add them to the build
|
|
const natives: Record<string, string | null> = await findNatives();
|
|
if (disableBs3) natives.sqlite = null;
|
|
if (!natives.sqlite) disableBs3 = true;
|
|
for (const [k, v] of Object.entries(natives)) {
|
|
if (!v) {
|
|
defines[`natives.${k}`] = "null";
|
|
continue;
|
|
}
|
|
defines[`natives.${k}`] =
|
|
"(__dirname+" +
|
|
JSON.stringify("/../natives/" + v.split("/").at(-1)!) +
|
|
")";
|
|
copies.push({ from: v, to: "./natives" });
|
|
}
|
|
|
|
// find binaries and add them to the build
|
|
const binaries = Object.fromEntries(
|
|
(await readdir(file("./src/bin"))).map((bin) => [
|
|
bin.replace(/\..+$/, ""),
|
|
file(`./src/bin/${bin}`),
|
|
])
|
|
);
|
|
for (const bin of Object.keys(binaries)) {
|
|
copies.push({
|
|
from: self,
|
|
to: `./bin/${bin}`,
|
|
toType: "file",
|
|
transform: () =>
|
|
`#!/bin/sh\nexec node --enable-source-maps "$(dirname "$0")/${bin}.cjs" "$@"\n`,
|
|
});
|
|
}
|
|
|
|
// find schemas and add them to the build
|
|
const schemas: string[] = [];
|
|
{
|
|
async function impl(dir: string) {
|
|
for (const file of await readdir(dir, { withFileTypes: true })) {
|
|
if (file.isDirectory()) {
|
|
await impl(dir + "/" + file.name);
|
|
} else if (file.isFile() && file.name.endsWith(".schema.json")) {
|
|
schemas.push(dir + "/" + file.name);
|
|
}
|
|
}
|
|
}
|
|
await impl(file("./src/schema"));
|
|
for (const schema of schemas) {
|
|
copies.push({ from: schema, to: "./schema" });
|
|
}
|
|
}
|
|
|
|
// resolve db sources statically or dynamically
|
|
if (dbSources === "dynamic") {
|
|
console.log("Resolving db interfaces dynamically");
|
|
aliases[file("./src/db/dbSources.ts")] = file("./src/db/dbSources.dyn.ts");
|
|
} else if (dbSources === "static") {
|
|
console.log("Resolving db interfaces statically");
|
|
aliases[file("./src/db/dbSources.ts")] = file(
|
|
"./src/db/dbSources.static.ts"
|
|
);
|
|
} else {
|
|
console.log("Resolving db interfaces shared");
|
|
aliases[file("./src/db/dbSources.ts")] = file(
|
|
"./src/db/dbSources.shared.ts"
|
|
);
|
|
}
|
|
|
|
// disable parts or all of the db interface
|
|
if (disableBs3 && disableNodeSqlite) disableDbSqlite = true;
|
|
if (disableDbSqlite) {
|
|
console.log("Disabling sqlite db interface completely");
|
|
aliases[file("./src/db/sqlite/getdb.static.ts")] = file("./src/db/stub.ts");
|
|
aliases[file("./src/db/sqlite/getdb.dyn.ts")] = file("./src/db/stub.ts");
|
|
} else if (disableBs3) {
|
|
console.log("Disabling better-sqlite3 sqlite db backend");
|
|
aliases[file("./src/db/sqlite/impl/implementations.ts")] = file(
|
|
"./src/db/sqlite/impl/implementations.node.ts"
|
|
);
|
|
compiledSources.push("sqlite");
|
|
} else if (disableNodeSqlite) {
|
|
console.log("Disabling node:sqlite sqlite db backend");
|
|
aliases[file("./src/db/sqlite/impl/implementations.ts")] = file(
|
|
"./src/db/sqlite/impl/implementations.bs3.ts"
|
|
);
|
|
compiledSources.push("sqlite");
|
|
} else {
|
|
console.log(
|
|
"Enabling sqlite db interface with better-sqlite3 and node:sqlite backends"
|
|
);
|
|
aliases[file("./src/db/sqlite/impl/implementations.ts")] = file(
|
|
"./src/db/sqlite/impl/implementations.all.ts"
|
|
);
|
|
compiledSources.push("sqlite");
|
|
}
|
|
|
|
// disable the api db interface
|
|
if (disableDbApi) {
|
|
console.log("Disabling api db interface completely");
|
|
aliases[file("./src/db/api/getdb.static.ts")] = file("./src/db/stub.ts");
|
|
aliases[file("./src/db/api/getdb.dyn.ts")] = file("./src/db/stub.ts");
|
|
} else {
|
|
console.log("Enabling api db interface");
|
|
compiledSources.push("api");
|
|
}
|
|
|
|
// check the compiled sources and add it to the defines
|
|
compiledSources.sort();
|
|
defines.compiledSources = JSON.stringify(compiledSources);
|
|
for (const source of existingSources)
|
|
defines[`compiledSources.${source}`] = JSON.stringify(
|
|
compiledSources.includes(source)
|
|
);
|
|
if (!compiledSources.length) {
|
|
console.warn(
|
|
"No db interface enabled, the builds will be completely useless"
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
// log about the natives we have
|
|
console.log(
|
|
`Using ${Object.values(natives).filter(Boolean).length} natives:`
|
|
);
|
|
for (const [key, path] of Object.entries(natives)) {
|
|
if (path) console.log(`- ${key}: ${path}`);
|
|
else console.warn(`- ${key}: (not found)`);
|
|
}
|
|
|
|
// log about the binaries we're making
|
|
console.log(`Generating ${Object.entries(binaries).length} binaries:`);
|
|
for (const [key, path] of Object.entries(binaries)) {
|
|
console.log(`- ${key}: ${path}`);
|
|
}
|
|
|
|
// generate a json report for the stuff included in the build
|
|
{
|
|
const report = {
|
|
binaries: Object.keys(binaries),
|
|
natives: Object.entries(natives)
|
|
.filter((x) => x[1])
|
|
.map((x) => x[0]),
|
|
db: { mode: dbSources, sources: compiledSources },
|
|
schemas: schemas.map((x) => x.split("/").at(-1)!),
|
|
};
|
|
if (!disableDbSqlite)
|
|
Object.assign(report.db, {
|
|
sqlite: { bs3: !disableBs3, node: !disableNodeSqlite },
|
|
});
|
|
copies.push({
|
|
from: self,
|
|
to: "./report/build.json",
|
|
toType: "file",
|
|
transform: () => JSON.stringify(report, null, 2),
|
|
});
|
|
}
|
|
|
|
const config: Configuration[] = [];
|
|
|
|
config.push({
|
|
mode: env,
|
|
devtool: "source-map",
|
|
target: "node",
|
|
entry: binaries,
|
|
output: {
|
|
path: file("./dist"),
|
|
filename: "bin/[name].cjs",
|
|
chunkFilename: "chunk/bin.[name].chunk.cjs",
|
|
},
|
|
resolve: {
|
|
extensionAlias: {
|
|
".js": [".js", ".ts", ".tsx"],
|
|
},
|
|
extensions: [".js", ".ts"],
|
|
alias: {
|
|
...aliases,
|
|
},
|
|
},
|
|
module: {
|
|
rules: [
|
|
{
|
|
test: /\.sql$/,
|
|
include: file("./src"),
|
|
loader: "raw-loader",
|
|
},
|
|
{
|
|
type: "javascript/esm",
|
|
include: file("./src/schema/validators.ts"),
|
|
use: [
|
|
{
|
|
loader: "val-loader",
|
|
options: {
|
|
executableFile: file("./src/meta/pack/valLoader.ts"),
|
|
loader: file("./src/meta/pack/validators.ts"),
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
test: /\.tsx?$/,
|
|
type: "javascript/esm",
|
|
include: file("./src"),
|
|
use: [
|
|
{
|
|
loader: "ts-loader",
|
|
options: {
|
|
ignoreDiagnostics: true,
|
|
compilerOptions: {
|
|
noEmit: false,
|
|
jsx: "react-jsx",
|
|
diagnostics: false,
|
|
noEmitOnError: false,
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
plugins: [
|
|
new DefinePlugin({
|
|
...defines,
|
|
"import.meta.hot": "undefined",
|
|
}),
|
|
new IgnorePlugin({
|
|
resourceRegExp: /^react-devtools-core$|^\.\/devtools\.js$|^bindings$/,
|
|
}),
|
|
new CopyPlugin({
|
|
patterns: copies,
|
|
}),
|
|
new BundleAnalyzerPlugin({
|
|
openAnalyzer: false,
|
|
analyzerMode: "static",
|
|
reportFilename: "report/bin.html",
|
|
}),
|
|
],
|
|
ignoreWarnings: [
|
|
{
|
|
// webpack doesn't like the `require` used by better-sqlite3
|
|
// it's an indirect call to a runtime string, so it can't be analyzed
|
|
// the way we use it however, we force the argument to be constant at build time
|
|
module: /\/node_modules\/better-sqlite3\/lib\/database\.js/,
|
|
},
|
|
],
|
|
});
|
|
|
|
return config;
|
|
};
|