taskgenius_taskgenius-plugin/esbuild.config.mjs
Quorafind 7e05356927 chore(security): extract OAuth client secret to environment variable
- Add .env.example with GOOGLE_CLIENT_SECRET_B64 placeholder
- Update esbuild config to inject env vars via define at build time
- Add env.d.ts for TypeScript process.env type declarations
- Use base64 encoding for basic obfuscation of injected secrets

This prevents OAuth client secrets from being committed directly to
the repository. Developers need to create .env with their own secrets.
2025-12-17 15:43:59 +08:00

179 lines
4.5 KiB
JavaScript

import esbuild from "esbuild";
import process from "process";
import builtins from "builtin-modules";
import fs from "fs";
import path from "path";
import dotenv from "dotenv";
import inlineWorkerPlugin from "esbuild-plugin-inline-worker";
import { sassPlugin } from "esbuild-sass-plugin";
// Load environment variables from .env file
dotenv.config();
// Respect release-it dry-run: skip writing build artifacts entirely
const __D_RY__ =
process.env.RELEASE_IT_DRY_RUN === "1" || process.env.RELEASE_IT === "1";
if (__D_RY__) {
console.log("[dry-run] skip esbuild production build");
process.exit(0);
}
const banner = `/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
`;
const prod = process.argv[2] === "production";
const outDir = prod ? "dist" : ".";
// Ensure dist directory exists in production mode
if (prod && !fs.existsSync("dist")) {
fs.mkdirSync("dist", { recursive: true });
}
// Update plugins to handle output directory
const renamePluginWithDir = {
name: "rename-styles",
setup(build) {
build.onEnd(() => {
const { outfile } = build.initialOptions;
const outcss = outfile.replace(/\.js$/, ".css");
const fixcss = outfile.replace(/main\.js$/, "styles.css");
if (fs.existsSync(outcss)) {
console.log("Renaming", outcss, "to", fixcss);
fs.renameSync(outcss, fixcss);
}
});
},
};
// Update CSS settings plugin to handle output directory
const cssSettingsPluginWithDir = {
name: "css-settings-plugin",
setup(build) {
build.onEnd(async (result) => {
// Path to the output CSS file
const cssOutfile = path.join(outDir, "styles.css");
// The settings comment to prepend (read from SCSS file now)
const indexFile = fs.existsSync("src/styles/index.scss")
? "src/styles/index.scss"
: "src/styles/index.css";
const settingsComment =
fs.readFileSync(indexFile, "utf8").split("*/")[0] + "*/\n\n";
if (fs.existsSync(cssOutfile)) {
// Read the current content
const cssContent = fs.readFileSync(cssOutfile, "utf8");
// Check if the settings comment is already there
if (!cssContent.includes("/* @settings")) {
// Prepend the settings comment
fs.writeFileSync(cssOutfile, settingsComment + cssContent);
}
}
});
},
};
// Copy manifest to output directory in production
const copyManifestPlugin = {
name: "copy-manifest",
setup(build) {
build.onEnd(() => {
if (prod) {
fs.copyFileSync(
"manifest.json",
path.join(outDir, "manifest.json"),
);
console.log("Copied manifest.json to", outDir);
}
});
},
};
const buildOptions = {
banner: {
js: banner,
},
define: {
// Inject base64-encoded secrets at build time (decoded at runtime)
"process.env.GOOGLE_CLIENT_SECRET_B64": JSON.stringify(
process.env.GOOGLE_CLIENT_SECRET_B64 || "",
),
},
minify: prod ? true : false,
entryPoints: ["src/index.ts"],
plugins: [
inlineWorkerPlugin({ workerName: "Task Genius Indexer" }),
sassPlugin({
// Enable modern SASS API
type: "css",
// Load paths for @use and @import
loadPaths: [path.resolve(process.cwd(), "src/styles")],
}),
renamePluginWithDir,
cssSettingsPluginWithDir,
copyManifestPlugin,
],
bundle: true,
alias: {
"@": path.resolve(process.cwd(), "src"),
},
external: [
"obsidian",
"electron",
"codemirror",
"@codemirror/autocomplete",
"@codemirror/closebrackets",
"@codemirror/collab",
"@codemirror/commands",
"@codemirror/comment",
"@codemirror/fold",
"@codemirror/gutter",
"@codemirror/highlight",
"@codemirror/history",
"@codemirror/language",
"@codemirror/lint",
"@codemirror/matchbrackets",
"@codemirror/panel",
"@codemirror/rangeset",
"@codemirror/rectangular-selection",
"@codemirror/search",
"@codemirror/state",
"@codemirror/stream-parser",
"@codemirror/text",
"@codemirror/tooltip",
"@codemirror/view",
"@lezer/common",
"@lezer/lr",
"@lezer/highlight",
"obsidian-typings",
...builtins,
],
format: "cjs",
target: "es2018",
logLevel: "info",
sourcemap: prod ? false : "inline",
treeShaking: true,
outfile: path.join(outDir, "main.js"),
pure: prod
? ["console.log", "console.time", "console.timeEnd", "console.info"]
: [],
};
if (prod) {
// Production build
esbuild.build(buildOptions).catch(() => process.exit(1));
} else {
// Development build with watch
esbuild
.context(buildOptions)
.then((ctx) => {
ctx.watch();
console.log("Watching for changes...");
})
.catch(() => process.exit(1));
}