/
wasm.ts
91 lines (79 loc) · 2.51 KB
/
wasm.ts
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
import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin'
import { fileToUrl } from './asset'
const wasmHelperId = '/__vite-wasm-helper'
const wasmHelper = async (opts = {}, url: string) => {
let result
if (url.startsWith('data:')) {
// @ts-ignore
const binaryString = atob(url.replace(/^data:.*?base64,/, ''))
const bytes = new Uint8Array(binaryString.length)
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i)
}
// @ts-ignore
result = await WebAssembly.instantiate(bytes, opts)
} else {
// https://github.com/mdn/webassembly-examples/issues/5
// WebAssembly.instantiateStreaming requires the server to provide the
// correct MIME type for .wasm files, which unfortunately doesn't work for
// a lot of static file servers, so we just work around it by getting the
// raw buffer.
// @ts-ignore
const response = await fetch(url)
const contentType = response.headers.get('Content-Type') || ''
if (
// @ts-ignore
'instantiateStreaming' in WebAssembly &&
contentType.startsWith('application/wasm')
) {
// @ts-ignore
result = await WebAssembly.instantiateStreaming(response, opts)
} else {
const buffer = await response.arrayBuffer()
// @ts-ignore
result = await WebAssembly.instantiate(buffer, opts)
}
}
return result.instance
}
const wasmHelperCode = wasmHelper.toString()
export const wasmHelperPlugin = (config: ResolvedConfig): Plugin => {
return {
name: 'vite:wasm-helper',
resolveId(id) {
if (id === wasmHelperId) {
return id
}
},
async load(id) {
if (id === wasmHelperId) {
return `export default ${wasmHelperCode}`
}
if (!id.endsWith('.wasm?init')) {
return
}
const url = await fileToUrl(id, config, this)
return `
import initWasm from "${wasmHelperId}"
export default opts => initWasm(opts, ${JSON.stringify(url)})
`
}
}
}
export const wasmFallbackPlugin = (): Plugin => {
return {
name: 'vite:wasm-fallback',
async load(id) {
if (!id.endsWith('.wasm')) {
return
}
throw new Error(
'"ESM integration proposal for Wasm" is not supported currently. ' +
'Use vite-plugin-wasm or other community plugins to handle this. ' +
'Alternatively, you can use `.wasm?init` or `.wasm?url`. ' +
'See https://vitejs.dev/guide/features.html#webassembly for more details.'
)
}
}
}