♻️(frontend) frontend environment free

Until now, the front had to know at build time
the url of the backend and the webrtc server
to be able to communicate with them.
It is not optimal because it means that we need
multiple docker image (1 per environment) to have
the app working, it is not very flexible.

This commit will make the frontend "environment free"
by determining these urls at runtime.
This commit is contained in:
Anthony LC
2024-05-13 10:54:47 +02:00
committed by Anthony LC
parent 88109623ba
commit f0b3090a73
12 changed files with 40 additions and 25 deletions

View File

@@ -1,2 +1,3 @@
NEXT_PUBLIC_API_URL=http://localhost:8071/api/v1.0/
NEXT_PUBLIC_API_ORIGIN=http://localhost:8071
NEXT_PUBLIC_API_URL=/api/v1.0/
NEXT_PUBLIC_SIGNALING_URL=ws://localhost:4444

View File

@@ -1,2 +1 @@
NEXT_PUBLIC_API_URL=https://impress-staging.beta.numerique.gouv.fr/api/v1.0/
NEXT_PUBLIC_SIGNALING_URL=wss://impress-staging.beta.numerique.gouv.fr/ws
NEXT_PUBLIC_API_URL=/api/v1.0/

View File

@@ -1 +1,2 @@
NEXT_PUBLIC_API_ORIGIN=http://test.jest
NEXT_PUBLIC_API_URL=/api/

View File

@@ -5,22 +5,19 @@ import { useAuthStore } from '@/core/auth';
describe('fetchAPI', () => {
beforeEach(() => {
process.env.NEXT_PUBLIC_API_URL = 'http://some.api.url/api/v1.0/';
fetchMock.restore();
});
it('adds correctly the basename', () => {
fetchMock.mock('http://some.api.url/api/v1.0/some/url', 200);
fetchMock.mock('http://test.jest/api/some/url', 200);
void fetchAPI('some/url');
expect(fetchMock.lastUrl()).toEqual(
'http://some.api.url/api/v1.0/some/url',
);
expect(fetchMock.lastUrl()).toEqual('http://test.jest/api/some/url');
});
it('adds the credentials automatically', () => {
fetchMock.mock('http://some.api.url/api/v1.0/some/url', 200);
fetchMock.mock('http://test.jest/api/some/url', 200);
void fetchAPI('some/url', { body: 'some body' });
@@ -45,14 +42,14 @@ describe('fetchAPI', () => {
useAuthStore.setState({ userData: { email: 'test@test.com', id: '1234' } });
fetchMock.mock('http://some.api.url/api/v1.0/some/url', 401);
fetchMock.mock('http://test.jest/api/some/url', 401);
await fetchAPI('some/url');
expect(useAuthStore.getState().userData).toBeUndefined();
expect(mockReplace).toHaveBeenCalledWith(
'http://some.api.url/api/v1.0/authenticate/',
'http://test.jest/api/authenticate/',
);
});
});

View File

@@ -1,4 +1,4 @@
import { login, useAuthStore } from '@/core/auth';
import { baseApiUrl, login, useAuthStore } from '@/core';
/**
* Retrieves the CSRF token from the document's cookies.
@@ -14,7 +14,7 @@ function getCSRFToken() {
}
export const fetchAPI = async (input: string, init?: RequestInit) => {
const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}${input}`;
const apiUrl = `${baseApiUrl()}${input}`;
const { logout } = useAuthStore.getState();
const csrfToken = getCSRFToken();

View File

@@ -1,11 +1,11 @@
import { create } from 'zustand';
import { baseApiUrl } from '@/core/conf';
import { User, getMe } from './api';
export const login = () => {
window.location.replace(
new URL('authenticate/', process.env.NEXT_PUBLIC_API_URL).href,
);
window.location.replace(new URL('authenticate/', baseApiUrl()).href);
};
interface AuthStore {

View File

@@ -0,0 +1,11 @@
export const baseApiUrl = () => {
const origin =
process.env.NEXT_PUBLIC_API_ORIGIN ||
(typeof window !== 'undefined' ? window.location.origin : '');
return `${origin}${process.env.NEXT_PUBLIC_API_URL}`;
};
export const signalingUrl = () =>
process.env.NEXT_PUBLIC_SIGNALING_URL ||
(typeof window !== 'undefined' ? `wss://${window.location.host}/ws` : '');

View File

@@ -1 +1,3 @@
export * from './AppProvider';
export * from './auth';
export * from './conf';

View File

@@ -19,6 +19,7 @@ declare module '*.svg?url' {
namespace NodeJS {
interface ProcessEnv {
NEXT_PUBLIC_API_ORIGIN?: string;
NEXT_PUBLIC_API_URL?: string;
NEXT_PUBLIC_SIGNALING_URL?: string;
}

View File

@@ -3,6 +3,8 @@ import { WebrtcProvider } from 'y-webrtc';
import * as Y from 'yjs';
import { create } from 'zustand';
import { signalingUrl } from '@/core';
import { Pad } from '../types';
export interface PadStore {
@@ -24,7 +26,7 @@ export const usePadStore = create<PadStore>((set) => ({
padsStore: initialState.padsStore,
createProvider: (padId: string) => {
const provider = new WebrtcProvider(padId, new Y.Doc(), {
signaling: [process.env.NEXT_PUBLIC_SIGNALING_URL || ''],
signaling: [signalingUrl()],
});
set(({ padsStore }) => {

View File

@@ -23,7 +23,7 @@ describe('PanelPads', () => {
});
it('renders with no pad to display', async () => {
fetchMock.mock(`/api/documents/?page=1&ordering=-created_at`, {
fetchMock.mock(`end:/api/documents/?page=1&ordering=-created_at`, {
count: 0,
results: [],
});
@@ -40,7 +40,7 @@ describe('PanelPads', () => {
});
it('renders an empty pad', async () => {
fetchMock.mock(`/api/documents/?page=1&ordering=-created_at`, {
fetchMock.mock(`end:/api/documents/?page=1&ordering=-created_at`, {
count: 1,
results: [
{
@@ -59,7 +59,7 @@ describe('PanelPads', () => {
});
it('renders a pad with only 1 member', async () => {
fetchMock.mock(`/api/documents/?page=1&ordering=-created_at`, {
fetchMock.mock(`end:/api/documents/?page=1&ordering=-created_at`, {
count: 1,
results: [
{
@@ -83,7 +83,7 @@ describe('PanelPads', () => {
});
it('renders a non-empty pad', async () => {
fetchMock.mock(`/api/documents/?page=1&ordering=-created_at`, {
fetchMock.mock(`end:/api/documents/?page=1&ordering=-created_at`, {
count: 1,
results: [
{
@@ -111,7 +111,7 @@ describe('PanelPads', () => {
});
it('renders the error', async () => {
fetchMock.mock(`/api/documents/?page=1&ordering=-created_at`, {
fetchMock.mock(`end:/api/documents/?page=1&ordering=-created_at`, {
status: 500,
});
@@ -127,7 +127,7 @@ describe('PanelPads', () => {
});
it('renders with pad panel open', async () => {
fetchMock.mock(`/api/documents/?page=1&ordering=-created_at`, {
fetchMock.mock(`end:/api/documents/?page=1&ordering=-created_at`, {
count: 1,
results: [],
});
@@ -142,7 +142,7 @@ describe('PanelPads', () => {
});
it('closes and opens the pad panel', async () => {
fetchMock.mock(`/api/documents/?page=1&ordering=-created_at`, {
fetchMock.mock(`end:/api/documents/?page=1&ordering=-created_at`, {
count: 1,
results: [],
});

View File

@@ -50,7 +50,8 @@ backend:
frontend:
envVars:
PORT: 8080
NEXT_PUBLIC_API_URL: https://impress.127.0.0.1.nip.io/api/v1.0/
NEXT_PUBLIC_API_ORIGIN: https://impress.127.0.0.1.nip.io
NEXT_PUBLIC_API_URL: /api/v1.0/
NEXT_PUBLIC_SIGNALING_URL: wss://impress.127.0.0.1.nip.io/ws
replicas: 1