Stacksave error trying to integrate webgl build with Angular 14

Hi folks

Let me say first that I am basically a noob with Angular.

Anyway I’ve been trying for weeks to get a minimal Unity app running inside Angular 14. It works great when I just use the index.html and javascript that was output by the webgl build.

Here’s the output from Chrome’s console log:

unitymap.loader.js:1 Assertion failed
printErr @ unitymap.loader.js:1
abort @ unitymap.framework.js:114
assert @ unitymap.framework.js:951
demangle @ unitymap.framework.js:2030
(anonymous) @ unitymap.framework.js:2060
demangleAll @ unitymap.framework.js:2058
ErrnoError @ unitymap.framework.js:6985
(anonymous) @ unitymap.framework.js:6992
ensureErrnoError @ unitymap.framework.js:6991
staticInit @ unitymap.framework.js:6996
(anonymous) @ unitymap.framework.js:15600
(anonymous) @ unitymap.loader.js:1
invoke @ zone-evergreen.js:372
onInvoke @ core.js:28591
invoke @ zone-evergreen.js:371
run @ zone-evergreen.js:134
(anonymous) @ zone-evergreen.js:1275
invokeTask @ zone-evergreen.js:406
onInvokeTask @ core.js:28578
invokeTask @ zone-evergreen.js:405
runTask @ zone-evergreen.js:178
drainMicroTaskQueue @ zone-evergreen.js:585
invokeTask @ zone-evergreen.js:491
invokeTask @ zone-evergreen.js:1661
globalCallback @ zone-evergreen.js:1692
globalZoneAwareCallback @ zone-evergreen.js:1725
load (async)
customScheduleGlobal @ zone-evergreen.js:1809
scheduleTask @ zone-evergreen.js:393
onScheduleTask @ zone-evergreen.js:283
scheduleTask @ zone-evergreen.js:386
scheduleTask @ zone-evergreen.js:221
scheduleEventTask @ zone-evergreen.js:247
(anonymous) @ zone-evergreen.js:1964
desc.set @ zone-evergreen.js:825
(anonymous) @ unitymap.loader.js:1
ZoneAwarePromise @ zone-evergreen.js:1429
x @ unitymap.loader.js:1
(anonymous) @ unitymap.loader.js:1
ZoneAwarePromise @ zone-evergreen.js:1429
createUnityInstance @ unitymap.loader.js:1
initializeUnityMap @ demo.component.ts:90
ngAfterViewInit @ demo.component.ts:42
callHook @ core.js:2573
callHooks @ core.js:2542
executeInitAndCheckHooks @ core.js:2493
refreshView @ core.js:9551
refreshComponent @ core.js:10651
refreshChildComponents @ core.js:9277
refreshView @ core.js:9530
renderComponentOrTemplate @ core.js:9594
tickRootContext @ core.js:10825
detectChangesInRootView @ core.js:10850
detectChanges @ core.js:22853
tick @ core.js:29572
_loadComponent @ core.js:29610
bootstrap @ core.js:29546
(anonymous) @ core.js:29245
_moduleDoBootstrap @ core.js:29245
(anonymous) @ core.js:29215
invoke @ zone-evergreen.js:372
onInvoke @ core.js:28591
invoke @ zone-evergreen.js:371
run @ zone-evergreen.js:134
(anonymous) @ zone-evergreen.js:1275
invokeTask @ zone-evergreen.js:406
onInvokeTask @ core.js:28578
invokeTask @ zone-evergreen.js:405
runTask @ zone-evergreen.js:178
drainMicroTaskQueue @ zone-evergreen.js:585
Promise.then (async)
nativeScheduleMicroTask @ zone-evergreen.js:561
scheduleMicroTask @ zone-evergreen.js:572
scheduleTask @ zone-evergreen.js:396
scheduleTask @ zone-evergreen.js:221
scheduleMicroTask @ zone-evergreen.js:241
scheduleResolveOrReject @ zone-evergreen.js:1265
then @ zone-evergreen.js:1461
bootstrapModule @ core.js:29240
zUnb @ main.ts:11
__webpack_require__ @ bootstrap:79
0 @ main.js:11
__webpack_require__ @ bootstrap:79
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.js:1
Show 59 more frames
Show less

unitymap.loader.js:1 ERROR Error: Uncaught (in promise): TypeError: stackSave is not a function
TypeError: stackSave is not a function
    at withStackSave (unitymap.framework.js:2019:19)
    at demangle (unitymap.framework.js:2031:14)
    at unitymap.framework.js:2060:19
    at String.replace (<anonymous>)
    at demangleAll (unitymap.framework.js:2058:19)
    at new ErrnoError (unitymap.framework.js:6985:26)
    at unitymap.framework.js:6992:36
    at Array.forEach (<anonymous>)
    at Object.ensureErrnoError (unitymap.framework.js:6991:14)
    at Object.staticInit (unitymap.framework.js:6996:12)
    at unitymap.framework.js:15600:6
    at unitymap.loader.js:1:20047
    at _ZoneDelegate.invoke (zone-evergreen.js:372:1)
    at Object.onInvoke (core.js:28591:1)
    at _ZoneDelegate.invoke (zone-evergreen.js:371:1)
    at Zone.run (zone-evergreen.js:134:1)
    at zone-evergreen.js:1275:1
    at _ZoneDelegate.invokeTask (zone-evergreen.js:406:1)
    at Object.onInvokeTask (core.js:28578:1)
    at _ZoneDelegate.invokeTask (zone-evergreen.js:405:1)
    at Zone.runTask (zone-evergreen.js:178:1)
    at drainMicroTaskQueue (zone-evergreen.js:585:1)
    at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:491:1)
    at invokeTask (zone-evergreen.js:1661:1)
    at globalCallback (zone-evergreen.js:1692:1)
    at HTMLScriptElement.globalZoneAwareCallback (zone-evergreen.js:1725:1)
    at resolvePromise (zone-evergreen.js:1211:1)
    at zone-evergreen.js:1282:1
    at _ZoneDelegate.invokeTask (zone-evergreen.js:406:1)
    at Object.onInvokeTask (core.js:28578:1)
    at _ZoneDelegate.invokeTask (zone-evergreen.js:405:1)
    at Zone.runTask (zone-evergreen.js:178:1)
    at drainMicroTaskQueue (zone-evergreen.js:585:1)
    at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:491:1)
    at invokeTask (zone-evergreen.js:1661:1)
    at globalCallback (zone-evergreen.js:1692:1)
    at HTMLScriptElement.globalZoneAwareCallback (zone-evergreen.js:1725:1)

Thank you in advance for any help.

I just noticed that I didn’t summarize and explicitly point out the error:

unitymap.loader.js:1 ERROR Error: Uncaught (in promise): TypeError: stackSave is not a function
TypeError: stackSave is not a function

I was able to get it working. In case anyone else needs the solution, here are the important parts:

Update to 2023.2.9

Check Project Settings/Player/Use WebAssembly.Table true

in your component html:

<div #unitycontainer id="unity-container">
<canvas
    #unitycanvas
    id="unity-canvas"
    width="960"
    height="600"
    tabindex="-1"
  ></canvas>
  <div #unityloadingbar id="unity-loading-bar">
    <div #unitylogo id="unity-logo"></div>
    <div #unityprogressbarempty id="unity-progress-bar-empty">
      <div #unityprogressbarfull id="unity-progress-bar-full"></div>
    </div>
  </div>
  <div #unitywarning id="unity-warning"></div>
  <div #unityfooter id="unity-footer">
    <div #unitylogotitlefooter id="unity-logo-title-footer"></div>
    <div #unityfullscreenbutton id="unity-fullscreen-button"></div>
    <div #unitybuildtitle id="unity-build-title">Unity Map</div>
  </div>
</div>

in typings.d.ts:

declare var createUnityInstance: any;

in your component class file:

export class UnityComponent implements OnInit, AfterViewInit {
  @ViewChild('unitycontainer') unitycontainer: ElementRef;
  @ViewChild('unitycanvas') unitycanvas: ElementRef;
  @ViewChild('unityloadingbar') unityloadingbar: ElementRef;
  @ViewChild('unityprogressbarfull') unityprogressbarfull: ElementRef;
  @ViewChild('unityfullscreenbutton') unityfullscreenbutton: ElementRef;
  @ViewChild('unitywarning') unitywarning: ElementRef;

  mUnityInstance: any = undefined;

and

  async ngAfterViewInit() {
      this.InitializeUnity();
  } 

  InitializeUnity() {
  
    var buildUrl = 'assets/unityproject/Build';
    var config = {
      dataUrl: buildUrl + '/unityproject.data',
      frameworkUrl: buildUrl + '/unityproject.framework.js',
      codeUrl: buildUrl + '/unityproject.wasm',
      streamingAssetsUrl: 'StreamingAssets',
      companyName: 'some company',
      productName: 'unityproject
      productVersion: '0.1',
      devicePixelRatio: 0
    };
    let container: HTMLElement = this.unitycontainer
      .nativeElement as HTMLElement;
    var canvas: HTMLElement = this.unitycanvas.nativeElement as HTMLElement;
    var loadingBar: HTMLElement = this.unityloadingbar
      .nativeElement as HTMLElement;
    var progressBarFull: HTMLElement = this.unityprogressbarfull
      .nativeElement as HTMLElement;
    var fullscreenButton: HTMLElement = this.unityfullscreenbutton
      .nativeElement as HTMLElement;
    var mobileWarning: HTMLElement = this.unitywarning
      .nativeElement as HTMLElement;
    if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
      console.log('log: mobile environment');
      container.className = 'unity-mobile';
      config.devicePixelRatio = 1;
      mobileWarning.style.display = 'block';
      setTimeout(() => {
        mobileWarning.style.display = 'none';
      }, 5000);
    } else {
      console.log('log: non-mobile environment');
      canvas.style.width = '640px';
      canvas.style.height = '320px';
    }
    loadingBar.style.display = 'block';
    //@ts-ignore
    createUnityInstance(canvas, config, (progress: any) => {
      progressBarFull.style.width = 100 * progress + '%';
    })
      .then((unityInstance: any) => {
        loadingBar.style.display = 'none';
        fullscreenButton.onclick = () => {
          unityInstance.SetFullscreen(1);
        };
        this.mUnityInstance = unityInstance;
      })
      .catch((message: any) => {
        //alert(message);
        console.error(message);
      });
  }
1 Like