Tschrock / esbuild-plugin-wasm

WASM module loader for esbuild
MIT License
24 stars 5 forks source link

Adding wasmLoader() to esbuild plugins raises: TypeError: wasmLoader is not a function #3

Closed coenbakker closed 1 year ago

coenbakker commented 1 year ago

Error Came across this error when adding wasmLoader to Esbuild plugins: TypeError: wasmLoader is not a function. I have not been able to track down the source of the error yet.

package.json

{
  "name": "name",
  "version": "1.0.0",
  "description": "",
  "main": "js/app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@automerge/automerge": "^2.0.1",
    "phoenix": "file:../deps/phoenix",
    "phoenix_html": "file:../deps/phoenix_html",
    "phoenix_live_view": "file:../deps/phoenix_live_view"
  },
  "devDependencies": {
    "esbuild": "^0.17.8",
    "esbuild-plugin-wasm": "^1.0.0"
  }
}

build.js

const esbuild = require('esbuild')
let wasmLoader = require('esbuild-plugin-wasm')

const args = process.argv.slice(2)
const watch = args.includes('--watch')
const deploy = args.includes('--deploy')

const loader = {}

const plugins = [wasmLoader()]

let opts = {
  entryPoints: ['js/app.js'],
  bundle: true,
  target: 'es2020',
  outdir: '../priv/static/assets',
  logLevel: 'info',
  target: ['chrome111'],
  loader,
  plugins
}

if (watch) {
  opts = {
    ...opts,
    watch,
    sourcemap: 'inline'
  }
}

if (deploy) {
  opts = {
    ...opts,
    minify: true
  }
}

const promise = esbuild.build(opts)

if (watch) {
  promise.then(_result => {
    process.stdin.on('close', () => {
      process.exit(0)
    })

    process.stdin.resume()
  })
}
coenbakker commented 1 year ago

I was also able to replicate this error in a bare bones setup. I've included a console.dir of the wasmLoader.wasmLoader(), which is the closest thing I could find in the imported wasmLoader object to the desired plugin function. Using wasmLoader.wasmLoader() instead of wasmLoader() did work, btw.

package.js

{
  "name": "name",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "type": "module",
  "scripts": {
    "build": "node build.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "esbuild": "^0.17.8",
    "esbuild-plugin-wasm": "^1.0.0"
  }
}

build.js

import * as esbuild from 'esbuild'
import wasmLoader from 'esbuild-plugin-wasm';

console.dir(wasmLoader.wasmLoader.toString())
/*
'function S(e){var o;let t=((o=e==null?void 0:e.mode)==null?void 0:o.toLowerCase())=="embedded";return{name:"wasm",setup(s){s.onResolve({filter:/\\.(?:wasm)$/},r=>{if(r.namespace===p)return{path:r.path,namespace:t?y:b};if(r.resolveDir!=="")return{path:n.default.isAbsolute(r.path)?r.path:n.default.join(r.resolveDir,r.path),namespace:p}}),s.onLoad({filter:/.*/,namespace:p},async r=>({contents:await w(r.path),resolveDir:n.default.dirname(r.path)})),s.onLoad({filter:/.*/,namespace:b},async r=>({contents:await i.default.promises.readFile(r.path),loader:"file"})),s.onLoad({filter:/.*/,namespace:y},async r=>({contents:await i.default.promises.readFile(r.path),loader:"binary"}))}}}'
*/

let result = await esbuild.build({
  entryPoints: ['app.js'],
  bundle: true,
  outdir: 'dist',
  plugins: [
    wasmLoader()
  ],
  format: 'esm'
})
Tschrock commented 1 year ago

I did some tests on different types of require/import:

JavaScript ```js > const test1 = require('esbuild-plugin-wasm') { default: [Getter], wasmLoader: [Getter] } ``` ```js > import test2 from 'esbuild-plugin-wasm' { default: [Getter], wasmLoader: [Getter] } ``` ```js > import * as test3 from 'esbuild-plugin-wasm' [Module: null prototype] { default: { default: [Getter], wasmLoader: [Getter] }, wasmLoader: [Function: S] } ``` ```js > const test4 = await import('esbuild-plugin-wasm') [Module: null prototype] { default: { default: [Getter], wasmLoader: [Getter] }, wasmLoader: [Function: S] } ```
TypeScript ```ts > const test1 = require('esbuild-plugin-wasm') { default: [Getter], wasmLoader: [Getter] } ``` ```ts > import test2 from 'esbuild-plugin-wasm' [Function: S] ``` ```ts > import * as test3 from 'esbuild-plugin-wasm' { default: [Getter], wasmLoader: [Getter] } ```

Other notes:


So there's a two different things happening here, both resulting in the same error:

In any case, you should always be able to use 'wasmLoader' as a named import:

// CommonJS
const { wasmLoader } = require('esbuild-plugin-wasm')
// CommonJS or ESM async
const { wasmLoader } = await import('esbuild-plugin-wasm')
// ESM
import { wasmLoader } from 'esbuild-plugin-wasm'

I'll add a javascript example to the README to avoid confusion in the future, and if I can find a way to make export = wasmLoader work without breaking the named export, I will add that too.