frandiox / vite-ssr

Use Vite for server side rendering in Node
MIT License
830 stars 92 forks source link

Crash on Vue 3.1 using onServerPrefetch #43

Closed IlyaSemenov closed 3 years ago

IlyaSemenov commented 3 years ago

vite-ssr crashes when using onServerPrefetch.

Example code:

<script lang="ts">
import { defineComponent, onServerPrefetch, ref } from "vue"

export default defineComponent({
    setup() {
        const data = ref("initial")
        onServerPrefetch(async () => {
            data.value = "server"
        })
        return { data }
    },
})
</script>

<template>
    <div>data = {{ data }}</div>
</template>

Steps to reproduce

~/tmp/2
❯ git clone https://github.com/IlyaSemenov/vite-ssr-crash.git
Cloning into 'vite-ssr-crash'...
remote: Enumerating objects: 13, done.
remote: Counting objects: 100% (13/13), done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 13 (delta 0), reused 13 (delta 0), pack-reused 0
Receiving objects: 100% (13/13), 12.28 KiB | 172.00 KiB/s, done.

~/tmp/2
❯ cd vite-ssr-crash

~/tmp/2/vite-ssr-crash master
❯ nodenv local 16.0.0

~/tmp/2/vite-ssr-crash master
❯ yarn
yarn install v1.22.10
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
warning "vite-ssr > @rollup/plugin-replace@2.4.2" has unmet peer dependency "rollup@^1.20.0 || ^2.0.0".
warning "vite-ssr > react-ssr-prepass@1.4.0" has unmet peer dependency "react@^16.8.0 || ^17.0.0".
warning "vite-ssr > @rollup/plugin-replace > @rollup/pluginutils@3.1.0" has unmet peer dependency "rollup@^1.20.0||^2.0.0".
warning Workspaces can only be enabled in private projects.
[4/4] 🔨  Building fresh packages...
✨  Done in 1.65s.

~/tmp/2/vite-ssr-crash master
❯ yarn dev
yarn run v1.22.10
$ vite-ssr
Pre-bundling dependencies:
  vite-ssr
  @vue/runtime-core
  vite-ssr/vue/entry-client
  vite-ssr/vue/entry-server
(this will be run only when your dependencies or config have changed)

  vite v2.3.8 dev server running at:

  > Local: http://localhost:3000/
  > Network: use `--host` to expose

 -- SSR mode

TypeError: render is not a function
    at handleSsrRequest (/Users/semenov/tmp/2/vite-ssr-crash/node_modules/vite-ssr/dev/server.js:88:37)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
10:40:51 PM [vite] Internal server error: render is not a function
      at handleSsrRequest (/Users/semenov/tmp/2/vite-ssr-crash/node_modules/vite-ssr/dev/server.js:88:37)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)
/node_modules/vite-ssr/vue/entry-client.js:20
    const url = window.location;
                ^

ReferenceError: window is not defined
    at Module.viteSSR [as default] (/node_modules/vite-ssr/vue/entry-client.js:20:17)
    at eval (/Users/semenov/tmp/2/vite-ssr-crash/src/main.ts:12:61)
    at instantiateModule (/Users/semenov/tmp/2/vite-ssr-crash/node_modules/vite/dist/node/chunks/dep-0ed4fbc0.js:69982:166)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
IlyaSemenov commented 3 years ago

Interestingly, in a slightly different environment I'm getting different crashes (on the same component):

[Vue warn]: Unhandled error during execution of setup function 
  at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > >
/node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:2929
        const apiName = __vite_ssr_import_1__.toHandlerKey(ErrorTypeStrings[type].replace(/ hook$/, ''));
                                                                                  ^

TypeError: Cannot read property 'replace' of undefined
    at injectHook (/node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:2929:83)
    at Module.eval (/node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:2941:5)
    at setup (/src/pages/index.vue:8:27)
    at _sfc_main.setup (/src/pages/index.vue:36:23)
    at callWithErrorHandling (/Users/semenov/work/xyzzy/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:156:22)
    at setupStatefulComponent (/Users/semenov/work/xyzzy/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:7069:29)
    at setupComponent (/Users/semenov/work/xyzzy/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:7025:11)
    at renderComponentVNode (/Users/semenov/work/xyzzy/node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:160:17)
    at renderVNode (/Users/semenov/work/xyzzy/node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:266:22)
    at renderComponentSubTree (/Users/semenov/work/xyzzy/node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:231:13)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
m4rvr commented 3 years ago

@IlyaSemenov You are importing from "@vue/runtime-core" which isn't correct, I think. Try to import from "vue" instead.

IlyaSemenov commented 3 years ago

@MarvinRudolph You must be kidding... vue simply re-exports these symbols from @vue/runtime-core.

But for the sake of brevity, I updated the reproduction repo. Obviously, that didn't change the outcome, it still crashes the same way.

m4rvr commented 3 years ago

@IlyaSemenov Well, it works for me. It crashes when I import from runtime-core with Internal server error: Cannot read property 'replace' of undefined. No errors when importing from vue. But it's still not correct to import from runtime-core. Vite handles dependencies differently and you should import from vue.

Looks like your alias causes that error. When I remove it, it works with your repro.

IlyaSemenov commented 3 years ago

But it's still not correct to import from runtime-core.

Yes, it is correct according to the documentation:

"This means you can install/import these deps individually [...]"

Vite handles dependencies differently and you should import from vue.

Vite (or rather, esbuild) uses node_modules/vue/package.json:

  "module": "dist/vue.runtime.esm-bundler.js",

which simply says:

export * from '@vue/runtime-dom';

There is nothing different or magic in this.

No errors when importing from vue. Looks like your alias causes that error.

That simply means there is some kind of race condition. Both using alias and importing directly from @vue/runtime-dom are fully correct and documented approaches, which work properly until onServerPrefetch is used.

For me, it crashes with import { ... } from "vue" as well. I haven't checked it without alias and honestly I don't see much point in doing so. I believe that until the documentation says "don't use aliases with server prefetch" (which is nonsense) there's no point in blaming aliases.

m4rvr commented 3 years ago

I don't have any problems with alias and onServerPrefetch in a TypeScript project. Resolves modules with @/foo.ts without problems, no errors or crashes. Maybe your tsconfig.json is wrong?

IlyaSemenov commented 3 years ago

Let's please stop this conversation, because you're not helping.

I have provided the reproduction repo which the project author may (or may not) find useful.

m4rvr commented 3 years ago

Just wanted to help ¯_(ツ)_/¯

IlyaSemenov commented 3 years ago

I realise that you wanted to help, but you gave three meaningless advices in a row: 1) Replace import source, without understanding that it's simply a shortcut re-export. 2) Remove alias from vite config, without understanding that aliases have nothing to do with the problem (and even if it did help by coincidence, that would constitute an error by itself). 3) Check tsconfig.json (without pointing to a specific error), as if it were a resolve problem (which it is clearly not).

No offense, but it's clear that you're not as competent as you probably think you are (this is called Dunning–Kruger effect). That is why I personally asked you to stop, because, again, you're not helping, even if you truly had best intentions.

IlyaSemenov commented 3 years ago

On a separate note, I worked around the problem by implementing a hook similar to fastify-vite's useServerData, which:

Still, I believe onServerFetch deserves to be fixed.

m4rvr commented 3 years ago

Wow, you are so smart, Ilya! Everyone should fall to the knees in front of you. 🙄 It still works without any problems for me when following the documentation. No problems with onServerPrefetch in a ts project. So at this point it's clearly your fault if you can't set up the project correctly. Why not just create your app with the vite cli? No need to be unfriendly to people who just want to help. Also, there is no reason to import from compiler-core directly. Just doesn't make sense. That's why vue re-exports it. But well, do your thing, good luck.

IlyaSemenov commented 3 years ago

Thank you for pointing that without aliases it does work. I concur that, and I was able to significantly simplify the reproduction case.

Of course, that doesn't mean that aliases itself are the problem (it is a widely used, documented feature), but it means that the problem resides at some different level, apparently in SSR module resolver/loader. Using aliases + onServerPrefetch simply surfaces it by coincidence.

I opened a separate issue and will close this one.