-
Notifications
You must be signed in to change notification settings - Fork 292
Expand file tree
/
Copy pathvite.config.ts
More file actions
167 lines (147 loc) · 4.64 KB
/
vite.config.ts
File metadata and controls
167 lines (147 loc) · 4.64 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
import fs from "node:fs";
import path from "node:path";
import MagicString from "magic-string";
import type { Plugin } from "vite";
import { defineConfig } from "vite";
import dts from "vite-plugin-dts";
import glsl from "vite-plugin-glsl";
/**
* Vite plugin to fix WASM data URL compatibility with webpack/Next.js.
*
* wasm-pack generates code like: new URL("data:...", import.meta.url)
* The import.meta.url argument is unnecessary for data: URLs and causes
* webpack/Vite to incorrectly try to rewrite the URL as a file path.
*
* This plugin transforms:
* new URL("data:...", import.meta.url) → new URL("data:...")
*
* Uses magic-string to ensure proper source map generation.
*
* See: https://github.com/sparkjsdev/spark/issues/95
*/
function fixWasmDataUrl(): Plugin {
return {
name: "fix-wasm-data-url",
renderChunk(code) {
// Match: new URL("data:...", import.meta.url)
// The data URL can contain any characters including quotes (escaped)
const dataUrlPattern =
/new\s+URL\(\s*("data:[^"]*")\s*,\s*import\.meta\.url\s*\)/g;
const matches = [...code.matchAll(dataUrlPattern)];
if (matches.length === 0) return null;
const magicString = new MagicString(code);
for (const match of matches) {
if (match.index === undefined) continue;
const start = match.index;
const end = start + match[0].length;
const replacement = `new URL(${match[1]})`;
magicString.overwrite(start, end, replacement);
}
return {
code: magicString.toString(),
map: magicString.generateMap({ hires: true }),
};
},
};
}
const assetsDirectory = "examples/assets";
const localAssetsDirectoryExist = fs.existsSync(assetsDirectory);
if (!localAssetsDirectoryExist) {
console.log(
"************************************************************************",
);
console.log(" Examples assets will be fetched from an external server.");
console.log(
" To work offline you can download them: npm run assets:download",
);
console.log(
"************************************************************************",
);
}
export default defineConfig(({ mode }) => {
const isMinify = mode === "production";
const isFirstPass = mode === "production";
return {
appType: "mpa",
plugins: [
glsl({
include: ["**/*.glsl"],
}),
dts({ outDir: "dist/types" }),
// Fix webpack/Next.js compatibility for WASM data URLs
fixWasmDataUrl(),
{
name: "serve-node-modules-alias",
configureServer(server) {
const baseUrlPath = "/examples/js/vendor/";
server.middlewares.use((req, res, next) => {
if (!req.url.startsWith(baseUrlPath)) return next();
const relModulePath = req.url.slice(baseUrlPath.length); // safe substring
const absPath = path.resolve("node_modules", relModulePath);
if (fs.existsSync(absPath) && fs.statSync(absPath).isFile()) {
const ext = path.extname(absPath);
const contentType =
{
".js": "application/javascript",
".mjs": "application/javascript",
".css": "text/css",
".json": "application/json",
}[ext] || "application/octet-stream";
res.setHeader("Content-Type", contentType);
fs.createReadStream(absPath).pipe(res);
} else {
res.statusCode = 404;
res.end(`Not found: ${relModulePath}`);
}
});
console.log(`📦 Dev alias active: ${baseUrlPath} → node_modules/*`);
},
},
],
build: {
minify: isMinify,
lib: {
entry: path.resolve(__dirname, "src/index.ts"),
name: "spark",
formats: ["es", "cjs"],
fileName: (format) => {
const base = format === "es" ? "spark.module" : `spark.${format}`;
return isMinify ? `${base}.min.js` : `${base}.js`;
},
},
sourcemap: true,
rollupOptions: {
external: ["three"],
output: {
globals: {
three: "THREE",
},
},
},
emptyOutDir: isFirstPass,
},
worker: {
rollupOptions: {
treeshake: "smallest",
},
plugins: () => [
glsl({
include: ["**/*.glsl"],
}),
],
},
server: {
watch: {
usePolling: true,
},
port: 8080,
},
optimizeDeps: {
force: true,
exclude: ["three"], // prevent Vite pre-bundling
},
define: {
sparkLocalAssets: localAssetsDirectoryExist,
},
};
});