Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bug] SvelteKit SPA window is not defined on build #6554

Closed
Owez opened this issue Mar 25, 2023 · 9 comments
Closed

[bug] SvelteKit SPA window is not defined on build #6554

Owez opened this issue Mar 25, 2023 · 9 comments
Labels
status: needs triage This issue needs to triage, applied to new issues type: bug

Comments

@Owez
Copy link

Owez commented Mar 25, 2023

Describe the bug

Bug report stems from #6226 (see #6226 (comment)). I'm trying to use Tauri with SvelteKit using an SPA, but I'm having troubles trying to deploy it.

When I run npm run build or npm run tauri build, the SvelteKit app errors out in the build process during the vite build packaging because of the @tauri-apps/api package including the following check (formatted code, its normally in a single line bundle):

"__TAURI_METADATA__" in window ? b = new s(window.__TAURI_METADATA__.__currentWindow.label, {
    skip: !0
}) : (console.warn(`Could not find "window.__TAURI_METADATA__". The "appWindow" value will reference the "main" window label.
Note that this is not an issue if running this frontend on a browser instead of a Tauri window.`), b = new s("main", {
    skip: !0
}));

This errors out with the following:

ReferenceError: window is not defined
    at file:///Users/owen/Projects/yark/yark-pages/node_modules/@tauri-apps/api/chunk-QSWLDHGO.js:1:9678
    at ModuleJob.run (node:internal/modules/esm/module_job:193:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:530:24)
    at async analyse (file:///Users/owen/Projects/yark/yark-pages/node_modules/@sveltejs/kit/src/core/postbuild/analyse.js:56:16)
    at async process.<anonymous> (file:///Users/owen/Projects/yark/yark-pages/node_modules/@sveltejs/kit/src/utils/fork.js:25:17)

I have SvelteKit SPA set up correctly with adapter-static and export const ssr = false in my root +layout.ts. It seems to be an issue with Vite always wanting to run SSR no matter what's been configured, so for now guarding Tauri is the only real solution.

image

Reproduction

  1. Create a new SvelteKit SPA with the fallback page for tauri
  2. Import and use @tauri-apps/api somewhere (im using it for FS open file/folder)
  3. Create a plain Tauri application for the SvelteKit SPA
  4. Build it

Expected behavior

It should build a working Tauri bundle.

Platform and versions

Environment
  › OS: Mac OS 12.5.1 X64
  › Node.js: 18.12.1
  › npm: 8.19.2
  › pnpm: Not installed!
  › yarn: Not installed!
  › rustup: 1.25.1
  › rustc: 1.64.0
  › cargo: 1.64.0
  › Rust toolchain: stable-aarch64-apple-darwin 

Packages
  › @tauri-apps/cli [NPM]: 1.2.3
  › @tauri-apps/api [NPM]: 1.2.0
  › tauri [RUST]: 1.2.4,
  › tauri-build [RUST]: 1.2.1,
  › tao [RUST]: 0.15.8,
  › wry [RUST]: 0.23.4,

App
  › build-type: bundle
  › CSP: default-src 'self' http://127.0.0.1:7666
  › distDir: ../build
  › devPath: http://localhost:5173/
  › framework: Svelte
  › bundler: Vite

App directory structure
  ├─ node_modules
  ├─ static
  ├─ src-tauri
  ├─ .svelte-kit
  └─ src

Stack trace

owen@Owens-MacBook-Air yark-pages % npm run tauri build

> yark-pages@0.0.1 tauri
> tauri build

     Running beforeBuildCommand `npm run build`

> yark-pages@0.0.1 build
> vite build


vite v4.0.4 building SSR bundle for production...
transforming (65) src/routes/(start)/+page.svelte
/img/comingsoon.png referenced in /Users/owen/Projects/yark/yark-pages/src/routes/(start)/load/federated/+page.svelte?svelte&type=style&lang.css didn't resolve at build time, it will remain unchanged to be resolved at runtime
✓ 155 modules transformed.
12:57:43 PM [vite-plugin-svelte] ssr compile done.
package         files     time     avg
yark-pages         61    0.17s   2.7ms
@sveltejs/kit       1   14.0ms  14.0ms
file:///Users/owen/Projects/yark/yark-pages/node_modules/@tauri-apps/api/chunk-QSWLDHGO.js:1
import{a as p,b as _,c as w}from"./chunk-3WDDWFXT.js";import{a as t}from"./chunk-HNLFKTAJ.js";import{a as v}from"./chunk-FEIY7W7S.js";var C={};v(C,{CloseRequestedEvent:()=>y,LogicalPosition:()=>c,LogicalSize:()=>m,PhysicalPosition:()=>o,PhysicalSize:()=>l,UserAttentionType:()=>W,WebviewWindow:()=>s,WebviewWindowHandle:()=>u,WindowManager:()=>h,appWindow:()=>b,availableMonitors:()=>T,currentMonitor:()=>E,getAll:()=>M,getCurrent:()=>f,primaryMonitor:()=>z});var m=class{constructor(e,a){this.type="Logical";this.width=e,this.height=a}},l=class{constructor(e,a){this.type="Physical";this.width=e,this.height=a}toLogical(e){return new m(this.width/e,this.height/e)}},c=class{constructor(e,a){this.type="Logical";this.x=e,this.y=a}},o=class{constructor(e,a){this.type="Physical";this.x=e,this.y=a}toLogical(e){return new c(this.x/e,this.y/e)}},W=(a=>(a[a.Critical=1]="Critical",a[a.Informational=2]="Informational",a))(W||{});function f(){return new s(window.__TAURI_METADATA__.__currentWindow.label,{skip:!0})}function M(){return window.__TAURI_METADATA__.__windows.map(i=>new s(i.label,{skip:!0}))}var P=["tauri://created","tauri://error"],u=class{constructor(e){this.label=e,this.listeners=Object.create(null)}async listen(e,a){return this._handleTauriEvent(e,a)?Promise.resolve(()=>{let n=this.listeners[e];n.splice(n.indexOf(a),1)}):_(e,this.label,a)}async once(e,a){return this._handleTauriEvent(e,a)?Promise.resolve(()=>{let n=this.listeners[e];n.splice(n.indexOf(a),1)}):w(e,this.label,a)}async emit(e,a){if(P.includes(e)){for(let n of this.listeners[e]||[])n({event:e,id:-1,windowLabel:this.label,payload:a});return Promise.resolve()}return p(e,this.label,a)}_handleTauriEvent(e,a){return P.includes(e)?(e in this.listeners?this.listeners[e].push(a):this.listeners[e]=[a],!0):!1}},h=class extends u{async scaleFactor(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"scaleFactor"}}}})}async innerPosition(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"innerPosition"}}}}).then(({x:e,y:a})=>new o(e,a))}async outerPosition(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"outerPosition"}}}}).then(({x:e,y:a})=>new o(e,a))}async innerSize(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"innerSize"}}}}).then(({width:e,height:a})=>new l(e,a))}async outerSize(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"outerSize"}}}}).then(({width:e,height:a})=>new l(e,a))}async isFullscreen(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"isFullscreen"}}}})}async isMaximized(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"isMaximized"}}}})}async isDecorated(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"isDecorated"}}}})}async isResizable(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"isResizable"}}}})}async isVisible(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"isVisible"}}}})}async theme(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"theme"}}}})}async center(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"center"}}}})}async requestUserAttention(e){let a=null;return e&&(e===1?a={type:"Critical"}:a={type:"Informational"}),t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"requestUserAttention",payload:a}}}})}async setResizable(e){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"setResizable",payload:e}}}})}async setTitle(e){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"setTitle",payload:e}}}})}async maximize(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"maximize"}}}})}async unmaximize(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"unmaximize"}}}})}async toggleMaximize(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"toggleMaximize"}}}})}async minimize(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"minimize"}}}})}async unminimize(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"unminimize"}}}})}async show(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"show"}}}})}async hide(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"hide"}}}})}async close(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"close"}}}})}async setDecorations(e){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"setDecorations",payload:e}}}})}async setAlwaysOnTop(e){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"setAlwaysOnTop",payload:e}}}})}async setSize(e){if(!e||e.type!=="Logical"&&e.type!=="Physical")throw new Error("the `size` argument must be either a LogicalSize or a PhysicalSize instance");return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"setSize",payload:{type:e.type,data:{width:e.width,height:e.height}}}}}})}async setMinSize(e){if(e&&e.type!=="Logical"&&e.type!=="Physical")throw new Error("the `size` argument must be either a LogicalSize or a PhysicalSize instance");return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"setMinSize",payload:e?{type:e.type,data:{width:e.width,height:e.height}}:null}}}})}async setMaxSize(e){if(e&&e.type!=="Logical"&&e.type!=="Physical")throw new Error("the `size` argument must be either a LogicalSize or a PhysicalSize instance");return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"setMaxSize",payload:e?{type:e.type,data:{width:e.width,height:e.height}}:null}}}})}async setPosition(e){if(!e||e.type!=="Logical"&&e.type!=="Physical")throw new Error("the `position` argument must be either a LogicalPosition or a PhysicalPosition instance");return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"setPosition",payload:{type:e.type,data:{x:e.x,y:e.y}}}}}})}async setFullscreen(e){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"setFullscreen",payload:e}}}})}async setFocus(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"setFocus"}}}})}async setIcon(e){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"setIcon",payload:{icon:typeof e=="string"?e:Array.from(e)}}}}})}async setSkipTaskbar(e){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"setSkipTaskbar",payload:e}}}})}async setCursorGrab(e){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"setCursorGrab",payload:e}}}})}async setCursorVisible(e){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"setCursorVisible",payload:e}}}})}async setCursorIcon(e){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"setCursorIcon",payload:e}}}})}async setCursorPosition(e){if(!e||e.type!=="Logical"&&e.type!=="Physical")throw new Error("the `position` argument must be either a LogicalPosition or a PhysicalPosition instance");return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"setCursorPosition",payload:{type:e.type,data:{x:e.x,y:e.y}}}}}})}async setIgnoreCursorEvents(e){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"setIgnoreCursorEvents",payload:e}}}})}async startDragging(){return t({__tauriModule:"Window",message:{cmd:"manage",data:{label:this.label,cmd:{type:"startDragging"}}}})}async onResized(e){return this.listen("tauri://resize",e)}async onMoved(e){return this.listen("tauri://move",e)}async onCloseRequested(e){return this.listen("tauri://close-requested",a=>{let n=new y(a);Promise.resolve(e(n)).then(()=>{if(!n.isPreventDefault())return this.close()})})}async onFocusChanged(e){let a=await this.listen("tauri://focus",d=>{e({...d,payload:!0})}),n=await this.listen("tauri://blur",d=>{e({...d,payload:!1})});return()=>{a(),n()}}async onScaleChanged(e){return this.listen("tauri://scale-change",e)}async onMenuClicked(e){return this.listen("tauri://menu",e)}async onFileDropEvent(e){let a=await this.listen("tauri://file-drop",r=>{e({...r,payload:{type:"drop",paths:r.payload}})}),n=await this.listen("tauri://file-drop-hover",r=>{e({...r,payload:{type:"hover",paths:r.payload}})}),d=await this.listen("tauri://file-drop-cancelled",r=>{e({...r,payload:{type:"cancel"}})});return()=>{a(),n(),d()}}async onThemeChanged(e){return this.listen("tauri://theme-changed",e)}},y=class{constructor(e){this._preventDefault=!1;this.event=e.event,this.windowLabel=e.windowLabel,this.id=e.id}preventDefault(){this._preventDefault=!0}isPreventDefault(){return this._preventDefault}},s=class extends h{constructor(e,a={}){super(e),a!=null&&a.skip||t({__tauriModule:"Window",message:{cmd:"createWebview",data:{options:{label:e,...a}}}}).then(async()=>this.emit("tauri://created")).catch(async n=>this.emit("tauri://error",n))}static getByLabel(e){return M().some(a=>a.label===e)?new s(e,{skip:!0}):null}},b;"__TAURI_METADATA__"in window?b=new s(window.__TAURI_METADATA__.__currentWindow.label,{skip:!0}):(console.warn(`Could not find "window.__TAURI_METADATA__". The "appWindow" value will reference the "main" window label.
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            

ReferenceError: window is not defined
    at file:///Users/owen/Projects/yark/yark-pages/node_modules/@tauri-apps/api/chunk-QSWLDHGO.js:1:9678
    at ModuleJob.run (node:internal/modules/esm/module_job:193:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:530:24)
    at async analyse (file:///Users/owen/Projects/yark/yark-pages/node_modules/@sveltejs/kit/src/core/postbuild/analyse.js:56:16)
    at async process.<anonymous> (file:///Users/owen/Projects/yark/yark-pages/node_modules/@sveltejs/kit/src/utils/fork.js:25:17)

Node.js v18.12.1
[vite-plugin-sveltekit-compile] Failed with code 1
error during build:
Error: Failed with code 1
    at ChildProcess.<anonymous> (file:///Users/owen/Projects/yark/yark-pages/node_modules/@sveltejs/kit/src/utils/fork.js:68:13)
    at ChildProcess.emit (node:events:513:28)
    at ChildProcess._handle.onexit (node:internal/child_process:291:12)
       Error beforeBuildCommand `npm run build` failed with exit code 1

Additional context

No response

@Owez Owez added status: needs triage This issue needs to triage, applied to new issues type: bug labels Mar 25, 2023
@Owez Owez changed the title SvelteKit SPA window is not defined on build [bug] SvelteKit SPA window is not defined on build Mar 25, 2023
@amrbashir
Copy link
Member

This is the same issue as #6226
closing as duplicate

@amrbashir amrbashir closed this as not planned Won't fix, can't repro, duplicate, stale Mar 26, 2023
@cegredev
Copy link

I figured out a workaround!

This bug is preventing me from shipping my Tauri + SvelteKit application, so I came up with this:

$lib/tauriFix.ts

let invokeFunction: any = () => console.log('invoking nothing!');

if (!import.meta.env.SSR) {
	const { invoke } = await import('@tauri-apps/api');
	invokeFunction = invoke;
}

export async function invoke<T>(name: string, args?: any): Promise<T> {
	return await invokeFunction(name, args);
}

Since the error is probably caused by importing @tauri-apps/api, I made my own wrapper ("invokeFunction") for invoke which does nothing if in an SSR environment. However, if not in an SSR environment, I await import the invoke method from @tauri-apps and set invokeFunction to that. Finally, I export my own invoke method which interally just calls invokeFunction and returns the result of that. And that's (mostly) it!

Now for this to work, we need top level await, which is not supported by default (at least it wasn't for me). Luckily, all you need to do is to modify your vite.config.ts to look like this:

vite.config.ts

export default defineConfig({
	//...
	build: {
		target: 'esnext'
	},
	//...
});

I did the same thing for a few more tauri functions, but it works in the exact same way.

This is very ugly though, especially since you lose type all type information about the functions (unless you want to manually copy and maintain the interfaces from Tauri's source) and I hope this could be fixed someday.

@FabianLars
Copy link
Member

@cegredev If it's just about invoke it should also be possible to replace import { inovke } from "@tauri-apps/api" with import { inovke } from "@tauri-apps/api/tauri" (note the /tauri at the end). This way the SSR-incompatible variables are not in scope for the import.

@cegredev
Copy link

@FabianLars That works too and is a lot cleaner! Thanks! Does this just work with invoke or with other functions like dialog/open as well?

@FabianLars
Copy link
Member

It will work with all modules that don't export variables (only functions and objects), iirc this currently includes the path and window modules (therefore the "root" module you imported invoke from too). All others should work with the "normal" import.

@cegredev
Copy link

Good to know, thank you! I'll stick to my solution where there's no other way, then.

@cegredev
Copy link

@FabianLars Actually, I think using @tauri-apps/api/tauri causes a problem in builds: Whenever I try to start my build and I'm using that version of invoke, all I get is a white screen. Probably a combination of that and a lot of other factors, but I'm going to stay away from it for now.

@Owez
Copy link
Author

Owez commented May 19, 2023

Woah thanks @cegredev :) I didn't get a notification before but this seems to work!

@gknapp
Copy link

gknapp commented Aug 12, 2024

I've updated my imports to use either:

import { invoke } from "@tauri-apps/api"

or

import { invoke } from "@tauri-apps/api/tauri"

The same issue as seen in #6226 persists in my debug & production build (v1.6.0).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: needs triage This issue needs to triage, applied to new issues type: bug
Projects
None yet
Development

No branches or pull requests

5 participants