atagen

malice

public
Star0
Watch0
2021154f9e16d427af2b4379df1017f1c9e10072
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git
web/vite.config.tsTypescript98 lines3.0 KB
1
import { readdirSync, readFileSync } from 'node:fs';
2
import { join } from 'node:path';
3
import { fileURLToPath } from 'node:url';
4
import { defineConfig } from 'vite';
5
import { svelte } from '@sveltejs/vite-plugin-svelte';
6
7
/**
8
 * The page isn't SW-controlled on first launch, so the worker chunk and the
9
 * wasm can bypass fetch interception entirely and never get cached. Instead
10
 * of relying on runtime fetches, prepend the full list of emitted files
11
 * (chunks, assets, wasm) to sw.js as a global so install() can precache all
12
 * of it directly, no separate request needed.
13
 */
14
function precacheManifestPlugin(): import('vite').Plugin {
15
  return {
16
    name: 'malice-sw-precache-manifest',
17
    generateBundle(_options, bundle) {
18
      const urls = Object.keys(bundle)
19
        .filter((fileName) => fileName !== 'sw.js' && !fileName.startsWith('twemoji/'))
20
        .map((fileName) => `/${fileName}`);
21
      const swChunk = bundle['sw.js'];
22
      if (swChunk && swChunk.type === 'chunk') {
23
        swChunk.code = `self.__MALICE_PRECACHE__=${JSON.stringify(urls)};\n${swChunk.code}`;
24
      }
25
    }
26
  };
27
}
28
29
function twemojiPlugin(): import('vite').Plugin {
30
  const dir = fileURLToPath(new URL('./node_modules/@twemoji/svg', import.meta.url));
31
  const svgs = () => readdirSync(dir).filter((f) => f.endsWith('.svg'));
32
  return {
33
    name: 'malice-twemoji',
34
    configureServer(server) {
35
      server.middlewares.use('/twemoji', (req, res, next) => {
36
        const name = decodeURIComponent((req.url ?? '').split('?')[0]).replace(/^\//, '');
37
        if (!/^[0-9a-f-]+\.svg$/.test(name)) return next();
38
        try {
39
          res.setHeader('Content-Type', 'image/svg+xml');
40
          res.end(readFileSync(join(dir, name)));
41
        } catch {
42
          res.statusCode = 404;
43
          res.end();
44
        }
45
      });
46
    },
47
    generateBundle() {
48
      for (const file of svgs()) {
49
        this.emitFile({ type: 'asset', fileName: `twemoji/${file}`, source: readFileSync(join(dir, file)) });
50
      }
51
    }
52
  };
53
}
54
55
export default defineConfig(({ mode }) => {
56
  const device = mode === 'device';
57
  return {
58
    plugins: [svelte(), twemojiPlugin(), ...(device ? [precacheManifestPlugin()] : [])],
59
    assetsInclude: ['**/*.wasm'],
60
    resolve: {
61
      alias: {
62
        'malice:device-transport': device ? '/src/lib/device-transport.ts' : '/src/lib/device-transport.stub.ts'
63
      }
64
    },
65
    server: {
66
      host: '127.0.0.1',
67
      port: 5173,
68
      proxy: {
69
        '/api': 'http://localhost:3000'
70
      }
71
    },
72
    preview: {
73
      host: '127.0.0.1',
74
      port: 4173,
75
      proxy: {
76
        '/api': 'http://localhost:3000'
77
      }
78
    },
79
    build: device
80
      ? {
81
          outDir: 'dist-device',
82
          emptyOutDir: true,
83
          rollupOptions: {
84
            input: {
85
              main: 'index.html',
86
              sw: 'src/sw.ts'
87
            },
88
            output: {
89
              entryFileNames: (chunk) => (chunk.name === 'sw' ? 'sw.js' : 'assets/[name]-[hash].js')
90
            }
91
          }
92
        }
93
      : {
94
          outDir: 'dist',
95
          emptyOutDir: true
96
        }
97
  };
98
});