Skip to content

Commit

Permalink
Make WASM runnable
Browse files Browse the repository at this point in the history
  • Loading branch information
Schniz committed Feb 16, 2022
1 parent bd514e5 commit 338251b
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 15 deletions.
Expand Up @@ -10,20 +10,18 @@ const MiddlewareWasmLoader: webpack.loader.Loader = function (
source,
_sourceMap
) {
const cb = this.async()
if (!cb) throw new Error('async() must be used with wasm-loader')

const name = `wasm_${sha1(source)}`
const file = `middleware-chunks/${name}.wasm`
const binding: WasmBinding = { file, name }
this._module.buildInfo.nextWasmMiddlewareBinding = binding
this.emitFile(`/${file}`, source, undefined)

cb(null, `module.exports = globalThis[${JSON.stringify(name)}];`)
this.emitFile(`/${file}`, source, null)
return `module.exports = globalThis[${JSON.stringify(name)}];`
}

export const raw = true

export default MiddlewareWasmLoader

function sha1(source: string | Buffer) {
return crypto.createHash('sha1').update(source).digest('hex')
}

export default MiddlewareWasmLoader
11 changes: 11 additions & 0 deletions packages/next/server/next-server.ts
Expand Up @@ -1251,6 +1251,7 @@ export default class NextNodeServer extends BaseServer {
name: middlewareInfo.name,
paths: middlewareInfo.paths,
env: middlewareInfo.env,
wasmBindings: middlewareInfo.wasmBindings,
request: {
headers: params.request.headers,
method: params.request.method || 'GET',
Expand Down Expand Up @@ -1333,3 +1334,13 @@ export default class NextNodeServer extends BaseServer {
}
}
}

function loadWasmBindings(
wasmBindings: { file: string; name: string }[]
): Record<string, WebAssembly.Module> {
const wasmBindingsMap: Record<string, WebAssembly.Module> = {}
for (const { file, name } of wasmBindings) {
wasmBindingsMap[name] = WebAssembly.compile(fs.readFileSync(file))
}
return wasmBindingsMap
}
11 changes: 10 additions & 1 deletion packages/next/server/require.ts
Expand Up @@ -85,7 +85,12 @@ export function getMiddlewareInfo(params: {
distDir: string
page: string
serverless: boolean
}): { name: string; paths: string[]; env: string[] } {
}): {
name: string
paths: string[]
env: string[]
wasmBindings: { file: string; name: string }[]
} {
const serverBuildPath = join(
params.distDir,
params.serverless && !params.dev ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY
Expand Down Expand Up @@ -113,5 +118,9 @@ export function getMiddlewareInfo(params: {
name: pageInfo.name,
paths: pageInfo.files.map((file) => join(params.distDir, file)),
env: pageInfo.env ?? [],
wasmBindings: (pageInfo.wasmBindings ?? []).map((binding) => ({
...binding,
file: join(params.distDir, binding.file),
})),
}
}
25 changes: 21 additions & 4 deletions packages/next/server/web/sandbox/context.ts
Expand Up @@ -52,18 +52,19 @@ const caches = new Map<
* run in within the context. It may or may not use a cache depending on
* the parameters.
*/
export function getModuleContext(options: {
export async function getModuleContext(options: {
module: string
onWarning: (warn: Error) => void
useCache: boolean
env: string[]
wasmBindings: WasmBinding[]
}) {
let moduleCache = options.useCache
? caches.get(options.module)
: createModuleContext(options)
: await createModuleContext(options)

if (!moduleCache) {
moduleCache = createModuleContext(options)
moduleCache = await createModuleContext(options)
caches.set(options.module, moduleCache)
}

Expand Down Expand Up @@ -95,10 +96,11 @@ export function getModuleContext(options: {
* 2. Dependencies that require runtime globals such as Blob.
* 3. Dependencies that are scoped for the provided parameters.
*/
function createModuleContext(options: {
async function createModuleContext(options: {
onWarning: (warn: Error) => void
module: string
env: string[]
wasmBindings: WasmBinding[]
}) {
const requireCache = new Map([
[require.resolve('next/dist/compiled/cookie'), { exports: cookie }],
Expand Down Expand Up @@ -166,6 +168,8 @@ function createModuleContext(options: {
return fetch(String(input), init)
}

Object.assign(context, await loadWasmBindings(options.wasmBindings))

return moduleCache
}

Expand Down Expand Up @@ -259,3 +263,16 @@ function buildEnvironmentVariablesFrom(
const pairs = keys.map((key) => [key, process.env[key]])
return Object.fromEntries(pairs)
}

async function loadWasmBindings(
wasmBindings: WasmBinding[]
): Promise<Record<string, WebAssembly.Module>> {
const modules: Record<string, WebAssembly.Module> = {}
for (const binding of wasmBindings) {
const module = await WebAssembly.compile(readFileSync(binding.file))
modules[binding.name] = module
}
return modules
}

export type WasmBinding = { file: string; name: string }
6 changes: 4 additions & 2 deletions packages/next/server/web/sandbox/sandbox.ts
@@ -1,5 +1,5 @@
import type { RequestData, FetchEventResult } from '../types'
import { getModuleContext } from './context'
import { getModuleContext, WasmBinding } from './context'

export async function run(params: {
name: string
Expand All @@ -8,12 +8,14 @@ export async function run(params: {
paths: string[]
request: RequestData
useCache: boolean
wasmBindings: WasmBinding[]
}): Promise<FetchEventResult> {
const { runInContext, context } = getModuleContext({
const { runInContext, context } = await getModuleContext({
module: params.name,
onWarning: params.onWarning,
useCache: params.useCache !== false,
env: params.env,
wasmBindings: params.wasmBindings,
})

for (const paramPath of params.paths) {
Expand Down

0 comments on commit 338251b

Please sign in to comment.