aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2022-12-09 23:49:07 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2022-12-11 12:18:43 +0100
commit280a3fab74348697429b7bab56b3436968113d79 (patch)
treee1603153db18f7f35c1bcceb03462409f75002db
parentrefactor(frontend): lazy load XtextClient (diff)
downloadrefinery-280a3fab74348697429b7bab56b3436968113d79.tar.gz
refinery-280a3fab74348697429b7bab56b3436968113d79.tar.zst
refinery-280a3fab74348697429b7bab56b3436968113d79.zip
refactor(frontend): split vite config
Also introduces tsconfig.shared.json to keep track of source files used both and build time and in the browser.
-rw-r--r--subprojects/frontend/.eslintrc.cjs8
-rw-r--r--subprojects/frontend/config/backendConfigVitePlugin.ts27
-rw-r--r--subprojects/frontend/config/detectDevModeOptions.ts94
-rw-r--r--subprojects/frontend/config/fetchPackageMetadata.ts20
-rw-r--r--subprojects/frontend/config/manifest.ts40
-rw-r--r--subprojects/frontend/config/minifyHTMLVitePlugin.ts24
-rw-r--r--subprojects/frontend/config/preloadFontsVitePlugin.ts24
-rw-r--r--subprojects/frontend/package.json5
-rw-r--r--subprojects/frontend/src/xtext/BackendConfig.ts13
-rw-r--r--subprojects/frontend/src/xtext/fetchBackendConfig.ts12
-rw-r--r--subprojects/frontend/tsconfig.json8
-rw-r--r--subprojects/frontend/tsconfig.node.json4
-rw-r--r--subprojects/frontend/tsconfig.shared.json13
-rw-r--r--subprojects/frontend/vite.config.ts183
-rw-r--r--yarn.lock48
15 files changed, 329 insertions, 194 deletions
diff --git a/subprojects/frontend/.eslintrc.cjs b/subprojects/frontend/.eslintrc.cjs
index eadd3fb4..8a7b474a 100644
--- a/subprojects/frontend/.eslintrc.cjs
+++ b/subprojects/frontend/.eslintrc.cjs
@@ -4,6 +4,7 @@ const path = require('node:path');
4const project = [ 4const project = [
5 path.join(__dirname, 'tsconfig.json'), 5 path.join(__dirname, 'tsconfig.json'),
6 path.join(__dirname, 'tsconfig.node.json'), 6 path.join(__dirname, 'tsconfig.node.json'),
7 path.join(__dirname, 'tsconfig.shared.json'),
7]; 8];
8 9
9/** @type {import('eslint').Linter.Config} */ 10/** @type {import('eslint').Linter.Config} */
@@ -86,7 +87,12 @@ module.exports = {
86 }, 87 },
87 }, 88 },
88 { 89 {
89 files: ['.eslintrc.cjs', 'prettier.config.cjs', 'vite.config.ts'], 90 files: [
91 '.eslintrc.cjs',
92 'config/*.ts',
93 'prettier.config.cjs',
94 'vite.config.ts',
95 ],
90 env: { 96 env: {
91 browser: false, 97 browser: false,
92 node: true, 98 node: true,
diff --git a/subprojects/frontend/config/backendConfigVitePlugin.ts b/subprojects/frontend/config/backendConfigVitePlugin.ts
new file mode 100644
index 00000000..7a6bc3db
--- /dev/null
+++ b/subprojects/frontend/config/backendConfigVitePlugin.ts
@@ -0,0 +1,27 @@
1import type { PluginOption } from 'vite';
2
3import type BackendConfig from '../src/xtext/BackendConfig';
4import { ENDPOINT } from '../src/xtext/BackendConfig';
5
6export default function backendConfigVitePlugin(
7 backendConfig: BackendConfig,
8): PluginOption {
9 return {
10 name: 'backend-config',
11 apply: 'serve',
12 configureServer(server) {
13 const config = JSON.stringify(backendConfig);
14 server.middlewares.use((req, res, next) => {
15 if (req.url === `/${ENDPOINT}`) {
16 res.setHeader('Content-Type', 'application/json');
17 res.end(config);
18 } else {
19 next();
20 }
21 });
22 },
23 };
24}
25
26export type { default as BackendConfig } from '../src/xtext/BackendConfig';
27export { ENDPOINT as CONFIG_ENDPOINT } from '../src/xtext/BackendConfig';
diff --git a/subprojects/frontend/config/detectDevModeOptions.ts b/subprojects/frontend/config/detectDevModeOptions.ts
new file mode 100644
index 00000000..b3696241
--- /dev/null
+++ b/subprojects/frontend/config/detectDevModeOptions.ts
@@ -0,0 +1,94 @@
1import type { PluginOption, ServerOptions } from 'vite';
2
3import backendConfigVitePlugin, {
4 type BackendConfig,
5} from './backendConfigVitePlugin';
6
7export const API_ENDPOINT = 'xtext-service';
8
9export interface DevModeOptions {
10 mode: string;
11 isDevelopment: boolean;
12 devModePlugins: PluginOption[];
13 serverOptions: ServerOptions;
14}
15
16interface ListenOptions {
17 host: string;
18 port: number;
19 secure: boolean;
20}
21
22function detectListenOptions(
23 name: string,
24 fallbackHost: string,
25 fallbackPort: number,
26): ListenOptions {
27 const host = process.env[`${name}_HOST`] ?? fallbackHost;
28 const rawPort = process.env[`${name}_PORT`];
29 const port = rawPort === undefined ? fallbackPort : parseInt(rawPort, 10);
30 const secure = port === 443;
31 return { host, port, secure };
32}
33
34function listenURL(
35 { host, port, secure }: ListenOptions,
36 protocol = 'http',
37): string {
38 return `${secure ? `${protocol}s` : protocol}://${host}:${port}`;
39}
40
41export default function detectDevModeOptions(): DevModeOptions {
42 const mode = process.env['MODE'] || 'development';
43 const isDevelopment = mode === 'development';
44
45 if (!isDevelopment) {
46 return {
47 mode,
48 isDevelopment,
49 devModePlugins: [],
50 serverOptions: {},
51 };
52 }
53
54 const listen = detectListenOptions('LISTEN', 'localhost', 1313);
55 // Make sure we always use IPv4 to connect to the backend,
56 // because it doesn't listen on IPv6.
57 const api = detectListenOptions('API', '127.0.0.1', 1312);
58 const publicAddress = detectListenOptions('PUBLIC', listen.host, listen.port);
59
60 const backendConfig: BackendConfig = {
61 webSocketURL: `${listenURL(publicAddress, 'ws')}/${API_ENDPOINT}`,
62 };
63
64 return {
65 mode,
66 isDevelopment,
67 devModePlugins: [backendConfigVitePlugin(backendConfig)],
68 serverOptions: {
69 host: listen.host,
70 port: listen.port,
71 strictPort: true,
72 https: listen.secure,
73 headers: {
74 // Enable strict origin isolation, see e.g.,
75 // https://github.com/vitejs/vite/issues/3909#issuecomment-1065893956
76 'Cross-Origin-Opener-Policy': 'same-origin',
77 'Cross-Origin-Embedder-Policy': 'require-corp',
78 'Cross-Origin-Resource-Policy': 'cross-origin',
79 },
80 proxy: {
81 [`/${API_ENDPOINT}`]: {
82 target: listenURL(api),
83 ws: true,
84 secure: api.secure,
85 },
86 },
87 hmr: {
88 host: publicAddress.host,
89 clientPort: publicAddress.port,
90 path: '/vite',
91 },
92 },
93 };
94}
diff --git a/subprojects/frontend/config/fetchPackageMetadata.ts b/subprojects/frontend/config/fetchPackageMetadata.ts
new file mode 100644
index 00000000..50807b03
--- /dev/null
+++ b/subprojects/frontend/config/fetchPackageMetadata.ts
@@ -0,0 +1,20 @@
1import { readFile } from 'node:fs/promises';
2import path from 'node:path';
3
4import z from 'zod';
5
6const PackageInfo = z.object({
7 name: z.string().min(1),
8 version: z.string().min(1),
9});
10
11export default async function fetchPackageMetadata(
12 thisDir: string,
13): Promise<void> {
14 const contents = await readFile(path.join(thisDir, 'package.json'), 'utf8');
15 const { name: packageName, version: packageVersion } = PackageInfo.parse(
16 JSON.parse(contents),
17 );
18 process.env['VITE_PACKAGE_NAME'] ??= packageName;
19 process.env['VITE_PACKAGE_VERSION'] ??= packageVersion;
20}
diff --git a/subprojects/frontend/config/manifest.ts b/subprojects/frontend/config/manifest.ts
new file mode 100644
index 00000000..3cec777c
--- /dev/null
+++ b/subprojects/frontend/config/manifest.ts
@@ -0,0 +1,40 @@
1import type { ManifestOptions } from 'vite-plugin-pwa';
2
3const manifest: Partial<ManifestOptions> = {
4 lang: 'en-US',
5 name: 'Refinery',
6 short_name: 'Refinery',
7 description: 'An efficient graph sovler for generating well-formed models',
8 theme_color: '#f5f5f5',
9 display_override: ['window-controls-overlay'],
10 display: 'standalone',
11 background_color: '#21252b',
12 icons: [
13 {
14 src: 'icon-192x192.png',
15 sizes: '192x192',
16 type: 'image/png',
17 purpose: 'any maskable',
18 },
19 {
20 src: 'icon-512x512.png',
21 sizes: '512x512',
22 type: 'image/png',
23 purpose: 'any maskable',
24 },
25 {
26 src: 'icon-any.svg',
27 sizes: 'any',
28 type: 'image/svg+xml',
29 purpose: 'any maskable',
30 },
31 {
32 src: 'mask-icon.svg',
33 sizes: 'any',
34 type: 'image/svg+xml',
35 purpose: 'monochrome',
36 },
37 ],
38};
39
40export default manifest;
diff --git a/subprojects/frontend/config/minifyHTMLVitePlugin.ts b/subprojects/frontend/config/minifyHTMLVitePlugin.ts
new file mode 100644
index 00000000..18336d4d
--- /dev/null
+++ b/subprojects/frontend/config/minifyHTMLVitePlugin.ts
@@ -0,0 +1,24 @@
1import { minify, type Options as TerserOptions } from 'html-minifier-terser';
2import type { PluginOption } from 'vite';
3
4export default function minifyHTMLVitePlugin(
5 options?: TerserOptions | undefined,
6): PluginOption {
7 return {
8 name: 'minify-html',
9 apply: 'build',
10 enforce: 'post',
11 transformIndexHtml(html) {
12 return minify(html, {
13 collapseWhitespace: true,
14 collapseBooleanAttributes: true,
15 minifyCSS: true,
16 removeComments: true,
17 removeAttributeQuotes: true,
18 removeRedundantAttributes: true,
19 sortAttributes: true,
20 ...(options ?? {}),
21 });
22 },
23 };
24}
diff --git a/subprojects/frontend/config/preloadFontsVitePlugin.ts b/subprojects/frontend/config/preloadFontsVitePlugin.ts
new file mode 100644
index 00000000..bc6f8eaf
--- /dev/null
+++ b/subprojects/frontend/config/preloadFontsVitePlugin.ts
@@ -0,0 +1,24 @@
1import micromatch from 'micromatch';
2import type { PluginOption } from 'vite';
3
4export default function preloadFontsVitePlugin(
5 fontsGlob: string | string[],
6): PluginOption {
7 return {
8 name: 'refinery-preload-fonts',
9 apply: 'build',
10 enforce: 'post',
11 transformIndexHtml(_html, { bundle }) {
12 return micromatch(Object.keys(bundle ?? {}), fontsGlob).map((href) => ({
13 tag: 'link',
14 attrs: {
15 href,
16 rel: 'preload',
17 type: 'font/woff2',
18 as: 'font',
19 crossorigin: 'anonymous',
20 },
21 }));
22 },
23 };
24}
diff --git a/subprojects/frontend/package.json b/subprojects/frontend/package.json
index db5d3f68..a826755d 100644
--- a/subprojects/frontend/package.json
+++ b/subprojects/frontend/package.json
@@ -7,7 +7,7 @@
7 "build": "cross-env MODE=production vite build", 7 "build": "cross-env MODE=production vite build",
8 "serve": "cross-env MODE=development vite serve", 8 "serve": "cross-env MODE=development vite serve",
9 "typegen": "xstate typegen \"src/**/*.ts?(x)\"", 9 "typegen": "xstate typegen \"src/**/*.ts?(x)\"",
10 "typecheck": "tsc -p tsconfig.node.json && tsc -p tsconfig.json", 10 "typecheck": "tsc -p tsconfig.shared.json && tsc -p tsconfig.node.json && tsc -p tsconfig.json",
11 "lint": "eslint .", 11 "lint": "eslint .",
12 "lint:ci": "eslint -f json -o build/eslint.json .", 12 "lint:ci": "eslint -f json -o build/eslint.json .",
13 "lint:fix": "yarn run lint --fix" 13 "lint:fix": "yarn run lint --fix"
@@ -62,6 +62,7 @@
62 "@types/eslint": "^8.4.10", 62 "@types/eslint": "^8.4.10",
63 "@types/html-minifier-terser": "^7.0.0", 63 "@types/html-minifier-terser": "^7.0.0",
64 "@types/lodash-es": "^4.17.6", 64 "@types/lodash-es": "^4.17.6",
65 "@types/micromatch": "^4.0.2",
65 "@types/ms": "^0.7.31", 66 "@types/ms": "^0.7.31",
66 "@types/node": "^18.11.13", 67 "@types/node": "^18.11.13",
67 "@types/prettier": "^2.7.1", 68 "@types/prettier": "^2.7.1",
@@ -83,10 +84,10 @@
83 "eslint-plugin-react": "^7.31.11", 84 "eslint-plugin-react": "^7.31.11",
84 "eslint-plugin-react-hooks": "^4.6.0", 85 "eslint-plugin-react-hooks": "^4.6.0",
85 "html-minifier-terser": "^7.1.0", 86 "html-minifier-terser": "^7.1.0",
87 "micromatch": "^4.0.5",
86 "prettier": "^2.8.1", 88 "prettier": "^2.8.1",
87 "typescript": "4.9.3", 89 "typescript": "4.9.3",
88 "vite": "^4.0.0", 90 "vite": "^4.0.0",
89 "vite-plugin-inject-preload": "^1.1.1",
90 "vite-plugin-pwa": "^0.13.3", 91 "vite-plugin-pwa": "^0.13.3",
91 "workbox-window": "^6.5.4" 92 "workbox-window": "^6.5.4"
92 } 93 }
diff --git a/subprojects/frontend/src/xtext/BackendConfig.ts b/subprojects/frontend/src/xtext/BackendConfig.ts
new file mode 100644
index 00000000..41737c0b
--- /dev/null
+++ b/subprojects/frontend/src/xtext/BackendConfig.ts
@@ -0,0 +1,13 @@
1/* eslint-disable @typescript-eslint/no-redeclare -- Declare types with their companion objects */
2
3import { z } from 'zod';
4
5export const ENDPOINT = 'config.json';
6
7const BackendConfig = z.object({
8 webSocketURL: z.string().url(),
9});
10
11type BackendConfig = z.infer<typeof BackendConfig>;
12
13export default BackendConfig;
diff --git a/subprojects/frontend/src/xtext/fetchBackendConfig.ts b/subprojects/frontend/src/xtext/fetchBackendConfig.ts
index f8087a70..15e976d8 100644
--- a/subprojects/frontend/src/xtext/fetchBackendConfig.ts
+++ b/subprojects/frontend/src/xtext/fetchBackendConfig.ts
@@ -1,15 +1,7 @@
1/* eslint-disable @typescript-eslint/no-redeclare -- Declare types with their companion objects */ 1import BackendConfig, { ENDPOINT } from './BackendConfig';
2
3import { z } from 'zod';
4
5export const BackendConfig = z.object({
6 webSocketURL: z.string().url(),
7});
8
9export type BackendConfig = z.infer<typeof BackendConfig>;
10 2
11export default async function fetchBackendConfig(): Promise<BackendConfig> { 3export default async function fetchBackendConfig(): Promise<BackendConfig> {
12 const configURL = `${import.meta.env.BASE_URL}config.json`; 4 const configURL = `${import.meta.env.BASE_URL}${ENDPOINT}`;
13 const response = await fetch(configURL); 5 const response = await fetch(configURL);
14 const rawConfig = (await response.json()) as unknown; 6 const rawConfig = (await response.json()) as unknown;
15 return BackendConfig.parse(rawConfig); 7 return BackendConfig.parse(rawConfig);
diff --git a/subprojects/frontend/tsconfig.json b/subprojects/frontend/tsconfig.json
index 0dccec40..35abd789 100644
--- a/subprojects/frontend/tsconfig.json
+++ b/subprojects/frontend/tsconfig.json
@@ -10,8 +10,12 @@
10 "src", 10 "src",
11 "types" 11 "types"
12 ], 12 ],
13 "exclude": ["types/node"], 13 "exclude": [
14 "src/xtext/BackendConfig.ts",
15 "types/node"
16 ],
14 "references": [ 17 "references": [
15 { "path": "./tsconfig.node.json" } 18 { "path": "./tsconfig.node.json" },
19 { "path": "./tsconfig.shared.json" }
16 ] 20 ]
17} 21}
diff --git a/subprojects/frontend/tsconfig.node.json b/subprojects/frontend/tsconfig.node.json
index c4539dbc..f4908bcb 100644
--- a/subprojects/frontend/tsconfig.node.json
+++ b/subprojects/frontend/tsconfig.node.json
@@ -9,8 +9,12 @@
9 }, 9 },
10 "include": [ 10 "include": [
11 ".eslintrc.cjs", 11 ".eslintrc.cjs",
12 "config/*.ts",
12 "prettier.config.cjs", 13 "prettier.config.cjs",
13 "types/node", 14 "types/node",
14 "vite.config.ts" 15 "vite.config.ts"
16 ],
17 "references": [
18 { "path": "./tsconfig.shared.json" }
15 ] 19 ]
16} 20}
diff --git a/subprojects/frontend/tsconfig.shared.json b/subprojects/frontend/tsconfig.shared.json
new file mode 100644
index 00000000..b7e1de55
--- /dev/null
+++ b/subprojects/frontend/tsconfig.shared.json
@@ -0,0 +1,13 @@
1{
2 "extends": "./tsconfig.base.json",
3 "compilerOptions": {
4 "composite": true,
5 "lib": ["ES2022"],
6 "types": [],
7 "emitDeclarationOnly": true,
8 "outDir": "build/typescript"
9 },
10 "include": [
11 "src/xtext/BackendConfig.ts",
12 ]
13}
diff --git a/subprojects/frontend/vite.config.ts b/subprojects/frontend/vite.config.ts
index 08b3db0c..cd9993cc 100644
--- a/subprojects/frontend/vite.config.ts
+++ b/subprojects/frontend/vite.config.ts
@@ -1,160 +1,61 @@
1import { setDefaultResultOrder } from 'node:dns';
2import { readFileSync } from 'node:fs';
3import path from 'node:path'; 1import path from 'node:path';
4import { fileURLToPath } from 'node:url'; 2import { fileURLToPath } from 'node:url';
5 3
6import { lezer } from '@lezer/generator/rollup'; 4import { lezer } from '@lezer/generator/rollup';
7import react from '@vitejs/plugin-react-swc'; 5import react from '@vitejs/plugin-react-swc';
8import { minify } from 'html-minifier-terser'; 6import { defineConfig, type UserConfig as ViteConfig } from 'vite';
9import { defineConfig, type PluginOption } from 'vite';
10import injectPreload from 'vite-plugin-inject-preload';
11import { VitePWA } from 'vite-plugin-pwa'; 7import { VitePWA } from 'vite-plugin-pwa';
12 8
13setDefaultResultOrder('verbatim'); 9import { CONFIG_ENDPOINT } from './config/backendConfigVitePlugin';
10import detectDevModeOptions, {
11 API_ENDPOINT,
12} from './config/detectDevModeOptions';
13import fetchPackageMetadata from './config/fetchPackageMetadata';
14import manifest from './config/manifest';
15import minifyHTMLVitePlugin from './config/minifyHTMLVitePlugin';
16import preloadFontsVitePlugin from './config/preloadFontsVitePlugin';
14 17
15const thisDir = path.dirname(fileURLToPath(import.meta.url)); 18const thisDir = path.dirname(fileURLToPath(import.meta.url));
16 19
17const mode = process.env['MODE'] || 'development'; 20const { mode, isDevelopment, devModePlugins, serverOptions } =
18const isDevelopment = mode === 'development'; 21 detectDevModeOptions();
19process.env['NODE_ENV'] ??= mode;
20
21function portNumberOrElse(envName: string, fallback: number): number {
22 const value = process.env[envName];
23 return value ? parseInt(value, 10) : fallback;
24}
25 22
26const listenHost = process.env['LISTEN_HOST'] || 'localhost'; 23process.env['NODE_ENV'] ??= mode;
27const listenPort = portNumberOrElse('LISTEN_PORT', 1313);
28const apiHost = process.env['API_HOST'] || '127.0.0.1';
29const apiPort = portNumberOrElse('API_PORT', 1312);
30const apiSecure = apiPort === 443;
31const publicHost = process.env['PUBLIC_HOST'] || listenHost;
32const publicPort = portNumberOrElse('PUBLIC_PORT', listenPort);
33const publicSecure = publicPort === 443;
34 24
35const { name: packageName, version: packageVersion } = JSON.parse( 25const fontsGlob = [
36 readFileSync(path.join(thisDir, 'package.json'), 'utf8'), 26 'inter-latin-variable-wghtOnly-normal-*.woff2',
37) as { name: string; version: string }; 27 'jetbrains-mono-latin-variable-wghtOnly-{normal,italic}-*.woff2',
38process.env['VITE_PACKAGE_NAME'] ??= packageName; 28];
39process.env['VITE_PACKAGE_VERSION'] ??= packageVersion;
40 29
41const minifyPlugin: PluginOption = { 30const viteConfig: ViteConfig = {
42 name: 'minify-html',
43 enforce: 'post',
44 async transformIndexHtml(html) {
45 if (isDevelopment) {
46 return html;
47 }
48 return minify(html, {
49 collapseWhitespace: true,
50 collapseBooleanAttributes: true,
51 minifyCSS: true,
52 removeComments: true,
53 removeAttributeQuotes: true,
54 removeRedundantAttributes: true,
55 sortAttributes: true,
56 });
57 },
58};
59
60const backendConfigPlugin: PluginOption = {
61 name: 'backend-config',
62 configureServer(server) {
63 const protocol = publicSecure ? 'wss' : 'ws';
64 const webSocketURL = `${protocol}://${publicHost}:${publicPort}/xtext-service`;
65 const config = JSON.stringify({ webSocketURL });
66 server.middlewares.use((req, res, next) => {
67 if (req.url === '/config.json') {
68 res.setHeader('Content-Type', 'application/json');
69 res.end(config);
70 } else {
71 next();
72 }
73 });
74 },
75};
76
77export default defineConfig({
78 logLevel: 'info', 31 logLevel: 'info',
79 mode, 32 mode,
80 root: thisDir, 33 root: thisDir,
81 cacheDir: path.join(thisDir, 'build/vite/cache'), 34 cacheDir: path.join(thisDir, 'build/vite/cache'),
82 plugins: [ 35 plugins: [
83 minifyPlugin,
84 backendConfigPlugin,
85 react(), 36 react(),
86 injectPreload({
87 files: [
88 {
89 match:
90 /(?:inter-latin-variable-wghtOnly-normal|jetbrains-mono-latin-variable-wghtOnly-(?:italic|normal)).+\.woff2$/,
91 attributes: {
92 type: 'font/woff2',
93 as: 'font',
94 crossorigin: 'anonymous',
95 },
96 },
97 ],
98 }),
99 lezer(), 37 lezer(),
38 preloadFontsVitePlugin(fontsGlob),
39 minifyHTMLVitePlugin(),
100 VitePWA({ 40 VitePWA({
101 strategies: 'generateSW', 41 strategies: 'generateSW',
102 registerType: 'prompt', 42 registerType: 'prompt',
103 injectRegister: null, 43 injectRegister: null,
104 workbox: { 44 workbox: {
105 globPatterns: [ 45 globPatterns: ['**/*.{css,html,js}', ...fontsGlob],
106 '**/*.{css,html,js}',
107 'inter-latin-variable-wghtOnly-normal-*.woff2',
108 'jetbrains-mono-latin-variable-wghtOnly-{normal,italic}-*.woff2',
109 ],
110 dontCacheBustURLsMatching: /\.(?:css|js|woff2?)$/, 46 dontCacheBustURLsMatching: /\.(?:css|js|woff2?)$/,
111 navigateFallbackDenylist: [/^\/xtext-service/], 47 navigateFallbackDenylist: [new RegExp(`^\\/${API_ENDPOINT}$`)],
112 runtimeCaching: [ 48 runtimeCaching: [
113 { 49 {
114 urlPattern: 'config.json', 50 urlPattern: CONFIG_ENDPOINT,
115 handler: 'StaleWhileRevalidate', 51 handler: 'StaleWhileRevalidate',
116 }, 52 },
117 ], 53 ],
118 }, 54 },
119 includeAssets: ['apple-touch-icon.png', 'favicon.svg', 'mask-icon.svg'], 55 includeAssets: ['apple-touch-icon.png', 'favicon.svg'],
120 manifest: { 56 manifest,
121 lang: 'en-US',
122 name: 'Refinery',
123 short_name: 'Refinery',
124 description:
125 'An efficient graph sovler for generating well-formed models',
126 theme_color: '#f5f5f5',
127 display_override: ['window-controls-overlay'],
128 display: 'standalone',
129 background_color: '#21252b',
130 icons: [
131 {
132 src: 'icon-192x192.png',
133 sizes: '192x192',
134 type: 'image/png',
135 purpose: 'any maskable',
136 },
137 {
138 src: 'icon-512x512.png',
139 sizes: '512x512',
140 type: 'image/png',
141 purpose: 'any maskable',
142 },
143 {
144 src: 'icon-any.svg',
145 sizes: 'any',
146 type: 'image/svg+xml',
147 purpose: 'any maskable',
148 },
149 {
150 src: 'mask-icon.svg',
151 sizes: 'any',
152 type: 'image/svg+xml',
153 purpose: 'monochrome',
154 },
155 ],
156 },
157 }), 57 }),
58 ...devModePlugins,
158 ], 59 ],
159 base: '', 60 base: '',
160 define: { 61 define: {
@@ -162,36 +63,18 @@ export default defineConfig({
162 }, 63 },
163 build: { 64 build: {
164 assetsDir: '.', 65 assetsDir: '.',
165 // If we don't control inlining manually, 66 // If we don't control inlining manually, web fonts will be randomly inlined
166 // web fonts will randomly get inlined into the CSS, degrading performance. 67 // into the CSS, which degrades performance.
167 assetsInlineLimit: 0, 68 assetsInlineLimit: 0,
168 outDir: path.join('build/vite', mode), 69 outDir: path.join('build/vite', mode),
169 emptyOutDir: true, 70 emptyOutDir: true,
170 sourcemap: isDevelopment, 71 sourcemap: isDevelopment,
171 minify: !isDevelopment, 72 minify: !isDevelopment,
172 }, 73 },
173 server: { 74 server: serverOptions,
174 host: listenHost, 75};
175 port: listenPort, 76
176 strictPort: true, 77export default defineConfig(async () => {
177 headers: { 78 await fetchPackageMetadata(thisDir);
178 // Enable strict origin isolation, see e.g., 79 return viteConfig;
179 // https://github.com/vitejs/vite/issues/3909#issuecomment-1065893956
180 'Cross-Origin-Opener-Policy': 'same-origin',
181 'Cross-Origin-Embedder-Policy': 'require-corp',
182 'Cross-Origin-Resource-Policy': 'cross-origin',
183 },
184 proxy: {
185 '/xtext-service': {
186 target: `${apiSecure ? 'https' : 'http'}://${apiHost}:${apiPort}`,
187 ws: true,
188 secure: apiSecure,
189 },
190 },
191 hmr: {
192 host: publicHost,
193 clientPort: publicPort,
194 path: '/vite',
195 },
196 },
197}); 80});
diff --git a/yarn.lock b/yarn.lock
index 8d3f7b23..d56377b8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2114,6 +2114,7 @@ __metadata:
2114 "@types/eslint": ^8.4.10 2114 "@types/eslint": ^8.4.10
2115 "@types/html-minifier-terser": ^7.0.0 2115 "@types/html-minifier-terser": ^7.0.0
2116 "@types/lodash-es": ^4.17.6 2116 "@types/lodash-es": ^4.17.6
2117 "@types/micromatch": ^4.0.2
2117 "@types/ms": ^0.7.31 2118 "@types/ms": ^0.7.31
2118 "@types/node": ^18.11.13 2119 "@types/node": ^18.11.13
2119 "@types/prettier": ^2.7.1 2120 "@types/prettier": ^2.7.1
@@ -2141,6 +2142,7 @@ __metadata:
2141 lodash-es: ^4.17.21 2142 lodash-es: ^4.17.21
2142 loglevel: ^1.8.1 2143 loglevel: ^1.8.1
2143 loglevel-plugin-prefix: ^0.8.4 2144 loglevel-plugin-prefix: ^0.8.4
2145 micromatch: ^4.0.5
2144 mobx: ^6.7.0 2146 mobx: ^6.7.0
2145 mobx-react-lite: ^3.4.0 2147 mobx-react-lite: ^3.4.0
2146 ms: ^2.1.3 2148 ms: ^2.1.3
@@ -2151,7 +2153,6 @@ __metadata:
2151 react-dom: ^18.2.0 2153 react-dom: ^18.2.0
2152 typescript: 4.9.3 2154 typescript: 4.9.3
2153 vite: ^4.0.0 2155 vite: ^4.0.0
2154 vite-plugin-inject-preload: ^1.1.1
2155 vite-plugin-pwa: ^0.13.3 2156 vite-plugin-pwa: ^0.13.3
2156 workbox-window: ^6.5.4 2157 workbox-window: ^6.5.4
2157 xstate: ^4.35.0 2158 xstate: ^4.35.0
@@ -2375,6 +2376,13 @@ __metadata:
2375 languageName: node 2376 languageName: node
2376 linkType: hard 2377 linkType: hard
2377 2378
2379"@types/braces@npm:*":
2380 version: 3.0.1
2381 resolution: "@types/braces@npm:3.0.1"
2382 checksum: 3749f7673a03d498ddb2f199b222bb403e53e78ac05a599c757c2049703ece802602c78640af0ff826be0fd2ea8b03daff04ce18806ed739592302195b7a569b
2383 languageName: node
2384 linkType: hard
2385
2378"@types/eslint@npm:^8.4.10": 2386"@types/eslint@npm:^8.4.10":
2379 version: 8.4.10 2387 version: 8.4.10
2380 resolution: "@types/eslint@npm:8.4.10" 2388 resolution: "@types/eslint@npm:8.4.10"
@@ -2436,6 +2444,15 @@ __metadata:
2436 languageName: node 2444 languageName: node
2437 linkType: hard 2445 linkType: hard
2438 2446
2447"@types/micromatch@npm:^4.0.2":
2448 version: 4.0.2
2449 resolution: "@types/micromatch@npm:4.0.2"
2450 dependencies:
2451 "@types/braces": "*"
2452 checksum: 6c678e9c625d5b422c6d2c1001da1c502ecc4457248343bbd324b79fd798a6563e336a4d79630d80e8202312013dd7cf8b4440afa644d04477abd26fde6fba24
2453 languageName: node
2454 linkType: hard
2455
2439"@types/ms@npm:^0.7.31": 2456"@types/ms@npm:^0.7.31":
2440 version: 0.7.31 2457 version: 0.7.31
2441 resolution: "@types/ms@npm:0.7.31" 2458 resolution: "@types/ms@npm:0.7.31"
@@ -5248,7 +5265,7 @@ __metadata:
5248 languageName: node 5265 languageName: node
5249 linkType: hard 5266 linkType: hard
5250 5267
5251"micromatch@npm:^4.0.4": 5268"micromatch@npm:^4.0.4, micromatch@npm:^4.0.5":
5252 version: 4.0.5 5269 version: 4.0.5
5253 resolution: "micromatch@npm:4.0.5" 5270 resolution: "micromatch@npm:4.0.5"
5254 dependencies: 5271 dependencies:
@@ -5258,22 +5275,6 @@ __metadata:
5258 languageName: node 5275 languageName: node
5259 linkType: hard 5276 linkType: hard
5260 5277
5261"mime-db@npm:1.52.0":
5262 version: 1.52.0
5263 resolution: "mime-db@npm:1.52.0"
5264 checksum: 0d99a03585f8b39d68182803b12ac601d9c01abfa28ec56204fa330bc9f3d1c5e14beb049bafadb3dbdf646dfb94b87e24d4ec7b31b7279ef906a8ea9b6a513f
5265 languageName: node
5266 linkType: hard
5267
5268"mime-types@npm:^2.1.35":
5269 version: 2.1.35
5270 resolution: "mime-types@npm:2.1.35"
5271 dependencies:
5272 mime-db: 1.52.0
5273 checksum: 89a5b7f1def9f3af5dad6496c5ed50191ae4331cc5389d7c521c8ad28d5fdad2d06fd81baf38fed813dc4e46bb55c8145bb0ff406330818c9cf712fb2e9b3836
5274 languageName: node
5275 linkType: hard
5276
5277"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": 5278"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2":
5278 version: 3.1.2 5279 version: 3.1.2
5279 resolution: "minimatch@npm:3.1.2" 5280 resolution: "minimatch@npm:3.1.2"
@@ -6871,17 +6872,6 @@ __metadata:
6871 languageName: node 6872 languageName: node
6872 linkType: hard 6873 linkType: hard
6873 6874
6874"vite-plugin-inject-preload@npm:^1.1.1":
6875 version: 1.1.1
6876 resolution: "vite-plugin-inject-preload@npm:1.1.1"
6877 dependencies:
6878 mime-types: ^2.1.35
6879 peerDependencies:
6880 vite: ^2.9.0 || ^3.0.0-0
6881 checksum: a39b0bfa7b37253d96f6837064d1192847fb0b05ce9346091880d9517070f58df84ef710609d1a828df7a0af182018bf0f80b62ac42ff7a8e5dd3cd2040e6de5
6882 languageName: node
6883 linkType: hard
6884
6885"vite-plugin-pwa@npm:^0.13.3": 6875"vite-plugin-pwa@npm:^0.13.3":
6886 version: 0.13.3 6876 version: 0.13.3
6887 resolution: "vite-plugin-pwa@npm:0.13.3" 6877 resolution: "vite-plugin-pwa@npm:0.13.3"