Repository navigation
Expand file tree
/
Copy pathvite.config.js
More file actions
78 lines (74 loc) · 2.81 KB
/
Copy pathvite.config.js
File metadata and controls
78 lines (74 loc) · 2.81 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
import { defineConfig } from 'vite';
import { viteSingleFile } from 'vite-plugin-singlefile';
import { build as esbuild } from 'esbuild';
import { fileURLToPath } from 'node:url';
import path from 'node:path';
import fs from 'node:fs';
const root = path.dirname(fileURLToPath(import.meta.url));
// Bundles an AudioWorklet entry (and everything it imports) into one classic
// script string, exposed as `import code from 'virtual:worklet:src/dsp/worklet.js'`.
// The audio engine turns the string into a Blob URL for audioWorklet.addModule(),
// which works the same in `vite dev`, normal builds, the single-file build, and Electron.
function workletString() {
const PREFIX = 'virtual:worklet:';
return {
name: 'orograph-worklet-string',
resolveId(id) {
if (id.startsWith(PREFIX)) return '\0' + id;
return null;
},
async load(id) {
if (!id.startsWith('\0' + PREFIX)) return null;
const entry = path.resolve(root, id.slice(PREFIX.length + 1));
const result = await esbuild({
entryPoints: [entry],
bundle: true,
write: false,
format: 'iife',
target: 'es2020',
minify: process.env.NODE_ENV === 'production',
metafile: true,
});
for (const input of Object.keys(result.metafile.inputs)) this.addWatchFile(path.resolve(root, input));
return `export default ${JSON.stringify(result.outputFiles[0].text)};`;
},
};
}
// In the one-file offline build there is no folder next to the HTML file, so
// inline the SVG favicon and drop links that would point at missing files.
function singleFileHead() {
return {
name: 'orograph-single-file-head',
transformIndexHtml: {
order: 'post',
handler(html) {
const svg = fs.readFileSync(path.resolve(root, 'public/favicon.svg'));
const dataUri = `data:image/svg+xml;base64,${svg.toString('base64')}`;
return html.replace(/<link\b[^>]*\brel="(icon|apple-touch-icon|manifest)"[^>]*>\s*/g, (tag, rel) =>
rel === 'icon' && /favicon\.svg/.test(tag) ? tag.replace(/href="[^"]*"/, `href="${dataUri}"`) : '');
},
},
};
}
export default defineConfig(({ mode }) => ({
base: './',
plugins: [
workletString(),
...(mode === 'single' ? [viteSingleFile({ removeViteModuleLoader: true }), singleFileHead()] : []),
],
build: {
outDir: mode === 'single' ? 'dist-single' : 'dist',
copyPublicDir: mode !== 'single',
target: 'es2022',
chunkSizeWarningLimit: 4000,
assetsInlineLimit: mode === 'single' ? 100_000_000 : 4096,
},
server: { host: '127.0.0.1', port: 5173 },
test: {
include: ['tests/**/*.test.js'],
environment: 'node',
// Offline audio renders take a few seconds on a busy machine or CI runner;
// a slow pass is not a failure (a hung test still is, after 30 s).
testTimeout: 30000,
},
}));