mirror of
				https://github.com/monkeytypegame/monkeytype.git
				synced 2025-10-28 01:39:29 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			281 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			281 lines
		
	
	
	
		
			7.6 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";
 | |
| import { fontawesomeSubset } from "fontawesome-subset";
 | |
| import { getFontawesomeConfig } from "./scripts/fontawesome";
 | |
| import { generatePreviewFonts } from "./scripts/font-preview";
 | |
| 
 | |
| 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: {
 | |
|         tsconfigPath: path.resolve(__dirname, "./tsconfig.json"),
 | |
|       },
 | |
|       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,
 | |
|   },
 | |
|   clearScreen: false,
 | |
|   root: "src",
 | |
|   publicDir: "../static",
 | |
|   css: {
 | |
|     devSourcemap: true,
 | |
|     postcss: {
 | |
|       plugins: [autoprefixer({})],
 | |
|     },
 | |
|   },
 | |
|   envDir: "../",
 | |
|   build: {
 | |
|     emptyOutDir: true,
 | |
|     outDir: "../dist",
 | |
|     assetsInlineLimit: 0, //dont inline small files as data
 | |
|     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";
 | |
|           }
 | |
|           if (/\.(woff|woff2|eot|ttf|otf)$/.test(assetInfo.name)) {
 | |
|             return `webfonts/[name]-[hash].${extType}`;
 | |
|           }
 | |
|           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"],
 | |
|     exclude: ["@fortawesome/fontawesome-free"],
 | |
|   },
 | |
| };
 | |
| 
 | |
| /** @type {import("vite").UserConfig} */
 | |
| const DEV_CONFIG = {
 | |
|   css: {
 | |
|     preprocessorOptions: {
 | |
|       scss: {
 | |
|         additionalData: `
 | |
|         $fontAwesomeOverride:"@fortawesome/fontawesome-free/webfonts";
 | |
|         $previewFontsPath:"webfonts";
 | |
|         `,
 | |
|       },
 | |
|     },
 | |
|   },
 | |
| };
 | |
| 
 | |
| /** @type {import("vite").UserConfig} */
 | |
| const BUILD_CONFIG = {
 | |
|   plugins: [
 | |
|     {
 | |
|       name: "vite-plugin-fontawesome-subset",
 | |
|       apply: "build",
 | |
|       buildStart() {
 | |
|         const fontawesomeClasses = getFontawesomeConfig();
 | |
|         fontawesomeSubset(fontawesomeClasses, "src/webfonts-generated", {
 | |
|           targetFormats: ["woff2"],
 | |
|         });
 | |
|       },
 | |
|     },
 | |
|     {
 | |
|       name: "vite-plugin-webfonts-preview",
 | |
|       apply: "build",
 | |
|       buildStart() {
 | |
|         generatePreviewFonts();
 | |
|       },
 | |
|     },
 | |
|     splitVendorChunkPlugin(),
 | |
|     VitePWA({
 | |
|       injectRegister: "networkfirst",
 | |
|       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),
 | |
|   },
 | |
|   /** Enable for font awesome v6 */
 | |
|   /*preprocessorOptions: {
 | |
|     scss: {
 | |
|       additionalData(source, fp) {
 | |
|         if (fp.endsWith("index.scss")) {
 | |
|           const fontawesomeClasses = getFontawesomeConfig();
 | |
|           return `
 | |
|           //inject variables into sass context
 | |
|           $fontawesomeBrands: ${sassList(
 | |
|             fontawesomeClasses.brands
 | |
|           )};             
 | |
|           $fontawesomeSolid: ${sassList(fontawesomeClasses.solid)};
 | |
| 
 | |
|           ${source}`;
 | |
|         } else {
 | |
|           return source;
 | |
|         }
 | |
|       },
 | |
|     },
 | |
|   },*/
 | |
| };
 | |
| 
 | |
| 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 mergeConfig(BASE_CONFIG, DEV_CONFIG);
 | |
|   }
 | |
| });
 | |
| 
 | |
| /** Enable for font awesome v6 */
 | |
| /*
 | |
| function sassList(values) {
 | |
|   return values.map((it) => `"${it}"`).join(",");
 | |
| }
 | |
| */
 |