tauri icon indicating copy to clipboard operation
tauri copied to clipboard

[bug] WebSocket HMR not working as expected with Nuxt

Open Sun-ZhenXing opened this issue 1 year ago • 5 comments

Describe the bug

The methods described in this document does not mark HMR work on mobile devices.

Because Nuxt does not use vite's HMR config. Nuxt rewrite vite config, and uses ws://$host:$port/_nuxt/ to provide HMR:

09-27 18:01:57.473  9019  9019 E Tauri/Console: File: http://tauri.localhost/_nuxt/@vite/client - Line 535 - Msg: WebSocket connection to 'ws://tauri.localhost/_nuxt/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
09-27 18:01:57.473  9019  9019 E Tauri/Console: File: http://tauri.localhost/_nuxt/@vite/client - Line 535 - Msg: Uncaught (in promise) SyntaxError: Failed to construct 'WebSocket': The URL 'ws://localhost:undefined/_nuxt/' is invalid.

It tries to connect to localhost:undefined and tauri.localhost, but this is incorrect.

All endpoints have been tried and there is no WebSocket support. This may require a direct connection to the host.

Reproduction

From official document: https://v2.tauri.app/start/frontend/nuxt/

adb devices # connect a Android devices ...

pnpm tauri android dev

If this is not detailed enough, please call me for reproduction.

Expected behavior

No error.

Full tauri info output

[✔] Environment
    - OS: Windows 10.0.22631 x86_64 (X64)
    ✔ WebView2: 129.0.2792.52
    ✔ MSVC: Visual Studio Community 2022
    ✔ rustc: 1.81.0 (eeb90cda1 2024-09-04)
    ✔ cargo: 1.81.0 (2dbb1af80 2024-08-20)
    ✔ rustup: 1.27.1 (54dd3d00f 2024-04-24)
    ✔ Rust toolchain: stable-x86_64-pc-windows-msvc (default)
    - node: 20.14.0
    - pnpm: 9.11.0
    - npm: 10.7.0
    - bun: 1.1.28

[-] Packages
    - tauri 🦀: 2.0.0-rc.15
    - tauri-build 🦀: 2.0.0-rc.12
    - wry 🦀: 0.43.1
    - tao 🦀: 0.30.1
    - @tauri-apps/api : 2.0.0-rc.5
    - @tauri-apps/cli : 2.0.0-rc.16

[-] Plugins
    - tauri-plugin-log 🦀: 2.0.0-rc.2
    - @tauri-apps/plugin-log : not installed!

[-] App
    - build-type: bundle
    - CSP: connect-src ws://*
    - frontendDist: ../dist
    - devUrl: http://localhost:3000/
    - framework: Vue.js (Nuxt)
    - bundler: Webpack

Stack trace

09-27 18:02:41.207  9019  9019 E Tauri/Console: File: http://tauri.localhost/_nuxt/@vite/client - Line 535 - Msg: WebSocket connection to 'ws://tauri.localhost/_nuxt/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
09-27 18:02:41.209  9019  9019 E Tauri/Console: File: http://tauri.localhost/_nuxt/@vite/client - Line 535 - Msg: Uncaught (in promise) SyntaxError: Failed to construct 'WebSocket': The URL 'ws://localhost:undefined/_nuxt/' is invalid.
09-27 18:04:34.822  9019  9019 I HwViewRootImpl: removeInvalidNode jank list is null
09-27 18:04:37.867  9019  9019 I HwViewRootImpl: removeInvalidNode jank list is null
09-27 18:04:40.996  9019  9019 E Tauri/Console: File: http://tauri.localhost/__nuxt_devtools__/client/_nuxt/l4ouzdbv.js - Line 8 - Msg: Uncaught (in promise) Error: [birpc] timeout on calling "getOptions"
09-27 18:04:41.307  9019  9019 E Tauri/Console: File: http://tauri.localhost/__nuxt_devtools__/client/_nuxt/l4ouzdbv.js - Line 8 - Msg: Uncaught (in promise) Error: [birpc] timeout on calling "getModuleOptions"
09-27 18:04:41.309  9019  9019 E Tauri/Console: File: http://tauri.localhost/__nuxt_devtools__/client/_nuxt/l4ouzdbv.js - Line 8 - Msg: Uncaught (in promise) Error: [birpc] timeout on calling "getOptions"
09-27 18:04:41.312  9019  9019 E Tauri/Console: File: http://tauri.localhost/__nuxt_devtools__/client/_nuxt/l4ouzdbv.js - Line 8 - Msg: Uncaught (in promise) Error: [birpc] timeout on calling "telemetryEvent"
09-27 18:04:41.314  9019  9019 E Tauri/Console: File: http://tauri.localhost/__nuxt_devtools__/client/_nuxt/l4ouzdbv.js - Line 8 - Msg: Uncaught (in promise) Error: [birpc] timeout on calling "getOptions"

Additional context

No response

Sun-ZhenXing avatar Sep 27 '24 10:09 Sun-ZhenXing

I found a workaround:

{
  devServer: {
    host: isMobile ? '0.0.0.0' : undefined,
  },
  hooks: {
    'vite:extend': function ({ config }) {
      if (config.server && config.server.hmr && config.server.hmr !== true) {
        config.server.hmr.protocol = 'ws'
        config.server.hmr.host = '192.168.XXX.XXX'
        config.server.hmr.port = 3000
      }
    },
  },
  vite: {
    clearScreen: false,
    envPrefix: ['VITE_', 'TAURI_'],
    server: {
      strictPort: true,
      watch: {
        ignored: ['**/src-tauri/**'],
      },
    },
  },
}

But I think undefined appearing in URLs is a bug.

Sun-ZhenXing avatar Sep 27 '24 10:09 Sun-ZhenXing

Hey @Sun-ZhenXing can you share a working example, as I am getting a white screen creating a nuxt based app for mobile

georgiai1 avatar Nov 16 '24 06:11 georgiai1

I dig a little bit further and saw those errors as the culprit of the white screen

11-18 01:04:14.193 15907 15907 E Tauri/Console: File: - Line 138 - Msg: Uncaught TypeError: Cannot redefine property: postMessage 11-18 01:04:14.194 15907 15907 E Tauri/Console: File: - Line 2 - Msg: Uncaught TypeError: Cannot redefine property: metadata 11-18 01:04:14.194 15907 15907 E Tauri/Console: File: - Line 25 - Msg: Uncaught TypeError: Cannot redefine property: TAURI_PATTERN 11-18 01:04:14.194 15907 15907 E Tauri/Console: File: - Line 5 - Msg: Uncaught TypeError: Cannot redefine property: path

image

georgiai1 avatar Nov 18 '24 08:11 georgiai1

@gkkirilov Im suspecting about the blank screen is caused (correct me if Im wrong, those folders dont need to be generated for dev but I suspect Tauri needs it for app dev) because dist and .output folders are empty. When running npx tauri android dev after nuxi generate both folders content wipe with no reason apparently i don't know if Tauri is gonna use those folders because they ask to run nuxi generate... Ive taken some snapshots while npx tauri android dev --verbose was running and I got this 5 different both folders state:

FIRST STATE: issue1

SECOND STATE: (Notice that nitro.json is removed) issue2

THIRD STATE: issue3

FOURTH STATE: issue4

FIFTH STATE: issue5

The wipe of both folders occurs exactly at this part of the logging:

issue6

If I remove ssr: false the blank screen dissapears and content appears but looks messy obviously because ssr has no place here... anyways sometimes I get the app correctly rendered... those are the 3 possible cases but HMR still not working with @Sun-ZhenXing solution. In both cases the initial loading page of Nuxt appears as usual.

FIRST CASE:

issue7

SECOND CASE:

issue8

THIRD CASE:

issue9

Any clues?

igvoloj avatar Nov 27 '24 16:11 igvoloj

Here's my minimal working config. (Some of) the lengthy fs ignores are necessary to keep the server startup time low. It was taking well over 1 minute to startup without putting these ignores in.

The entire setup took me quite a few hours to figure out.

The main issue with HMR is the undefined value for the Vite WS port.

Screenshot 2024-11-30 at 12 45 18 AM

The vite:hook example above helped, but I needed to leave the original devServer values alone (better to take in what Tauri gives you anyway).

export default defineNuxtConfig({
  // (optional) Enable the Nuxt devtools
  devtools: { enabled: true },

  // Enable SSG
  ssr: false,
  ignore: ['**/src-tauri/**', '**/node_modules/**', '**/dist/**', '**/.git/**', '**/.nuxt/**', '**/.output/**'],

  // Enables the development server to be discoverable by other devices when running on iOS physical devices
  devServer: { host: process.env.TAURI_DEV_HOST || 'localhost' },

  vite: {
    // Better support for Tauri CLI output
    clearScreen: false,
    // Enable environment variables
    // Additional environment variables can be found at
    // https://v2.tauri.app/reference/environment-variables/
    envPrefix: ['VITE_', 'TAURI_'],
    server: {
      // Tauri requires a consistent port
      strictPort: true,
      watch: {
        ignored: [
          '**/src-tauri/**',
          '**/node_modules/**',
          '**/dist/**',
          '**/.git/**',
          '**/.nuxt/**',
          '**/public/**',
          '**/.output/**'
        ]
      }
    },
  },

  hooks: {
    'vite:extend': function ({ config }) {
      if (config.server && config.server.hmr && config.server.hmr !== true) {
        config.server.hmr.port = 3000
      }
    },
  },

  compatibilityDate: '2024-11-29'
});

JessicaSachs avatar Nov 30 '24 06:11 JessicaSachs

This got my HMR working. Thanks


    hooks: {
        'vite:extend': function ({ config }) {
            if (config.server && config.server.hmr && config.server.hmr !== true) {
                config.server.hmr.port = 3000
            }
        },
    },

    vite: {
        clearScreen: false,
        envPrefix: ['VITE_', 'TAURI_'],
        server: {
            watch: {
                ignored: ["**/src-tauri/**"],
                usePolling: true
            },
            strictPort: true,
            hmr: {
                host: '192.168.0.15',
                port: 5137,
                protocol: "ws"
            },
            
        },

        
        css: {
            preprocessorOptions: {
                scss: {
                    additionalData: '@use "@/assets/scss/variables.scss" as *;',
                },
            },
        },
    },
    
    ````

codywakeford avatar Jan 11 '25 15:01 codywakeford

Cargo.zip

When reproducing on my Android phone, I encountered another new issue tauri-apps/wry#1420.

I am attaching the Cargo lock file that works so that it can be debugged properly. Until the above issue is fixed, I can't confirm that the latest Tauri will work on my Android phone.

# Cargo.toml
[package]
name = "app"
version = "0.1.0"
description = "A Tauri App"
authors = ["you"]
license = ""
repository = ""
edition = "2021"
rust-version = "1.77.2"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
# Do not update tauri, till the issue is resolved

[lib]
name = "app_lib"
crate-type = ["staticlib", "cdylib", "lib"]

[build-dependencies]
tauri-build = { version = "2.0.0", features = [] }

[dependencies]
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
log = { version = "0.4" }
tauri = { version = "2.0.0", features = [] }
tauri-plugin-log = "2.0.0"
// nuxt.config.ts
// ...
import process from 'node:process'

const isMobile = !!/android|ios/.exec(process.env.TAURI_ENV_PLATFORM || '')
const host = process.env.NUXT_HMR_HOST || process.env.TAURI_DEV_HOST || undefined

// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  devServer: {
    host: isMobile ? '0.0.0.0' : undefined,
  },
  ignore: [
    '**/src-tauri/**',
    '**/node_modules/**',
    '**/dist/**',
    '**/.git/**',
    '**/.nuxt/**',
    '**/.output/**',
  ],
  hooks: {
    // [BUG] https://github.com/tauri-apps/tauri/issues/11165
    'vite:extend': host && isMobile
      ? ({ config }) => {
          if (config.server && config.server.hmr && config.server.hmr !== true) {
            config.server.hmr.protocol = 'ws'
            config.server.hmr.host = host
            config.server.hmr.port = 3000
          }
        }
      : undefined,
  },
  vite: {
    clearScreen: false,
    envPrefix: ['VITE_', 'TAURI_'],
    server: {
      watch: {
        ignored: ['**/src-tauri/**'],
        usePolling: true,
      },
      strictPort: true,
    },
    css: {
      preprocessorOptions: {
        scss: { api: 'modern-compiler' },
      },
    },
  },
})

I'm pretty sure that this problem can't be solved at the moment, because WebSocket doesn't seem to be able to be proxied yet.

So this workaround will work for a long time yet.

Sun-ZhenXing avatar Jan 23 '25 06:01 Sun-ZhenXing

I have similar problem.

This is my config

  compatibilityDate: '2024-11-01',
  devtools: { enabled: true },
  ssr: false,
  devServer: { host: process.env.TAURI_DEV_HOST || 'localhost' },
  hooks: {
    'vite:extend': function ({ config }) {
      if (config.server && config.server.hmr && config.server.hmr !== true) {
        config.server.hmr.port = 3000
      }
    },
  },
  vite: {
    clearScreen: false,
    envPrefix: ['VITE_', 'TAURI_'],
    server: {
      watch: {
        ignored: ["**/src-tauri/**"],
        usePolling: true
      },
      strictPort: true,
      hmr: {
        host: '192.168.1.2',
        port: 3000,
        protocol: "ws"
      },
    },
  },
})

I see in page data. I cant see in android emulator any data. When i remove ssr: false or set up ssr: true, i can see data in android emulator. However hmr never works for me. Any suggestions ?

in tauri conf i have

    "beforeDevCommand": "yarn dev",
    "beforeBuildCommand": "yarn generate",
    "devUrl": "http://localhost:3000",
    "frontendDist": "../dist"
  },

felek000 avatar Jan 31 '25 09:01 felek000