monkeytype/frontend/vite.config.js
Christian Fehmer 9432602727
impr: add selfhosting using docker only (fehmer) (#5170)
* impr: add selfhosting using docker only

* add recaptcha config and docs

* add documentation on the backend-configuration.json file, remove ---redacted--- from example config

---------

Co-authored-by: Jack <jack@monkeytype.com>
2024-03-12 12:02:13 +01:00

214 lines
5.7 KiB
JavaScript

import { defineConfig, splitVendorChunkPlugin, mergeConfig } from "vite";
import path from "node:path";
import injectHTML from "vite-plugin-html-inject";
import childProcess from "child_process";
import { checker } from "vite-plugin-checker";
import { VitePWA } from "vite-plugin-pwa";
import replace from "vite-plugin-filter-replace";
import Inspect from "vite-plugin-inspect";
import autoprefixer from "autoprefixer";
import "dotenv/config";
function pad(numbers, maxLength, fillString) {
return numbers.map((number) =>
number.toString().padStart(maxLength, fillString)
);
}
function buildClientVersion() {
const date = new Date();
const versionPrefix = pad(
[date.getFullYear(), date.getMonth() + 1, date.getDate()],
2,
"0"
).join(".");
const versionSuffix = pad([date.getHours(), date.getMinutes()], 2, "0").join(
"."
);
const version = [versionPrefix, versionSuffix].join("_");
try {
const commitHash = childProcess
.execSync("git rev-parse --short HEAD")
.toString();
return `${version}.${commitHash}`;
} catch (e) {
return `${version}.unknown-hash`;
}
}
/** @type {import("vite").UserConfig} */
const BASE_CONFIG = {
plugins: [
{
name: "simple-jquery-inject",
async transform(src, id) {
if (id.endsWith(".ts")) {
//check if file has a jQuery or $() call
if (/(?:jQuery|\$)\([^)]*\)/.test(src)) {
//if file has "use strict"; at the top, add it below that line, if not, add it at the very top
if (src.startsWith(`"use strict";`)) {
return src.replace(
/("use strict";)/,
`$1import $ from "jquery";`
);
} else {
return `import $ from "jquery";${src}`;
}
}
}
},
},
checker({
typescript: {
root: path.resolve(__dirname, "./"),
},
eslint: {
lintCommand: `eslint "${path.resolve(__dirname, "./src/ts/**/*.ts")}"`,
},
overlay: {
initialIsOpen: false,
},
}),
injectHTML(),
Inspect(),
],
server: {
open: process.env.SERVER_OPEN !== "false",
port: 3000,
host: process.env.BACKEND_URL !== undefined,
},
root: "src",
publicDir: "../static",
css: {
devSourcemap: true,
postcss: {
plugins: [autoprefixer({})],
},
},
envDir: "../",
build: {
emptyOutDir: true,
outDir: "../dist",
rollupOptions: {
input: {
monkeytype: path.resolve(__dirname, "src/index.html"),
email: path.resolve(__dirname, "src/email-handler.html"),
privacy: path.resolve(__dirname, "src/privacy-policy.html"),
security: path.resolve(__dirname, "src/security-policy.html"),
terms: path.resolve(__dirname, "src/terms-of-service.html"),
404: path.resolve(__dirname, "src/404.html"),
},
output: {
assetFileNames: (assetInfo) => {
let extType = assetInfo.name.split(".").at(1);
if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType)) {
extType = "images";
}
return `${extType}/[name].[hash][extname]`;
},
chunkFileNames: "js/[name].[hash].js",
entryFileNames: "js/[name].[hash].js",
},
},
},
// resolve: {
// alias: {
// "/src": path.resolve(process.cwd(), "src"),
// $: "jquery",
// },
// },
define: {
BACKEND_URL: JSON.stringify(
process.env.BACKEND_URL || "http://localhost:5005"
),
IS_DEVELOPMENT: JSON.stringify(true),
CLIENT_VERSION: JSON.stringify("DEVELOPMENT_CLIENT"),
RECAPTCHA_SITE_KEY: JSON.stringify(
"6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"
),
},
optimizeDeps: {
include: ["jquery"],
},
};
/** @type {import("vite").UserConfig} */
const BUILD_CONFIG = {
plugins: [
splitVendorChunkPlugin(),
VitePWA({
registerType: "autoUpdate",
manifest: {
short_name: "Monkeytype",
name: "Monkeytype",
start_url: "/",
icons: [
{
src: "/images/icons/maskable_icon_x512.png",
sizes: "512x512",
type: "image/png",
purpose: "maskable",
},
{
src: "/images/icons/general_icon_x512.png",
sizes: "512x512",
type: "image/png",
purpose: "any",
},
],
background_color: "#323437",
display: "standalone",
theme_color: "#323437",
},
manifestFilename: "manifest.json",
workbox: {
clientsClaim: true,
cleanupOutdatedCaches: true,
globIgnores: ["**/.*"],
globPatterns: [],
navigateFallback: "",
runtimeCaching: [
{
urlPattern: (options) => {
const isApi = options.url.hostname === "api.monkeytype.com";
return options.sameOrigin && !isApi;
},
handler: "NetworkFirst",
options: {},
},
],
},
}),
replace([
{
filter: /firebase\.ts$/,
replace: {
from: /\.\/constants\/firebase-config/gi,
to: "./constants/firebase-config-live",
},
},
]),
],
define: {
BACKEND_URL: JSON.stringify(
process.env.BACKEND_URL || "https://api.monkeytype.com"
),
IS_DEVELOPMENT: JSON.stringify(false),
CLIENT_VERSION: JSON.stringify(buildClientVersion()),
RECAPTCHA_SITE_KEY: JSON.stringify(process.env.RECAPTCHA_SITE_KEY),
},
};
export default defineConfig(({ command }) => {
if (command === "build") {
if (process.env.RECAPTCHA_SITE_KEY === undefined) {
throw new Error(".env: RECAPTCHA_SITE_KEY is not defined");
}
return mergeConfig(BASE_CONFIG, BUILD_CONFIG);
} else {
return BASE_CONFIG;
}
});