mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2024-09-20 07:16:17 +08:00
impr: detect development mode based on config instead of window.location (fehmer) (#4703)
* impr: detect development mode based on config instead of window.location * Allow access to /configure on the backend using non-local ip * Use webpack define plugin * take BACKEND_URL from env
This commit is contained in:
parent
e9c25f7b15
commit
0f6884a5be
|
@ -83,6 +83,12 @@ Within the `frontend/src/ts/constants` directory, duplicate `firebase-config-exa
|
|||
4. The Firebase config will be visible below
|
||||
5. Paste the config into `firebase-config.ts`
|
||||
|
||||
If you want to access the frontend from other machines on your network create a file `frontend/.env` with this content:
|
||||
|
||||
```
|
||||
BACKEND_URL="http://<Your IP>:5005"
|
||||
```
|
||||
|
||||
### Backend (optional)
|
||||
|
||||
Follow these steps if you want to work on anything involving the database/account system. Otherwise, you can skip this section.
|
||||
|
|
|
@ -52,6 +52,11 @@ function addApiRoutes(app: Application): void {
|
|||
app.use("/configuration", configuration);
|
||||
|
||||
if (process.env.MODE === "dev") {
|
||||
//disable csp to allow assets to load from unsecured http
|
||||
app.use((req, res, next) => {
|
||||
res.setHeader("Content-Security-Policy", "");
|
||||
return next();
|
||||
});
|
||||
app.use("/configure", expressStatic(join(__dirname, "../../../private")));
|
||||
}
|
||||
|
||||
|
|
14
frontend/package-lock.json
generated
14
frontend/package-lock.json
generated
|
@ -6,7 +6,6 @@
|
|||
"packages": {
|
||||
"": {
|
||||
"name": "monkeytype-frontend",
|
||||
"version": "23.40.1",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"axios": "0.21.4",
|
||||
|
@ -48,6 +47,7 @@
|
|||
"copy-webpack-plugin": "10.2.4",
|
||||
"css-loader": "6.7.1",
|
||||
"css-minimizer-webpack-plugin": "3.4.1",
|
||||
"dotenv": "16.3.1",
|
||||
"eslint": "8.43.0",
|
||||
"eslint-webpack-plugin": "3.1.1",
|
||||
"extra-watch-webpack-plugin": "1.0.3",
|
||||
|
@ -6497,6 +6497,18 @@
|
|||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.3.1",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz",
|
||||
"integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/motdotla/dotenv?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/duplexer": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
"dep-graph": "madge -c -i \"dep-graph.png\" ./src/ts",
|
||||
"build": "npx gulp build",
|
||||
"build-live": "export COMMIT_HASH=`git rev-parse --short HEAD` && npx gulp build-production",
|
||||
"dev": "concurrently \"webpack serve --config=./webpack/config.dev.js\" \"npx gulp watch\"",
|
||||
"dev": "concurrently \"NODE_ENV=development webpack serve --config=./webpack/config.dev.js\" \"npx gulp watch\"",
|
||||
"deploy-live": "npm run build-live && firebase deploy -P live --only hosting",
|
||||
"deploy-preview": "npm run build-live && firebase hosting:channel:deploy preview -P live --expires 2h",
|
||||
"tsc": "tsc",
|
||||
|
@ -39,6 +39,7 @@
|
|||
"copy-webpack-plugin": "10.2.4",
|
||||
"css-loader": "6.7.1",
|
||||
"css-minimizer-webpack-plugin": "3.4.1",
|
||||
"dotenv": "16.3.1",
|
||||
"eslint": "8.43.0",
|
||||
"eslint-webpack-plugin": "3.1.1",
|
||||
"extra-watch-webpack-plugin": "1.0.3",
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
import endpoints from "./endpoints";
|
||||
import { buildHttpClient } from "./adapters/axios-adapter";
|
||||
|
||||
const DEV_SERVER_HOST = "http://localhost:5005";
|
||||
const PROD_SERVER_HOST = "https://api.monkeytype.com";
|
||||
import { envConfig } from "../constants/env-config";
|
||||
|
||||
const API_PATH = "";
|
||||
const BASE_URL =
|
||||
window.location.hostname === "localhost" ? DEV_SERVER_HOST : PROD_SERVER_HOST;
|
||||
const BASE_URL = envConfig.backendUrl;
|
||||
const API_URL = `${BASE_URL}${API_PATH}`;
|
||||
|
||||
const httpClient = buildHttpClient(API_URL, 10000);
|
||||
|
|
14
frontend/src/ts/constants/env-config.ts
Normal file
14
frontend/src/ts/constants/env-config.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
interface Config {
|
||||
backendUrl: string;
|
||||
isDevelopment: boolean;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const backendUrl = BACKEND_URL;
|
||||
// @ts-ignore
|
||||
const isDevelopment = IS_DEVELOPMENT;
|
||||
|
||||
export const envConfig: Config = {
|
||||
backendUrl,
|
||||
isDevelopment,
|
||||
};
|
|
@ -520,7 +520,7 @@ async function signUp(): Promise<void> {
|
|||
}
|
||||
|
||||
// Force user to use a capital letter, number, special character and reasonable length when setting up an account and changing password
|
||||
if (!Misc.isLocalhost() && !Misc.isPasswordStrong(password)) {
|
||||
if (!Misc.isDevEnvironment() && !Misc.isPasswordStrong(password)) {
|
||||
Notifications.add(
|
||||
"Password must contain at least one capital letter, number, a special character and must be between 8 and 64 characters long",
|
||||
0,
|
||||
|
|
|
@ -32,7 +32,7 @@ async function updateFavicon(): Promise<void> {
|
|||
let maincolor, bgcolor;
|
||||
bgcolor = await ThemeColors.get("bg");
|
||||
maincolor = await ThemeColors.get("main");
|
||||
if (Misc.isLocalhost()) {
|
||||
if (Misc.isDevEnvironment()) {
|
||||
[maincolor, bgcolor] = [bgcolor, maincolor];
|
||||
}
|
||||
if (bgcolor === maincolor) {
|
||||
|
|
|
@ -160,7 +160,7 @@ function updateFooter(lb: LbKey): void {
|
|||
}
|
||||
|
||||
if (
|
||||
!Misc.isLocalhost() &&
|
||||
!Misc.isDevEnvironment() &&
|
||||
(DB.getSnapshot()?.typingStats?.timeTyping ?? 0) < 7200
|
||||
) {
|
||||
$(`#leaderboardsWrapper table.${side} tfoot`).html(`
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Ape from "../ape";
|
||||
import { isLocalhost, secondsToString } from "../utils/misc";
|
||||
import { isDevEnvironment, secondsToString } from "../utils/misc";
|
||||
import * as Notifications from "./notifications";
|
||||
import format from "date-fns/format";
|
||||
import * as Alerts from "./alerts";
|
||||
|
@ -22,7 +22,7 @@ async function getLatest(): Promise<MonkeyTypes.PSA[] | null> {
|
|||
const response = await Ape.psas.get();
|
||||
|
||||
if (response.status === 500) {
|
||||
if (isLocalhost()) {
|
||||
if (isDevEnvironment()) {
|
||||
Notifications.addBanner(
|
||||
"Dev Info: Backend server not running",
|
||||
0,
|
||||
|
|
|
@ -3,7 +3,7 @@ import { FirebaseApp, initializeApp } from "firebase/app";
|
|||
import { getAuth, Auth as AuthType } from "firebase/auth";
|
||||
import { firebaseConfig } from "./constants/firebase-config"; // eslint-disable-line require-path-exists/exists
|
||||
import * as Notifications from "./elements/notifications";
|
||||
import { createErrorMessage, isLocalhost } from "./utils/misc";
|
||||
import { createErrorMessage, isDevEnvironment } from "./utils/misc";
|
||||
|
||||
// Initialize Firebase
|
||||
export let app: FirebaseApp | undefined;
|
||||
|
@ -16,7 +16,7 @@ try {
|
|||
app = undefined;
|
||||
Auth = undefined;
|
||||
console.error("Authentication failed to initialize", e);
|
||||
if (isLocalhost()) {
|
||||
if (isDevEnvironment()) {
|
||||
Notifications.addBanner(
|
||||
createErrorMessage(e, "Authentication uninitialized") +
|
||||
" Check your firebase-config.ts",
|
||||
|
|
|
@ -128,7 +128,7 @@ const checkPassword = (): void => {
|
|||
).val() as string;
|
||||
|
||||
// Force user to use a capital letter, number, special character and reasonable length when setting up an account and changing password
|
||||
if (!Misc.isLocalhost() && !Misc.isPasswordStrong(password)) {
|
||||
if (!Misc.isDevEnvironment() && !Misc.isPasswordStrong(password)) {
|
||||
if (password.length < 8) {
|
||||
passwordIndicator.show("short", "Password must be at least 8 characters");
|
||||
} else if (password.length > 64) {
|
||||
|
|
|
@ -25,7 +25,7 @@ import {
|
|||
import {
|
||||
createErrorMessage,
|
||||
isElementVisible,
|
||||
isLocalhost,
|
||||
isDevEnvironment,
|
||||
isPasswordStrong,
|
||||
reloadAfter,
|
||||
} from "../utils/misc";
|
||||
|
@ -660,7 +660,7 @@ list["updatePassword"] = new SimplePopup(
|
|||
};
|
||||
}
|
||||
|
||||
if (!isLocalhost() && !isPasswordStrong(newPass)) {
|
||||
if (!isDevEnvironment() && !isPasswordStrong(newPass)) {
|
||||
return {
|
||||
status: 0,
|
||||
message:
|
||||
|
|
|
@ -13,11 +13,12 @@ import * as FunboxList from "./test/funbox/funbox-list";
|
|||
//@ts-ignore
|
||||
import Konami from "konami";
|
||||
import { log } from "./controllers/analytics-controller";
|
||||
import { envConfig } from "./constants/env-config";
|
||||
|
||||
if (Misc.isLocalhost()) {
|
||||
if (Misc.isDevEnvironment()) {
|
||||
$("footer .currentVersion .text").text("localhost");
|
||||
$("body").prepend(
|
||||
`<a class='button configureAPI' href='http://localhost:5005/configure/' target='_blank' aria-label="Configure API" data-balloon-pos="right"><i class="fas fa-fw fa-server"></i></a>`
|
||||
`<a class='button configureAPI' href='${envConfig.backendUrl}/configure/' target='_blank' aria-label="Configure API" data-balloon-pos="right"><i class="fas fa-fw fa-server"></i></a>`
|
||||
);
|
||||
} else {
|
||||
Misc.getLatestReleaseFromGitHub().then((v) => {
|
||||
|
@ -88,7 +89,7 @@ if ("serviceWorker" in navigator) {
|
|||
window.addEventListener("load", () => {
|
||||
// disabling service workers on localhost - they dont really work well with local development
|
||||
// and cause issues with hot reloading
|
||||
if (Misc.isLocalhost()) {
|
||||
if (Misc.isDevEnvironment()) {
|
||||
navigator.serviceWorker.getRegistrations().then(function (registrations) {
|
||||
for (const registration of registrations) {
|
||||
// if (registration.scope !== "https://monkeytype.com/")
|
||||
|
|
|
@ -7,7 +7,7 @@ import * as ConfigEvent from "./observables/config-event";
|
|||
import { debounce, throttle } from "throttle-debounce";
|
||||
import * as TestUI from "./test/test-ui";
|
||||
import { get as getActivePage } from "./states/active-page";
|
||||
import { isLocalhost } from "./utils/misc";
|
||||
import { isDevEnvironment } from "./utils/misc";
|
||||
|
||||
function updateKeytips(): void {
|
||||
const modifierKey = window.navigator.userAgent.toLowerCase().includes("mac")
|
||||
|
@ -39,7 +39,7 @@ function updateKeytips(): void {
|
|||
}
|
||||
}
|
||||
|
||||
if (isLocalhost()) {
|
||||
if (isDevEnvironment()) {
|
||||
window.onerror = function (error): void {
|
||||
Notifications.add(error.toString(), -1);
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { isLocalhost } from "./misc";
|
||||
import { isDevEnvironment } from "./misc";
|
||||
|
||||
const nativeLog = console.log;
|
||||
const nativeWarn = console.warn;
|
||||
|
@ -6,7 +6,7 @@ const nativeError = console.error;
|
|||
|
||||
let debugLogs = localStorage.getItem("debugLogs") === "true" ?? false;
|
||||
|
||||
if (isLocalhost()) {
|
||||
if (isDevEnvironment()) {
|
||||
debugLogs = true;
|
||||
debug("Debug logs automatically enabled on localhost");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as Loader from "../elements/loader";
|
||||
import { normal as normalBlend } from "color-blend";
|
||||
import { envConfig } from "../constants/env-config";
|
||||
|
||||
async function fetchJson<T>(url: string): Promise<T> {
|
||||
try {
|
||||
|
@ -1487,12 +1488,8 @@ export function loadCSS(href: string, prepend = false): void {
|
|||
}
|
||||
}
|
||||
|
||||
export function isLocalhost(): boolean {
|
||||
return (
|
||||
location.hostname === "localhost" ||
|
||||
location.hostname === "127.0.0.1" ||
|
||||
location.hostname === ""
|
||||
);
|
||||
export function isDevEnvironment(): boolean {
|
||||
return envConfig.isDevelopment;
|
||||
}
|
||||
|
||||
export function getBinary(): string {
|
||||
|
@ -1669,7 +1666,7 @@ export function reloadAfter(seconds: number): void {
|
|||
}
|
||||
|
||||
export function updateTitle(title?: string): void {
|
||||
const local = isLocalhost() ? "localhost - " : "";
|
||||
const local = isDevEnvironment() ? "localhost - " : "";
|
||||
|
||||
if (!title) {
|
||||
document.title =
|
||||
|
|
|
@ -3,6 +3,8 @@ const CopyPlugin = require("copy-webpack-plugin");
|
|||
const CircularDependencyPlugin = require("circular-dependency-plugin");
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
const webpack = require("webpack");
|
||||
require("dotenv").config();
|
||||
|
||||
let circularImports = 0;
|
||||
|
||||
|
@ -19,6 +21,15 @@ const htmlWebpackPlugins = [
|
|||
});
|
||||
});
|
||||
|
||||
let BACKEND_URL = "https://api.monkeytype.com";
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
if (process.env.BACKEND_URL) {
|
||||
BACKEND_URL = process.env.BACKEND_URL;
|
||||
} else {
|
||||
BACKEND_URL = "http://localhost:5005";
|
||||
}
|
||||
}
|
||||
|
||||
/** @type { import('webpack').Configuration } */
|
||||
const BASE_CONFIG = {
|
||||
entry: {
|
||||
|
@ -77,6 +88,10 @@ const BASE_CONFIG = {
|
|||
},
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
BACKEND_URL: JSON.stringify(BACKEND_URL),
|
||||
IS_DEVELOPMENT: JSON.stringify(process.env.NODE_ENV === "development"),
|
||||
}),
|
||||
new CircularDependencyPlugin({
|
||||
exclude: /node_modules/,
|
||||
include: /./,
|
||||
|
|
Loading…
Reference in a new issue