Repository navigation
Expand file tree
/
Copy pathvite.config.js
More file actions
168 lines (156 loc) · 5.32 KB
/
Copy pathvite.config.js
File metadata and controls
168 lines (156 loc) · 5.32 KB
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
import fs from 'fs';
import glob from 'fast-glob';
import { createMockApi } from './test-server/mock-api.js';
import { createExtensionArchive } from './test-server/extension-archive.js';
const packagesDir = path.resolve(__dirname, 'packages');
const testServerDir = path.resolve(__dirname, 'test-server');
const extensionDir = path.resolve(testServerDir, 'configurator-extension');
const ignorePkg = (pkgName) => {
return pkgName.startsWith('.') ||
pkgName === 'analytics-browser-test' ||
pkgName === 'analytics-node-test';
}
function htmlEntriesPlugin(pattern = '**/*.html', { cwd, ignore = [] }) {
return {
name: 'vite-html-entries',
config: () => ({
build: {
rollupOptions: {
input: Object.fromEntries(
require('fast-glob').sync(pattern, { cwd, ignore }).map(f => [
f.replace(/\.html$/, ''), // key without ".html"
require('path').join(cwd, f) // absolute file path
])
)
}
}
})
};
}
function gzipServePlugin() {
return {
name: 'gzip-serve',
configureServer(server) {
server.middlewares.use((req, res, next) => {
if (req.url && req.url.endsWith('.gz')) {
// Set Content-Encoding header for gzip files
res.setHeader('Content-Encoding', 'gzip');
// Determine the original content type by removing .gz extension
const originalPath = req.url.replace(/\.gz$/, '');
if (originalPath.endsWith('.js')) {
res.setHeader('Content-Type', 'application/javascript');
} else if (originalPath.endsWith('.css')) {
res.setHeader('Content-Type', 'text/css');
} else if (originalPath.endsWith('.html')) {
res.setHeader('Content-Type', 'text/html');
} else if (originalPath.endsWith('.json')) {
res.setHeader('Content-Type', 'application/json');
} else {
res.setHeader('Content-Type', 'application/octet-stream');
}
// Add Vary header to indicate that the response varies by Accept-Encoding
res.setHeader('Vary', 'Accept-Encoding');
}
next();
});
}
};
}
function fileListingPlugin() {
return {
name: 'file-listing',
configureServer(server) {
server.middlewares.use('/api/list-files', async (req, res) => {
try {
const files = await glob('**/*.html', {
cwd: testServerDir,
absolute: false,
ignore: ['**/dist/**', '**/trc-e2e/**', '**/nuqs-spa/**']
});
const fileList = files.map(file => ({
name: path.basename(file, '.html'),
path: '/' + file,
}));
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(fileList));
} catch (error) {
console.error('Error listing files:', error);
res.statusCode = 500;
res.end(JSON.stringify({ error: 'Failed to list files' }));
}
});
}
};
}
function spaRoutingPlugin() {
return {
name: 'spa-routing',
configureServer(server) {
server.middlewares.use((req, res, next) => {
// Handle SPA routes - serve spa-test.html for all /spa-test.html/* routes
if (req.url && req.url.startsWith('/spa-test.html/')) {
req.url = '/spa-test.html';
}
next();
});
}
};
}
const amplitudeAliases = fs.readdirSync(packagesDir).reduce((aliases, pkgName) => {
const fullPath = path.join(packagesDir, pkgName);
if (ignorePkg(pkgName)) {
return aliases;
}
const key = `@amplitude/${pkgName}`;
aliases[key] = fullPath;
return aliases;
}, {});
export default defineConfig({
envDir: path.resolve(__dirname),
root: testServerDir,
publicDir: packagesDir,
resolve: {
alias: amplitudeAliases
},
server: {
// Listen on all interfaces so simulators/emulators/devices can reach the mock API.
host: process.env.SSH ? 'local.website.com' : true,
https: process.env.SSH ? {
key: fs.readFileSync(path.resolve(process.env.HOME, 'certs/local-website/key.pem')),
cert: fs.readFileSync(path.resolve(process.env.HOME, 'certs/local-website/cert.pem')),
} : undefined,
fs: {
allow: [
packagesDir,
testServerDir,
]
},
watch: {
usePolling: true,
interval: 100,
ignored: ['**/node_modules/**', '**/dist/**'],
},
},
preview: {
port: 5173,
host: true,
},
plugins: [
// These standalone React SPAs have dedicated Vite configs (`dev:trc` and `dev:nuqs`).
// Their root-relative entry points must not be swept into the shared multi-page build.
htmlEntriesPlugin('**/*.html', { cwd: testServerDir, ignore: ['**/trc-e2e/**', '**/nuqs-spa/**'] }),
// Scoped to configurator/ so the babel + react-refresh transform stays off the other test pages
// and the packages/* builds they pull in.
react({ include: [/\/configurator\/.*\.[jt]sx?$/] }),
gzipServePlugin(),
fileListingPlugin(),
spaRoutingPlugin(),
createMockApi(),
// Offers the configurator's runner extension as a download, since it isn't in the Chrome Web Store.
createExtensionArchive(extensionDir),
],
});