Skip to content

Commit

Permalink
feat: Wasmify supports custom wit folder, world name, debug mode and …
Browse files Browse the repository at this point in the history
…wasm cache

closes #168
  • Loading branch information
hugomrdias committed Mar 8, 2024
1 parent 0e96fd6 commit 1dafc13
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 76 deletions.
2 changes: 1 addition & 1 deletion packages/homestar/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
"@types/node": "^20.11.25",
"@types/object-path": "^0.11.4",
"execa": "^8.0.1",
"homestar-runtime": "^0.2.0",
"homestar-runtime": "rc",
"iso-base": "^2.0.1",
"kubo-rpc-client": "^3.0.4",
"p-defer": "^4.0.0",
Expand Down
38 changes: 37 additions & 1 deletion packages/homestar/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,44 @@ export type HomestarService = Service<
>

export interface WitOptions {
filePath?: string
entryPoint?: string
source?: string
worldName: string
wasiImports?: Set<string>
}

export interface WasmifyOptions {
/**
* The entry point of the js module
*/
entryPoint: string
/**
* The directory to output the generated files
*
* @default '<cwd>'
*/
outDir?: string

/**
* The name of the generated Wit World
*
* @default '<bundle-hash>'
*/
worldName?: string

/**
* Wit dependencies directory
*
* NOTE: this should be the directory where you run `wit-deps` and this script maybe delete any top level .wit files not inside the deps directory
*
* @default '<path-to-@fission-codes/homestar-wit>'
*/
witPath?: string

/**
* Componentize JS debug flag
*
* @default false
*/
debug?: boolean
}
67 changes: 43 additions & 24 deletions packages/homestar/src/wasmify/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { writeFile } from 'node:fs/promises'
import fs from 'node:fs'
import path from 'path'
import { createRequire } from 'node:module'
import { base32 } from 'iso-base/rfc4648'
import * as esbuild from 'esbuild'
import { deleteAsync } from 'del'
import { deleteSync } from 'del'

// @ts-ignore
import replacePlugin from 'esbuild-plugin-replace-regex'
Expand Down Expand Up @@ -63,42 +64,60 @@ async function bundle(filePath) {
/**
* Generate wasm component from a TypeScript file
*
* @param {string} filePath - Path to a TypeScript file
* @param {string} outDir - Path to a directory to write the Wasm component file
* @param {import('../types.js').WasmifyOptions} options
*/
export async function build(filePath, outDir = process.cwd()) {
const pkgPath = require.resolve('@fission-codes/homestar-wit')
const witPath = path.join(pkgPath, '..', '..', 'wit')
let witHash
export async function build(options) {
let {
entryPoint,
outDir = process.cwd(),
debug = false,
worldName,
witPath,
} = options

if (!witPath) {
const pkgPath = require.resolve('@fission-codes/homestar-wit')
witPath = path.join(pkgPath, '..', '..', 'wit')
}

if (!worldName) {
worldName = path.basename(entryPoint, path.extname(entryPoint))
}

// Clean up any old WIT files in the wit directory
// componentize process.exit(1) if it fails so we can't clean up after it
await deleteAsync([`${witPath}/*.wit`], { force: true })
deleteSync([`${witPath}/*.wit`], { force: true })

let witFile
try {
const { hash, src, wasiImports } = await bundle(filePath)
witHash = base32.encode(hash).toLowerCase()
const { hash, src, wasiImports } = await bundle(entryPoint)
const witHash = base32.encode(hash).toLowerCase()
const outPath = path.join(outDir, `${worldName}-${witHash}.wasm`)
witFile = path.join(witPath, `${worldName}-${witHash}.wit`)

// TODO: check the wit hash and only componentize if it has changed
const witSource = await wit({ filePath, worldName: witHash, wasiImports })
const witFile = path.join(witPath, `${witHash}.wit`)
await writeFile(witFile, witSource, 'utf8')
const { component } = await componentize(src, {
witPath,
worldName: witHash,
// debug: true,
sourceName: filePath,
})
const outPath = path.join(outDir, `${witHash}.wasm`)
await writeFile(outPath, component)
if (!fs.existsSync(outPath)) {
const witSource = await wit({
entryPoint,
worldName,
wasiImports,
})
await writeFile(witFile, witSource, 'utf8')
const { component } = await componentize(src, {
witPath,
worldName,
debug,
sourceName: entryPoint,
})
await writeFile(outPath, component)
}

return {
outPath,
witHash,
}
} finally {
if (witHash) {
await deleteAsync([path.join(witPath, `${witHash}.wit`)], { force: true })
if (witFile) {
deleteSync([witFile], { force: true })
}
}
}
38 changes: 1 addition & 37 deletions packages/homestar/src/wasmify/wit.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,42 +62,6 @@ function witType(type, msg = '') {
return 'list<u8>'
}

if (type.text === 'Int8Array') {
return 'list<s8>'
}

if (type.text === 'Uint16Array') {
return 'list<u16>'
}

if (type.text === 'Int16Array') {
return 'list<s16>'
}

if (type.text === 'Uint32Array') {
return 'list<u32>'
}

if (type.text === 'Int32Array') {
return 'list<s32>'
}

if (type.text === 'Float32Array') {
return 'list<float32>'
}

if (type.text === 'Float64Array') {
return 'list<float64>'
}

if (type.text === 'BigUint64Array') {
return 'list<u64>'
}

if (type.text === 'BigInt64Array') {
return 'list<s64>'
}

if (type.kind === 'Array' && type.elementType) {
return `list<${witType(type.elementType, msg)}>`
}
Expand Down Expand Up @@ -133,7 +97,7 @@ function msg(name, loc, line) {
* @param {import('../types').WitOptions} options
*/
export async function wit(options) {
const { filePath, source, wasiImports, worldName } = options
const { entryPoint: filePath, source, wasiImports, worldName } = options

/** @type {import('@ts-ast-parser/core').AnalyserResult } */
let result
Expand Down
27 changes: 14 additions & 13 deletions packages/homestar/test/wasmify.node.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const HS1_URL = process.env.HS1_URL || 'ws://localhost:8060'
const hs = new Homestar({
transport: new WebsocketTransport(HS1_URL),
})
const outDir = temporaryDirectory()

test.after(() => {
hs.close()
Expand All @@ -26,10 +27,10 @@ test.after(() => {
test(
'should wasmify',
async function () {
const { outPath } = await build(
path.join(__dirname, 'fixtures', 'wasmify', 'hello.ts'),
temporaryDirectory()
)
const { outPath } = await build({
entryPoint: path.join(__dirname, 'fixtures', 'wasmify', 'hello.ts'),
outDir,
})

/** @type {import('p-defer').DeferredPromise<string>} */
const prom = pDefer()
Expand Down Expand Up @@ -70,10 +71,10 @@ test(
test(
'should wasmify with bytes',
async function () {
const { outPath } = await build(
path.join(__dirname, 'fixtures', 'wasmify', 'hello.ts'),
temporaryDirectory()
)
const { outPath } = await build({
entryPoint: path.join(__dirname, 'fixtures', 'wasmify', 'hello.ts'),
outDir,
})

/** @type {import('p-defer').DeferredPromise<Uint8Array>} */
const prom = pDefer()
Expand Down Expand Up @@ -113,14 +114,14 @@ test(
test(
'should wasmify with wit logging',
async function () {
const { outPath } = await build(
path.join(__dirname, 'fixtures', 'wasmify', 'wit-test.ts'),
temporaryDirectory()
)
const { outPath } = await build({
entryPoint: path.join(__dirname, 'fixtures', 'wasmify', 'wit-test.ts'),
outDir,
})

/** @type {import('p-defer').DeferredPromise<number>} */
const prom = pDefer()
const args = [1.1, 1.1]
const args = [1, 1]
const wasmCID = await addFSFileToIPFS(outPath)
const workflow1 = await workflow({
name: 'hash',
Expand Down

0 comments on commit 1dafc13

Please sign in to comment.