WASM: Solving Webpack and ESLint errors

Small Dev-Ops things, but these were really frustrating to figure out.

1. Rust/Webpack error:

Recently I was testing my SPA and noticed that the page wouldn't load at all.

  • In the browser:

    Uncaught runtime errors:  
    ERROR  
    wasm is undefined  
    init@webpack://<SPA>/./src/pkg/index_bg.js?:344:18
    @webpack://<SPA>/./src/index.mjs?:13:208
    
  • In the console:

    Uncaught (in promise) TypeError: wasm is undefined
    src_wasm_dist_pkg_index_bg_js.spa.js line 2 > eval:344:18
    init webpack://<SPA>/./src/pkg/index_bg.js?:344
    <anonymous> webpack://<SPA>/./src/index.mjs?:13
    

I was sure it was working during the last commit (it's been working for years), but no matter how many git commits I rolled back to, I got the same errors, which was strange.

So I thought it might be the Rust or NPM cache. So I regenerated the node_modules and rust target folders, even from prior git commits, but I still got the same errors.

After a few more hours of frustrating git-rollbacks/re-installs/bad-symlink-hacking, I restored the entire project from a backup. And the SPA worked again as expected.

What I finally figured out was to change which WASM package index file I imported into the Webpack entry point.

  • Solution:

    index.mjs (Webpack entry point):
    
    Before:
    import('./pkg/index_bg.js').then((m) => m.init(process.env.NODE_ENV));
    
    After:
    import('./pkg/index.js').then((m) => m.init(process.env.NODE_ENV));
    

I'm pretty confident is has nothing to do with any of my rust code, but with the packagers/bundlers/dependencies as they are updated (Webpack, wasm-bindgen, wasm-tool/wasm-pack-plugin, etc.). Here are the differences between the backup and the current package files:

  • Diff: index_bg.js (wasm):

    *** /backup/index_bg.js	2023-07-07 10:06:04.951684240 -0400
    --- /current/index_bg.js	2023-07-07 10:22:25.448756811 -0400
    ***************
    *** 1 ****
    ! import * as wasm from './index_bg.wasm';
    --- 1,5 ----
    ! let wasm;
    ! export function __wbg_set_wasm(val) {
    !     wasm = val;
    ! }
    ! 
    ***************
    (cont.)
    ...
    
  • Diff: index.js (wasm):

    *** /backup/index.js	2023-07-07 10:06:04.951684240 -0400
    --- /current/index.js	2023-07-07 10:22:25.448756811 -0400
    ***************
    *** 2 ****
    ! export * from "./index_bg.js";
    \ No newline at end of file
    --- 2,4 ----
    ! import { __wbg_set_wasm } from "./index_bg.js";
    ! __wbg_set_wasm(wasm);
    ! export * from "./index_bg.js";
    

2. ESLint error:

This error I have always ignored because using their suggested fix (remove the relative directory prefixes) didn't work for me:

  • ESLint error on Webpack entry point (index.mjs):

    index.mjs|11 col 8 error| Relative import from another package
    is not allowed. Use wasm/index_bg.js instead of ./pkg/index_bg.js
    (import/no-relative-packages)
    
  • ESLint: import/no-relative-packages:

After going back and forth many times with this, it dawned on me that I was using the generated WASM package (generated by wasm-tool/wasm-pack-plugin) improperly the whole time. I was importing and using a single .js file (like I usually do with my Javascript modules - rather than the entire WASM package directory (like a node_modules dependency.

  • Solution:

    So I updated the SPA to:

    • Have separate top-level folders for Rust and NPM/Webpack (and their sizeable cache/build directories).
    • Have wasm-pack output the Rust package for NPM to the projects' NPM/Webpack folder.
    • register/link the Rust package via NPM so that Webpack knows where to find it.
    • Import/Use the Rust package like any other NodeJS package.
  • webpack-config.mjs

    const WasmPackPlugin = require('@wasm-tool/wasm-pack-plugin');
    module.exports = {
      // ...
      entry: './index.mjs',
    
      experiments: {
        syncWebAssembly: true
      },
      // ...
      plugins: [
        new WasmPackPlugin({
          // separate Rust/NPM directories
          crateDirectory: path.resolve(__dirname, '../rust'),
          outDir: '../npm/packages/spa-rs'
        })
      ]
    };
    
  • Link package: NPM Link (symlinks your rust package to the local node_modules folder)

  • package.json

    {
      "name": "SPA",
      },
      "dependencies": {
        "@wasm-tool/wasm-pack-plugin": ">=1.7.0",
        "spa-rs": "file:packages/spa-rs" // <-- file:/// reference OK here
      },
      "devDependencies": {
        //...
      }
    }
    
  • Webpack entry point index.mjs

    // NPM package import, not relative file import
    const wasm = import('spa-rs');
    wasm.then((w) => w.init(process.env.NODE_ENV));
    

Hope this helps someone.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.