forked from vitejs/vite
-
Notifications
You must be signed in to change notification settings - Fork 0
/
wasm.ts
95 lines (83 loc) · 2.75 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
92
93
94
95
import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin'
import { fileToUrl } from './asset'
const wasmHelperId = '\0vite/wasm-helper'
const wasmHelper = async (opts = {}, url: string) => {
let result
if (url.startsWith('data:')) {
const urlContent = url.replace(/^data:.*?base64,/, '')
let bytes
if (typeof Buffer === 'function' && typeof Buffer.from === 'function') {
bytes = Buffer.from(urlContent, 'base64')
} else if (typeof atob === 'function') {
const binaryString = atob(urlContent)
bytes = new Uint8Array(binaryString.length)
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i)
}
} else {
throw new Error(
'Failed to decode base64-encoded data URL, Buffer and atob are not supported',
)
}
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.
const response = await fetch(url)
const contentType = response.headers.get('Content-Type') || ''
if (
'instantiateStreaming' in WebAssembly &&
contentType.startsWith('application/wasm')
) {
result = await WebAssembly.instantiateStreaming(response, opts)
} else {
const buffer = await response.arrayBuffer()
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.',
)
},
}
}