frandiox / vite-ssr Goto Github PK
View Code? Open in Web Editor NEWUse Vite for server side rendering in Node
License: MIT License
Use Vite for server side rendering in Node
License: MIT License
Hi,
is there possibility to use this configuration https://vitejs.dev/config/#base to configure base path?
In my case it is not working if I use this in vite.config.ts with this configuration: "build": "node node_modules/vite-ssr/cli.js build",
It doesn't make sense to re-implement production server every time.
Similarly to vite preview
, there could be vite-ssr preview
that runs a local web server.
Also, there should be lower-level exports (say in vite-ssr/server
) for:
renderHtml
(so that the end user doesn't need to deal with importing from dist
folder, suppress type warnings, etc.)createApp
or something along the lines, an Express/Connect app that doesn't listen by itself but could be injected into own http serverI believe ssr-manifest.json
is logically a server dependency and thus should rather be stored in dist/server
.
Let's say I want to deploy a SSR server as a micro-service (and publish assets at CDN).
For the micro-service, I will need the entire dist/server
folder and for some reason one file from client
(which is not used by the client itself). How so?
how can I load bootrap 5 in client only?
The documentation says one can use SPA mode:
SPA mode:
vite dev
command runs Vite directly without any SSR.
However this results in deserialization error:
state.js:27 [SSR] On state deserialization - SyntaxError: Unexpected token u in JSON at position 0
at JSON.parse (<anonymous>)
at deserializeState (state.js:24)
at viteSSR2 (entry-client.js:20)
at main.ts:6 undefined
Hi,
Not sure it's the right place but I'm taking a chance here since it may generate ideas for ways to implement this (in a smart way that I'm tring to) in the future.
I'm trying to give to ViteSSR different routes based on localization.
First idea was to try to set the routes (with router.addroute()) inside of the base method inside ViteSSR export, but it's too late to edit the routes, it absolutely has to happen before.
Then I tried editing the routes in the async(ctx) => {}
, and it's working but for the SSR part only, because on hydration, the page disappears. I assume it's because SSR and Vue hydration don't have the same routes to work with.
I'm still learning Vue and I'm sorry if some things seems obvious. I'm using the boilerplate by the author of this package to help me getting started: https://github.com/frandiox/vitesse-ssr-template
Here is what I got to:
export default viteSSR(
App,
{
// Use Router's base for i18n routes
base: ({ url }) => {
const locale = extractLocaleFromPath(url.pathname)
return locale === DEFAULT_LOCALE ? '/' : `/${locale}/`
},
routes,
},
async(ctx) => {
// install all modules under `modules/`
Object.values(import.meta.globEager('./modules/*.ts')).map(i =>
i.install?.(ctx),
)
const { app, url, router, isClient, initialState, initialRoute } = ctx
setLocalizedRoutes(router)
...
setLocalizedRoutes() adds the localized routes to the router (and works, because router.getRoutes() gives me the good localized routes juste under).
I tried setting up before ViteSSR export, but router.currentRoute is always set at / and no way to check the language from URL then, and it makes sense it's not set yet.
Would there be a way to get routes based on language to work in that context? I don't mind losing the instant translation on language switching.
Any help would be welcome, thank you so so much.
We need a module export option for node applications that runs with mjs.
For example I have a fastify server with module system and I cannot import dist/server/main.js
becauase it uses require.
There can be an option like this for module nodejs or vite-ssr can bundle another file as main.mjs
plugins: [
ssr({
build: {
esm: true
}
})
]
Hello π I want to create a variable, that is from the initialState
, but is local for only one request.
In this example, I have a stack, that adds and pops numbers. The value is coming from the initialState
. Everything works fine, except, that the initialState
stays the same for every page refresh. Is there a way to define a "local" kinda variable?
import { useContext } from 'vite-ssr'
import { ref, readonly } from 'vue'
const state = ref<number[]>([])
export function useStack() {
const context = useContext()
if (context.isClient) {
state.value = context.initialState.stack || []
}
return {
add(n: number) {
state.value.push(n)
context.initialState.stack = state.value
},
pop() {
state.value.pop()
context.initialState.stack = state.value
},
get state() {
return readonly(state.value)
},
}
}
<script lang="ts" setup>
import { onMounted, onServerPrefetch } from 'vue'
import { useStack } from './composables'
const stack = useStack()
onMounted(() => {
console.log(stack.state) // expect to be [1] on every request, but get [1, ...1 * n request]
})
onServerPrefetch(() => {
stack.add(1)
})
</script>
<template>
<pre>{{ stack.state }}</pre>
</template>
When used with vite-plugin-compress
the resulting files in ./dist
are all compressed.
It only resolve root of the path pages
, but can't resolve some page in child folder.
.pages
βββ About.jsx
βββ Home.jsx
βββ note
β βββ api.jsx
β βββ index.jsx // can't resolve
βββ notes
βββ :id.jsx
Hi,
maybe I am missing something, but currently the router instance is only getting returned inside the viteSSR HookParams.
What if I want to use some kind of axios interceptor, in order to automatically redirect the user to some route in case of a 401 for example.
Also I am thinking about implementing an auth composable in which there should be a login and logout method. These need to be able to redirect the user to some routes.
How would you build this kind of thing? Do I really have to build everything router related inside the hook function?
Thank your very much in advance for all your work and effort.
I see that this project uses ^1.0.0-rc.9
Line 25 in 33fa848
I'd really love to see it use the latest - 2.0.0-beta.33
vite-ssr build
removes index.html
from the client bundle:
Lines 113 to 119 in f376c92
I was not expecting this behaviour as a normal Vite SSR build would include the index.html
in the client bundle.
For my purposes, I do want the index.html
in my client bundle, since I am only selectively using SSR on a few routes on my site, and serving a regular SPA for the rest.
Would it be possible to remove this behaviour from vite-ssr
? If the intention is to provide a easy to use SSR plugin for Vite users, I feel that it would be better if vite-ssr
's behaviour does not deviate too much from Vite's own SSR support. I would also be happy with a vite-ssr
CLI flag to retain index.html
!
Happy to submit a PR for either option. Thanks again for this easy-to-use package!
If you use @vitejs/plugin-legacy
in the project and try to build server, this error occures
A:\Desktop\VUE\kyzc-portfolio\node_modules\.pnpm\[email protected]_1875ae38a9ea4201aa9b0ba5cafe20a3\node_modules\vite-ssr\build\index.js:20
const indexHtml = clientResult.output.find((file) => file.type === 'asset' && file.fileName === 'index.html');
^
TypeError: Cannot read property 'find' of undefined
at module.exports (A:\Desktop\VUE\kyzc-portfolio\node_modules\.pnpm\[email protected]_1875ae38a9ea4201aa9b0ba5cafe20a3\node_modules\vite-ssr\build\index.js:20:43)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async A:\Desktop\VUE\kyzc-portfolio\node_modules\.pnpm\[email protected]_1875ae38a9ea4201aa9b0ba5cafe20a3\node_modules\vite-ssr\cli.js:19:9
βERRORβ Command failed with exit code 1.
Hi @frandiox, thanks for such an awesome library.
I'm currently getting the following error when I try to declare and use Vuex store
[vite] Error when evaluating SSR module /src/store/store.getters.ts:
SyntaxError: Unexpected token '.'
at new Function (<anonymous>)
at instantiateModule (/Users/xxx/.../node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-6b5f3ba8.js:68222:9)
SyntaxError: Unexpected token '.'
at new Function (<anonymous>)
at instantiateModule (/Users/xxx/.../node_modules/.pnpm/[email protected]/node_modules/vite/dist/node/chunks/dep-6b5f3ba8.js:68222:9)
3:38:59 PM [vite] Internal server error: Unexpected token '.'
store.getters.ts
import { GetterTree } from 'vuex'
import { StoreState } from './store.state'
const getters: GetterTree<StoreState, StoreState> = {
isAuthenticated(state) {
return !!state.user?.uid
}
}
export default getters
If I removed the optional chaining state.user?.uid
and did state.user && state.user.uid
it works alright. This has caused me to dynamically import createStore
and initialize the store when not in SSR mode
const unwrapStore = () => import('./store/store.index')
export default viteSSR(
App,
{ routes, base: () => '/' },
async ({ app, router, initialState, initialRoute }) => {
if (!import.meta.env.SSR) {
const r = await unwrapStore()
const store = r.default()
app.use(store, r.key)
store.replaceState(initialState)
}
})
Now the problem is that I can't use the store in setup()
in SSR mode. So the following will either fail or throw an error cannot reference commit of undefined
setup() {
const store = useStore()
store.commit("ACTION", payload)
}
Hello,
I'm trying to use Apollo Client with SSR and React.
My idea was to create a InMemoryCache
and extract data from the store. It seams that viteSSR
does not wait the resolution of a query. If I add a setTimeout
to the hook of viteSSR
, I cant print the good content of the store.
According the Apollo Documentation, I have to use renderToStringWithData
. But I have no idea how I can manage with vite-ssr plugin. Is it possible?
Thank you very much.
./server/index.js
// This is the server renderer we just built
const main = import('../dist/server/main.js');
server.get('*', async (req, res) => {
const url = `${req.protocol}://${req.get('host')}${req.originalUrl}`;
const renderPage = (await main).default.default;
const apolloCache = new InMemoryCache();
const { html } = await renderPage(url, {
manifest,
apolloCache,
preload: true,
});
res.setHeader('Cache-Control', 'max-age=0');
res.end(html);
});
./src/App.jsx
const App = ({
isClient,
apolloCache = new InMemoryCache(),
}) => {
const client = new ApolloClient({
link: createHttpLink({
uri: 'http://localhost:8080/graph',
credentials: 'same-origin',
}),
ssrMode: !isClient,
cache: apolloCache,
credentials: 'same-origin',
});
...
./src/main.jsx
export default viteSSR(App, { routes }, ({
initialState,
apolloCache,
}) => {
if (import.meta.env.SSR) {
setTimeout(() => {
console.log(apolloCache.extract()) // not empty
}, 1000)
initialState.apolloCache = apolloCache.extract();
}
// Custom initialization hook
})
Hey!
After I've upgraded from v0.10.5
to v0.10.6
, TypeScript no longer knows that the request
& response
properties exist in the entry hook.
import viteSSR from 'vite-ssr/vue'
export default viteSSR(
App,
{
routes,
// This works fine now
pageProps: {
passToPage: false,
},
},
// Property `request`/`response` does not exist on type ...
({ app, initialState, router, request, response }) => {
// ...
}
)
When a template ref is applied to a VNode slotted in ClientOnly, the ref is never available
<!-- This template won't work -->
<template lang="pug">
.relative: ClientOnly: .absolute.inset-0(ref="foo")
</template>
<!-- This template works -->
<template lang="pug">
.relative: .absolute.inset-0(ref="foo")
</template>
<!-- Log ref in watcher & mount hook -->
<script setup lang="ts">
import { onMounted, ref, watch } from 'vue'
const foo = ref<HTMLDivElement | null>(null)
watch(foo, x => console.info(x))
onMounted(() => console.info(foo?.value))
</script>
package.json
for afffected project{
"private": true,
"engines": {
"node": ">=14"
},
"scripts": {
"bi": "bi --pm pnpm",
"fetch": "node ./scripts/fetch-metadata",
"gen": "node ./scripts/generate-entities",
"dev": "vite-ssr --port 3333 --open",
"dev:spa": "vite --port 3333 --open",
"clean": "rm -rf dist; rm -rf api/renderer",
"build": "pnpm clean; cross-env NODE_ENV=production vite-ssr build; ./scripts/move-dist.sh",
"preview": "vc dev"
},
"dependencies": {
"@replygirl/tc": "^3.0.0",
"@vue/reactivity": "^3.0.11",
"@vue/server-renderer": "^3.0.11",
"@vueuse/core": "^4.9.3",
"@vueuse/head": "^0.5.1",
"axios": "^0.21.1",
"breeze-client": "^2.1.1",
"change-case": "^4.1.2",
"element-plus": "^1.0.2-beta.44",
"graphql": "^15.5.0",
"hash-sum": "^2.0.0",
"node-fetch": "^2.6.1",
"nprogress": "^0.2.0",
"pluralize": "^8.0.0",
"prism-theme-vars": "^0.2.2",
"querystring": "^0.2.1",
"vite-ssr": "^0.8.1",
"vue": "^3.0.11",
"vue-i18n": "^9.1.6",
"vue-router": "^4.0.6",
"vue3-google-map": "^0.7.6"
},
"devDependencies": {
"@antfu/eslint-config": "^0.6.5",
"@iconify/json": "^1.1.341",
"@intlify/vite-plugin-vue-i18n": "^2.1.2",
"@replygirl/curse": "^3.0.0-beta.0",
"@types/apple-mapkit-js-browser": "^5.50.0",
"@types/axios": "^0.14.0",
"@types/btoa": "^1.2.3",
"@types/dotenv-flow": "^3.1.0",
"@types/eslint": "^7.2.10",
"@types/eslint-config-prettier": "^6.11.0",
"@types/eslint-plugin-prettier": "^3.1.0",
"@types/hash-sum": "^1.0.0",
"@types/node": "^14.14.43",
"@types/node-fetch": "^2.5.10",
"@types/nprogress": "^0.2.0",
"@types/pluralize": "^0.0.29",
"@types/prettier": "^2.2.3",
"@types/pug": "^2.0.4",
"@types/rimraf": "^3.0.0",
"@typescript-eslint/eslint-plugin": "^4.23.0",
"@vercel/node": "^1.10.0",
"@vitejs/plugin-vue": "^1.2.2",
"@vue/compiler-sfc": "^3.0.11",
"better-install": "^0.1.0",
"breeze-entity-generator": "^1.0.0",
"btoa": "^1.2.1",
"cross-env": "^7.0.3",
"dotenv-flow": "^3.2.0",
"eslint": "^7.26.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^3.4.0",
"markdown-it-prism": "^2.1.6",
"pnpm": "^6.3.0",
"prettier": "2.3.0",
"pug": "^3.0.2",
"rimraf": "^3.0.2",
"ts-node": "^9.1.1",
"type-fest": "^1.1.1",
"typescript": "^4.2.4",
"vite": "^2.3.0",
"vite-plugin-components": "^0.9.0",
"vite-plugin-icons": "^0.5.0",
"vite-plugin-md": "^0.6.6",
"vite-plugin-pages": "^0.11.1",
"vite-plugin-pwa": "^0.7.3",
"vite-plugin-vue-layouts": "^0.3.1",
"vite-plugin-windicss": "^0.15.10",
"vite-ssg": "^0.10.0"
}
}
Using the latest, if you have a public/manifest.json for Web app manifests https://developer.mozilla.org/en-US/docs/Web/Manifest it becomes overridden to nothing.
I've found a work around by putting the manifest file in a folder. I can add a note to the readme about this if this functionality is intended.
I'd been finding a way to append extra string to the body
:
vite-ssr/src/vue/entry-server.js
Line 60 in f0a7e02
Because I'm using this state management lib:
https://github.com/andrewcourtice/harlem/tree/main/plugins/ssr
to enable the SSR feature of it, it requires appending extra state data to the rendered string.
I wasn't able to find a way to do that, so would you add a hook that allows modify the body
?
Thanks!
When you have outDir option in vite.config.ts vite-ssr doesn't follow the rule and bundles every file to dist
in main folder.
Hi and thanks for what looks to be a very promising library
node_modules/vite-ssr/index.d.ts:21:3 - error TS2666: Exports and export assignments are not permitted in module augmentations.
Got this while linting the project with vue-tsc --noEmit
// This is a generic mix of framework types
import type { SharedContext, SharedOptions } from './utils/types'
declare module 'vite-ssr' {
const handler: (
App: any,
options: SharedOptions & {
routes: Array<Record<string, any>>
routerOptions?: Record<string, any>
styleCollector?: (ctx: any) => any
},
hook?: (
params: SharedContext & {
app: any
router: any
initialRoute: any
}
) => any
) => any
**export** default handler
export const ClientOnly: any
export const useContext: () => SharedContext
}
Updated export default handler
to
export default function (
App: any,
options: SharedOptions & {
routes: Array<Record<string, any>>
routerOptions?: Record<string, any>
styleCollector?: (ctx: any) => any
},
hook?: (
params: SharedContext & {
app: any
router: any
initialRoute: any
}
) => any
): any
And it stopped complaining.
Unfortunately, my skills in JS/TS only allow me to do so much -- I am completely clueless how to fix that so that the built version of the library on NPM will generate the proper .d.ts
file
Anyone any ideas?
vite-ssr
currently lacks any reasonable option to perform a server-side redirect.
Even though response
object is passed in context, one can't use it like:
export default viteSSR(App, { routes }, ({ response }) => {
// Simplified version
// In real code, that could be injected/provided as a consumable hook for Vue pages
response.setHeader("location", "/foo")
response.statusCode = 302
response.end()
})
because vite-ssr will always try to end it itself:
Lines 103 to 107 in d758af9
Suggestions:
if (!response.writableEnded) {
const html = buildHtmlDocument(template, htmlParts)
response.setHeader('Content-Type', 'text/html')
response.end(html)
}
status
, statusText
, headers
and body
not only from options.getRenderContext
but also from viteSSR
.This works:
setup() {
const component = defineAsyncComponent(() => import(`../HelloWorld.vue`));
return { component };
}
This doesn't
setup() {
const name = "HelloWorld";
const component = defineAsyncComponent(() => import(`../${name}.vue`));
return { component };
}
Error:
Error: failed to load module for ssr: ../HelloWorld.vue
at instantiateModule (C:\Projects\vite-ssr\node_modules\vite\dist\node\chunks\dep-2c03f3f9.js:69022:15)
It works when u first load another page then navigate over VueRouter / Dev:SPA also build seems to work.
It's kinda feature request
Hi - great package!
What do you think about adding the possibility to pass router configuration to the viteSSR? Right now it's not possible to leverage other configuration options like scrollBehavior
or linkActiveClass
.
Happy to work sth out and submit a PR as well.
Since the renderToHtml call is inside the module, would it be possible to install and use https://github.com/vueuse/head?
This is a spin-off of #43 where I incorrectly identified the problem at first.
In a small reproducible case, something causes importing client entry during SSR, which leads to hard crash (process exit). I had this on a larger project, but then simplified the setup to bare minimum for the reproduction.
https://github.com/IlyaSemenov/vite-ssr-crash
~/tmp/4
β― git clone https://github.com/IlyaSemenov/vite-ssr-crash.git
Cloning into 'vite-ssr-crash'...
remote: Enumerating objects: 26, done.
remote: Counting objects: 100% (26/26), done.
remote: Compressing objects: 100% (17/17), done.
remote: Total 26 (delta 5), reused 25 (delta 4), pack-reused 0
Receiving objects: 100% (26/26), 13.52 KiB | 157.00 KiB/s, done.
Resolving deltas: 100% (5/5), done.
~/tmp/4
β― cd vite-ssr-crash
~/tmp/4/vite-ssr-crash master
β― nodenv local 16.0.0
~/tmp/4/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/[email protected]" has unmet peer dependency "rollup@^1.20.0 || ^2.0.0".
warning "vite-ssr > [email protected]" has unmet peer dependency "react@^16.8.0 || ^17.0.0".
warning "vite-ssr > @rollup/plugin-replace > @rollup/[email protected]" 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.69s.
~/tmp/4/vite-ssr-crash master
β― yarn dev
yarn run v1.22.10
$ vite-ssr
Pre-bundling dependencies:
vite-ssr
vue
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
>>>>>>>>>>>>>> (in a separate console) curl localhost:3000
[Function (anonymous)]
TypeError: render is not a function
at handleSsrRequest (/Users/semenov/tmp/4/vite-ssr-crash/node_modules/vite-ssr/dev/server.js:88:37)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
12:57:31 AM [vite] Internal server error: render is not a function
at handleSsrRequest (/Users/semenov/tmp/4/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/4/vite-ssr-crash/src/main.ts:12:61)
at instantiateModule (/Users/semenov/tmp/4/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.
The two key points are:
alias
section in vite configonServerPrefetch
UPDATE:
I came up with even simpler version without onServerPrefetch
, which crashes the same way.
https://github.com/IlyaSemenov/vite-ssr-crash/tree/no_routes
git clone https://github.com/IlyaSemenov/vite-ssr-crash.git -b no_routes
I noticed that the __INITIAL_STATE__
object that was being inserted into the HTML had lots of escaped double quote characters (i.e., \"
), and it was because the entire initial state object was itself a string. Apparently the initial state is put through JSON.stringify
twice before unsafe characters are escaped! That seemed odd and unnecessary to me, so in my project I changed that part of the code in serializeState
to JSON.stringify only once and in deserializeState
to simply return state || {}
without extra parsing. It turns out this works just fineβall unsafe characters are properly escaped, and there is far less overhead in transmitting/parsing the initial state object this way.
A couple questions:
Hi, i download this project with example and i try start this. After start he say me "Error: Cannot find module 'vite-ssr/build'"
nodejs 15.4
If you just start a fresh vite project and follow the vite-ssr vue documentation. When you run vite-ssr dev
or build an ssr version and host it, you will get an empty page source (just an empty #app <div/>
)
Tried debugging it but I cannot find the cause. Is this something you can reproduce?
Hi, I've just dug around the source code of this project for a while, after comparing to other Vite SSR projects, I believe this is the best SSR plugin for Vite I could find in the market despite the number of stars this project got... I really appreciate your efforts for this project!
But I feel like "unsafe" to modify any options without the type hintings, really wish it can be written in ts for benefitting both the users and contributors π anyway, great works! Thanks!
After I run vite-ssr build
, then I follow the example for deploying to Serverless function (Vercel) but i ran into such problem.
There's no error during build phases.
Below are the error while previewing Vercel locally.
C:\Coding\my-vitesse-app\serverless\node_modules\vite-ssr\vue\entry-server.js:1
import { createSSRApp } from 'vue';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at wrapSafe (internal/modules/cjs/loader.js:979:16)
at Module._compile (internal/modules/cjs/loader.js:1027:27)
at Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Object.require.extensions.<computed> [as .js] (C:\Users\sians\AppData\Roaming\npm\node_modules\vercel\node_modules\ts-node\src\index.ts:832:44)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
at Module.require (internal/modules/cjs/loader.js:952:19)
at require (internal/modules/cjs/helpers.js:88:18)
at Module.<anonymous> (C:\Coding\my-vitesse-app\serverless\api\renderer\main.js:21:15)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
Error! `node api/index.js` failed with exit code 1
Then I tried to deploy straight to vercel, similar error as such
undefined ERROR /var/task/node_modules/vite-ssr/vue/entry-server.js:1
import { createSSRApp } from 'vue';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at wrapSafe (internal/modules/cjs/loader.js:979:16)
at Module._compile (internal/modules/cjs/loader.js:1027:27)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
at Module.require (internal/modules/cjs/loader.js:952:19)
at require (internal/modules/cjs/helpers.js:88:18)
at Module.<anonymous> (/var/task/api/renderer/main.js:9:15)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
RequestId: 0cf21fd7-254a-4550-97c3-c6bc3948db7d Error: Runtime exited with error: exit status 1
Runtime.ExitError
Finally, I've tried deploy as ExpressJS, similar issue happens.
I have a testing environment that can use either vite or webpack, and to do this I've create a separate index.vite.html
and index.webpack.html
for each bundler. The following plugin works for vite without SSR, but vite-ssr has index.html
hardcoded. I can't actually have a file called index.html
or webpack will try to serve it.
{
name: 'configure-server',
configureServer(server) {
return () => {
server.middlewares.use('/', (req, res, next) => {
if (req.url === '/index.html') req.url = '/index.vite.html'
return next()
})
}
}
},
Lines 52 to 56 in 2019dc6
Heya, me again.
(vue.js 3.0 app)
I was reading the source code and noticed that our initialization hook is run early on, which is great, however, in my application (similar to https://pinia.esm.dev/ssr/#state-hydration example) I have my custom data stores.
Trouble is, those are filled with data by components at arbitrary levels deep, and I only have the data once the app has been fully rendered, as I rely on onServerPrefetch(async () => {})
That means that the initialState
variable passed to the userland hook can't have the final data the server has fetched, as my hook is ran very early on. I need another hook right after this await
renderToString(app, context).then(deferred.resolve).catch(deferred.reject)
const body = await deferred.promise
To make things consistent on the client end, we could be running that hook after app.mount('#app', true)
Other than that, using this library has been a great experience so far!
Hey! Thank you for the great SSR solution! I have an issue with the initialState
: when I pass something inside, it adds attributes to the component.
The issue resolves by adding a wrapper to the page, but it adds unnecessary attributes π’
Is there any solution to that?
The vite-ssr
detects the root of the project as a directory where vite.config is placed. But the root may be different. The root can be defined in vite.config: https://vitejs.dev/config/#root
Also build.outDir
is ignored too. The vite-ssr
is only built in ./dist
.
I'd like to be able to build a separate mobile and desktop app with some shared code, and the same npm dependencies, but different builds. I would expect that most people would want to set up projects in this way, but always find it difficult to do for some reason.
From what I can see, it looks like vite-ssr
could make this easier by:
App
that is passed to viteSSR()
outDir
At this stage I'm not really sure how feasible this would be, so i might just rewrite or move a file in my package.json
scripts until things become easier.
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>
~/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/[email protected]" has unmet peer dependency "rollup@^1.20.0 || ^2.0.0".
warning "vite-ssr > [email protected]" has unmet peer dependency "react@^16.8.0 || ^17.0.0".
warning "vite-ssr > @rollup/plugin-replace > @rollup/[email protected]" 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.
Hi, thanks for all the efforts to create this project !!!
I noticed that Support Suspense in SSR was possible in vue3.
Does this mean I can use fetch data in async setup
instead of serverPrefetch
?
I didn't see any example code in the readme shows how to use this plugins with the vue3's setup
method, so if I'm wrong would you show me an example that works with the setup
method?
Thanks a lot!
Hi, I'm trying to add custom types to context but none of things I tried worked. Is there a way for this?
import {Request, Response} from 'express';
declare module 'vite-ssr' {
export interface Context {
request: Request,
response: Response
}
}
or
import {Request, Response} from 'express';
declare module 'vite-ssr/vue' {
export interface Context {
request: Request,
response: Response
}
}
Hi,
how can I pass my httponly cookie from clientcontext to ssrcontext?
My serverside is allways unauthenticated :(
Our vite config has the following config to connect via ssl in dev.
server: {
hmr: {
host: 'leveluptutorials.dev',
port: 443,
protocol: 'wss',
},
},
This config works fine with the standard vite cli, but causes an infinite loop using vite ssr. It's hard to debug because of the nature of things, but it seems like the wss connection is failing causing a refresh on loop.
The network shows a 502 request.
Request URL: https://leveluptutorials.dev/__vite_ping
Request Method: GET
Status Code: 502
Remote Address: 127.0.0.1:443
Referrer Policy: strict-origin-when-cross-origin
It's kind of tough to put together a reproduction given the ssl requirements, I can provide as much as possible to help and can dive into your code to see if there is anything that sticks out.
Edit:
Some additional information. The looping we're seeing is the same as if the hmr config settings were not set at all. This tells me that this library might not be seeing the server.hmr options.
Hello,
I'm using eslint with:
extends: ['plugin:react/recommended', 'airbnb'],
unfortunately when I try to import 'vite-ssr' I have this error:
ESLint: Unable to resolve path to module 'vite-ssr'.(import/no-unresolved)
If someone has an idea :)
vite-ssr v0.10.6
vue-router v4.0.10
vite v2.3.8
Sometimes I'm getting following messages in the console when the server (dev & production) is running:
[Vue Router warn]: No match found for location with path "/node_modules/.vite/chunk-YSFGVYJQ.js?v=7feddd3a"
[Vue Router warn]: No match found for location with path "/node_modules/.vite/chunk-WM2BNGP4.js?v=7feddd3a"
[Vue Router warn]: No match found for location with path "/node_modules/.vite/chunk-AU43JL3D.js?v=7feddd3a"
[Vue Router warn]: No match found for location with path "/node_modules/.vite/chunk-AJTGOAVB.js?v=7feddd3a"
[Vue Router warn]: No match found for location with path "/node_modules/.vite/chunk-YSFGVYJQ.js?v=7feddd3a"
[Vue Router warn]: No match found for location with path "/node_modules/.vite/chunk-WM2BNGP4.js?v=7feddd3a"
[Vue Router warn]: No match found for location with path "/node_modules/.vite/chunk-AU43JL3D.js?v=7feddd3a"
[Vue Router warn]: No match found for location with path "/node_modules/.vite/chunk-AJTGOAVB.js?v=7feddd3a"
Any idea where this is coming from since the router is configured by vite-ssr? I'm using vite-plugin-pages
for the routes.
EDIT 1:
Not sure what caused this but it's gone after reinstalling all dependencies.
EDIT 2:
Happens again for me over and over again when starting the development server. π
Say I define my routes as follows:
export const routes = [
{
path: '/',
component: () => import('./pages/Home.vue'),
name: Routes.Home,
},
{
name: 'UserProfile',
path: '/user/:uid',
component: () => import('./pages/User.vue'),
props: true,
},
{
path: '/:catchAll(.*)',
name: 'not-found',
component: () => import('./pages/404.vue'),
}
]
...In SPA mode, I don't get the vid
param as a prop and in SSR mode, I have to patch to.meta.state
as shown below to get vid
param injected into the component as a prop.
router.beforeEach((to, from, next) => {
if (to.meta.state) {
return next()
}
// pass route params to the page as props
to.meta.state = Object.assign(
{},
to.meta.state,
initialState,
initialRoute.params,
)
next()
})
I guess I'm not doing something right
Currently, ssr-manifest.json
stores full local filenames:
{
"/Users/semenov/work/xxx/node_modules/@vue/shared/dist/shared.esm-bundler.js": [
"/assets/vendor.8b10200d.js"
],
"/Users/semenov/work/xxx/node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js": [
"/assets/vendor.8b10200d.js"
],
main.js
also has this:
./server/main.js: (ssrContext.modules || (ssrContext.modules = new Set())).add("/Users/semenov/work/xxx/src/pages/index.vue");
./server/main.js: (ssrContext.modules || (ssrContext.modules = new Set())).add("/Users/semenov/work/xxx/src/App.vue");
Hey!
The docs describe the use of Vuex for the initial state but I'm not 100% sure how I need to use that in a component.
For me, it sounds like that I either need to use app.provide
(& inject
in components) or a store like Vuex. Is this correct?
Currently my code sets the state of the store to the value of the initialStore
parameter. The value is available in my components, but only on the client-side (I think?), because it shows the title and instantly deletes it. Do I still need to set the initial state to that value in the component like it's in the Homepage.vue
example when I use a store?
This is my setup() code of my component:
const store = useStore()
const title = ref(store.title || null)
if (!title.value) {
onServerPrefetch(() => {
title.value = 'Fetched title'
store.$patch({
title: title.value
})
})
}
The same code works when I inject the initialState and set it like initialState.title = title.value
.
EDIT:
For reference there is actually this documentation (https://pinia.esm.dev/ssr/#state-hydration) for pinia in their docs which works perfectly.
Looking at the dev/server.js
, I noticed that the motivation to use such a dedicated file is because these two things
Line 64 in f0a7e02
Line 85 in f0a7e02
I think you can utilize these two hooks to get the same result:
https://vitejs.dev/guide/api-plugin.html#config
https://vitejs.dev/guide/api-plugin.html#configureserver
Have I missed anything else? let me know if I'm wrong.
Hey comunity!
I found myself in weird position where I found something that may be a bug(?) - namely: When this plugin tries to stringify state (in utils/state.js) that is then injected to FE, the JSON.stringify throws and error that theres circular structure.
It throws error like this:
`[SSR] On state serialization - TypeError: Converting circular structure to JSON --> starting at object with constructor 'Object' | property 'something' -> object with constructor 'Object' | property 'something' -> object with constructor 'Object' | ... | property 'something' -> object with constructor 'Array' --- index 0 closes the circle at JSON.stringify () at serializeState (/node_modules/vite-ssr/utils/state.js:32:36) at eval (/node_modules/vite-ssr/vue/entry-server.js:64:36) at runMicrotasks () at processTicksAndRejections (internal/process/task_queues.js:93:5) at async handleSsrRequest (C:\Users\Workgroup-L\Desktop\Work\radixal\mortage\mortgage\FE\node_modules\vite-ssr\dev\server.js:88:31)`
Should it use flatted package or have something like this?
Open to make a PR myself! Thanks.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.