aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/frontend/config/detectDevModeOptions.ts
blob: 665204dc64260baf920b4e23840a3ce6d37ba5e4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
 *
 * SPDX-License-Identifier: EPL-2.0
 */

import type { PluginOption, ServerOptions } from 'vite';

import backendConfigVitePlugin, {
  type BackendConfig,
} from './backendConfigVitePlugin';

export const API_ENDPOINT = 'xtext-service';

export interface DevModeOptions {
  mode: string;
  isDevelopment: boolean;
  devModePlugins: PluginOption[];
  serverOptions: ServerOptions;
}

interface ListenOptions {
  host: string;
  port: number;
  secure: boolean;
}

function detectListenOptions(
  name: string,
  fallbackHost: string,
  fallbackPort: number,
): ListenOptions {
  const host = process.env[`${name}_HOST`] ?? fallbackHost;
  const rawPort = process.env[`${name}_PORT`];
  const port = rawPort === undefined ? fallbackPort : parseInt(rawPort, 10);
  const secure = port === 443;
  return { host, port, secure };
}

function listenURL(
  { host, port, secure }: ListenOptions,
  protocol = 'http',
): string {
  return `${secure ? `${protocol}s` : protocol}://${host}:${port}`;
}

export default function detectDevModeOptions(): DevModeOptions {
  const mode = process.env['MODE'] || 'development';
  const isDevelopment = mode === 'development';

  if (!isDevelopment) {
    return {
      mode,
      isDevelopment,
      devModePlugins: [],
      serverOptions: {},
    };
  }

  const listen = detectListenOptions('LISTEN', 'localhost', 1313);
  // Make sure we always use IPv4 to connect to the backend,
  // because it doesn't listen on IPv6.
  const api = detectListenOptions('API', '127.0.0.1', 1312);
  const publicAddress = detectListenOptions('PUBLIC', listen.host, listen.port);

  const backendConfig: BackendConfig = {
    webSocketURL: `${listenURL(publicAddress, 'ws')}/${API_ENDPOINT}`,
  };

  return {
    mode,
    isDevelopment,
    devModePlugins: [backendConfigVitePlugin(backendConfig)],
    serverOptions: {
      host: listen.host,
      port: listen.port,
      strictPort: true,
      https: listen.secure,
      headers: {
        // Enable strict origin isolation, see e.g.,
        // https://github.com/vitejs/vite/issues/3909#issuecomment-1065893956
        'Cross-Origin-Opener-Policy': 'same-origin',
        'Cross-Origin-Embedder-Policy': 'require-corp',
        'Cross-Origin-Resource-Policy': 'cross-origin',
      },
      proxy: {
        [`/${API_ENDPOINT}`]: {
          target: listenURL(api),
          ws: true,
          secure: api.secure,
        },
      },
      hmr: {
        host: publicAddress.host,
        clientPort: publicAddress.port,
        path: '/vite',
      },
    },
  };
}