Skip to content

Commit

Permalink
feat(wasm): use instantiateStreaming when available (#1330)
Browse files Browse the repository at this point in the history
close #1143
  • Loading branch information
ianpurvis committed Jan 3, 2021
1 parent 25adf1e commit 2286f62
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 19 deletions.
11 changes: 8 additions & 3 deletions packages/playground/wasm/__tests__/wasm.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { untilUpdated } from '../../testUtils'

test('should work', async () => {
await page.click('.run')
await untilUpdated(() => page.textContent('.result'), 'Wasm result: 42')
test('should work when inlined', async () => {
await page.click('.inline-wasm .run')
await untilUpdated(() => page.textContent('.inline-wasm .result'), '42')
})

test('should work when output', async () => {
await page.click('.output-wasm .run')
await untilUpdated(() => page.textContent('.output-wasm .result'), '24')
})
Binary file added packages/playground/wasm/heavy.wasm
Binary file not shown.
1 change: 1 addition & 0 deletions packages/playground/wasm/heavy.wasm.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 29 additions & 9 deletions packages/playground/wasm/index.html
Original file line number Diff line number Diff line change
@@ -1,16 +1,36 @@
<button class="run">Click to run wasm</button>
<div class="result"></div>
<h1>Web Assembly</h1>

<div class="inline-wasm">
<h3>When wasm is inline, result should be 42</h3>
<button class="run">Click to run</button>
<span class="result"></span>
</div>

<div class="output-wasm">
<h3>When wasm is output, result should be 24</h3>
<button class="run">Click to run</button>
<span class="result"></span>
</div>

<script type="module">
import init from './simple.wasm'
;(async () => {
import light from './light.wasm'
import heavy from './heavy.wasm'

async function testWasm(init, resultElement) {
const { exported_func } = await init({
imports: {
imported_func: (res) => {
document.querySelector('.result').textContent = `Wasm result: ${res}`
}
imported_func: (res) => resultElement.textContent = res
}
})
document.querySelector('.run').addEventListener('click', exported_func)
})()
exported_func()
}

document.querySelector('.inline-wasm .run')
.addEventListener('click', async () =>
testWasm(light, document.querySelector('.inline-wasm .result')))

document.querySelector('.output-wasm .run')
.addEventListener('click', async () =>
testWasm(heavy, document.querySelector('.output-wasm .result')))

</script>
File renamed without changes.
23 changes: 16 additions & 7 deletions packages/vite/src/node/plugins/wasm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { fileToUrl } from './asset'

const wasmHelperId = '/__vite-wasm-helper'

const wasmHelper = (opts = {}, url: string) => {
let instance
const wasmHelper = async (opts = {}, url: string) => {
let result
if (url.startsWith('data:')) {
// @ts-ignore
const binaryString = atob(url.replace(/^data:.*?base64,/, ''))
Expand All @@ -14,21 +14,30 @@ const wasmHelper = (opts = {}, url: string) => {
bytes[i] = binaryString.charCodeAt(i)
}
// @ts-ignore
instance = WebAssembly.instantiate(bytes.buffer, opts)
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
instance = fetch(url)
const response = await fetch(url)
const contentType = response.headers.get('Content-Type') || ''
if (
// @ts-ignore
.then((r) => r.arrayBuffer())
'instantiateStreaming' in WebAssembly &&
contentType.startsWith('application/wasm')
) {
// @ts-ignore
.then((bytes) => WebAssembly.instantiate(bytes, opts))
result = await WebAssembly.instantiateStreaming(response, opts)
} else {
const buffer = await response.arrayBuffer()
// @ts-ignore
result = await WebAssembly.instantiate(buffer, opts)
}
}
return instance.then((i: any) => i.instance.exports)
return result.instance.exports
}

const wasmHelperCode = wasmHelper.toString()
Expand Down

0 comments on commit 2286f62

Please sign in to comment.