Coder Social home page Coder Social logo

vikejs / vike Goto Github PK

View Code? Open in Web Editor NEW
3.6K 19.0 319.0 64.46 MB

🔨 Like Next.js / Nuxt but as do-one-thing-do-it-well Vite plugin.

Home Page: https://vike.dev

License: MIT License

TypeScript 86.48% JavaScript 11.09% CSS 0.66% Vue 1.75% MDX 0.02%
vite vite-plugin ssr vite-ssr vue-ssr react-ssr vitejs full-stack node react

vike's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vike's Issues

Internal Failure in `getPreloadTags` when running in production mode

Having trouble putting together a minimal reproduction for this, but the stack is below.

Error: [[email protected]][Internal Failure] You stumbled upon a bug in `vite-plugin-ssr`'s source code (an internal assertion failed). This should definitely not be happening, and you should create a new issue at https://github.com/brillout/vite-plugin-ssr/issues/new that includes this error stack (the error stack is enough to debug this). Or reach out on Discord. A fix will be written promptly.
    at /Users/chrismcc/workspace/ss/node_modules/vite-plugin-ssr/dist/getPreloadTags.node.js:33:22
    at Array.forEach (<anonymous>)
    at Object.getPreloadTags (/Users/chrismcc/workspace/ss/node_modules/vite-plugin-ssr/dist/getPreloadTags.node.js:23:22)
    at renderHtmlDocument (/Users/chrismcc/workspace/ss/node_modules/vite-plugin-ssr/dist/renderPage.node.js:222:53)
    at async renderPageId (/Users/chrismcc/workspace/ss/node_modules/vite-plugin-ssr/dist/renderPage.node.js:116:30)
    at async renderPage (/Users/chrismcc/workspace/ss/node_modules/vite-plugin-ssr/dist/renderPage.node.js:96:24)
    at async Object.<anonymous> (/Users/chrismcc/workspace/ss/server.js:1713:20)

Vite v2.2.3

It's trying to look up the manifest entry for pages/all.page.tsx, which doesn't exist in client or server manifest for some reason, even though the page does + works great in dev mode. It's meant to be a SSR page, I don't have any static or prerendered pages. It's also a catchall, the route is defined as:

export default function () {
  return {
    match: -2
  };
}
Server Manifest
{
  'node_modules/vite-plugin-ssr/page-files/pageFiles.node.ts': {
    file: 'pageFiles.node.js',
    src: 'node_modules/vite-plugin-ssr/page-files/pageFiles.node.ts',
    isEntry: true,
    dynamicImports: [
      'pages/_error.page.tsx',
      '_all.page.97a49683.js',
      'pages/onboard.page.tsx',
      'pages/session.page.tsx',
      'pages/shops.page.tsx',
      'pages/_default/_default.page.client.tsx',
      'pages/all.page.server.ts',
      'pages/onboard.page.server.tsx',
      'pages/session.page.server.tsx',
      'pages/shops.page.server.tsx',
      'pages/_default/_default.page.server.tsx',
      'pages/all.page.route.js',
      'pages/onboard.page.route.js',
      'pages/session.page.route.js',
      'pages/shops.page.route.js'
    ]
  },
  'pages/_error.page.tsx': {
    file: 'assets/_error.page.797e0037.js',
    src: 'pages/_error.page.tsx',
    isDynamicEntry: true,
    imports: [ '_TwoPanelLayout.5aed1da0.js' ]
  },
  '_TwoPanelLayout.5aed1da0.js': {
    file: 'assets/TwoPanelLayout.5aed1da0.js',
    assets: [ 'assets/pattern2x.bb73d710.png' ]
  },
  '_all.page.97a49683.js': {
    file: 'assets/all.page.97a49683.js',
    isDynamicEntry: true,
    imports: [
      '_index.4f9d37b7.js',
      '_use-graphql.4e21b4ca.js',
      '_types.62a059e8.js',
      'pages/_error.page.tsx'
    ],
    dynamicImports: [ 'components/PageEditor.tsx' ]
  },
  '_types.62a059e8.js': { file: 'assets/types.62a059e8.js' },
  '_index.4f9d37b7.js': { file: 'assets/index.4f9d37b7.js' },
  '_use-graphql.4e21b4ca.js': { file: 'assets/use-graphql.4e21b4ca.js' },
  'pages/onboard.page.tsx': {
    file: 'assets/onboard.page.b445335a.js',
    src: 'pages/onboard.page.tsx',
    isDynamicEntry: true,
    imports: [
      '_TwoPanelLayout.5aed1da0.js',
      '_BrandButton.36c3ecbe.js',
      '_graphql.e071fc6a.js',
      '_use-graphql.4e21b4ca.js',
      '_logo.65f94883.js',
      '_enums.f99be063.js',
      '_types.62a059e8.js'
    ],
    assets: [
      'assets/airtablekey900k.534aaf1b.mp4',
      'assets/airtablekey900k.5770f3fb.webm',
      'assets/airtableshare700k.bc2dac47.mp4',
      'assets/airtableshare700k.2685e756.webm',
      'assets/googleoutput700k.cbf09c54.mp4',
      'assets/googleoutput700k.0d8460f6.webm'
    ]
  },
  '_BrandButton.36c3ecbe.js': { file: 'assets/BrandButton.36c3ecbe.js' },
  '_graphql.e071fc6a.js': { file: 'assets/graphql.e071fc6a.js' },
  '_logo.65f94883.js': {
    file: 'assets/logo.65f94883.js',
    assets: [ 'assets/logo.85f87099.svg' ]
  },
  '_enums.f99be063.js': { file: 'assets/enums.f99be063.js' },
  'pages/session.page.tsx': {
    file: 'assets/session.page.32c80824.js',
    src: 'pages/session.page.tsx',
    isDynamicEntry: true,
    imports: [
      '_TwoPanelLayout.5aed1da0.js',
      '_graphql.e071fc6a.js',
      '_use-graphql.4e21b4ca.js',
      '_logo.65f94883.js'
    ]
  },
  'pages/shops.page.tsx': {
    file: 'assets/shops.page.9f3e6ba7.js',
    src: 'pages/shops.page.tsx',
    isDynamicEntry: true,
    imports: [ '_use-graphql.4e21b4ca.js', '_logo.65f94883.js' ]
  },
  'pages/_default/_default.page.client.tsx': {
    file: 'assets/_default.page.client.b5770ade.js',
    src: 'pages/_default/_default.page.client.tsx',
    isDynamicEntry: true
  },
  'pages/all.page.server.ts': {
    file: 'assets/all.page.server.e439a3de.js',
    src: 'pages/all.page.server.ts',
    isDynamicEntry: true,
    imports: [
      '_types.62a059e8.js',
      '_widget-fragment.15763a42.js',
      '_shop.699429dc.js'
    ]
  },
  '_widget-fragment.15763a42.js': { file: 'assets/widget-fragment.15763a42.js' },
  '_shop.699429dc.js': { file: 'assets/shop.699429dc.js' },
  'pages/onboard.page.server.tsx': {
    file: 'assets/onboard.page.server.fcbbdb8b.js',
    src: 'pages/onboard.page.server.tsx',
    isDynamicEntry: true,
    imports: [ '_enums.f99be063.js' ]
  },
  'pages/session.page.server.tsx': {
    file: 'assets/session.page.server.e7258d58.js',
    src: 'pages/session.page.server.tsx',
    isDynamicEntry: true
  },
  'pages/shops.page.server.tsx': {
    file: 'assets/shops.page.server.6f2e1061.js',
    src: 'pages/shops.page.server.tsx',
    isDynamicEntry: true,
    imports: [ '_shop.699429dc.js' ]
  },
  'pages/_default/_default.page.server.tsx': {
    file: 'assets/_default.page.server.09a6d56f.js',
    src: 'pages/_default/_default.page.server.tsx',
    isDynamicEntry: true,
    imports: [
      '_logo.65f94883.js',
      '_BrandButton.36c3ecbe.js',
      '_index.4f9d37b7.js'
    ],
    css: [ 'assets/_default.page.server.704ed2fd.css' ]
  },
  'pages/all.page.route.js': {
    file: 'assets/all.page.route.dc102e33.js',
    src: 'pages/all.page.route.js',
    isDynamicEntry: true
  },
  'pages/onboard.page.route.js': {
    file: 'assets/onboard.page.route.287b457d.js',
    src: 'pages/onboard.page.route.js',
    isDynamicEntry: true
  },
  'pages/session.page.route.js': {
    file: 'assets/session.page.route.cabbba58.js',
    src: 'pages/session.page.route.js',
    isDynamicEntry: true
  },
  'pages/shops.page.route.js': {
    file: 'assets/shops.page.route.e0261f54.js',
    src: 'pages/shops.page.route.js',
    isDynamicEntry: true
  },
  'components/PageEditor.tsx': {
    file: 'assets/PageEditor.9b8afbb3.js',
    src: 'components/PageEditor.tsx',
    isDynamicEntry: true,
    imports: [
      '_all.page.97a49683.js',
      '_use-graphql.4e21b4ca.js',
      '_types.62a059e8.js',
      '_widget-fragment.15763a42.js',
      '_index.4f9d37b7.js',
      'pages/_error.page.tsx',
      '_TwoPanelLayout.5aed1da0.js'
    ]
  }
}
Client Manifest
{
  'pages/_default/_default.page.client.tsx': {
    file: 'assets/pages/_default/_default.page.client.tsx.5bd00183.js',
    src: 'pages/_default/_default.page.client.tsx',
    isEntry: true,
    isDynamicEntry: true,
    imports: [ '_vendor.2ab1f7ad.js' ],
    css: [ 'assets/pages/_default/_default.page.client.tsx.d82a5d3f.css' ]
  },
  '_vendor.2ab1f7ad.js': {
    file: 'assets/vendor.2ab1f7ad.js',
    dynamicImports: [
      'pages/_error.page.tsx',
      '_all.page.15209e07.js',
      'pages/onboard.page.tsx',
      'pages/session.page.tsx',
      'pages/shops.page.tsx',
      'pages/_default/_default.page.client.tsx',
      'pages/all.page.route.js',
      'pages/onboard.page.route.js',
      'pages/session.page.route.js',
      'pages/shops.page.route.js'
    ]
  },
  'pages/_error.page.tsx': {
    file: 'assets/_error.page.a5a13a3d.js',
    src: 'pages/_error.page.tsx',
    isDynamicEntry: true,
    imports: [ '_TwoPanelLayout.2282149a.js', '_vendor.2ab1f7ad.js' ]
  },
  '_TwoPanelLayout.2282149a.js': {
    file: 'assets/TwoPanelLayout.2282149a.js',
    imports: [ '_vendor.2ab1f7ad.js' ],
    assets: [ 'assets/pattern2x.bb73d710.png' ]
  },
  '_all.page.15209e07.js': {
    file: 'assets/all.page.15209e07.js',
    isDynamicEntry: true,
    imports: [
      '_vendor.2ab1f7ad.js',
      'pages/_default/_default.page.client.tsx',
      '_use-graphql.968707a4.js',
      '_types.b4659228.js',
      'pages/_error.page.tsx'
    ],
    dynamicImports: [ 'components/PageEditor.tsx' ]
  },
  '_types.b4659228.js': { file: 'assets/types.b4659228.js' },
  '_use-graphql.968707a4.js': {
    file: 'assets/use-graphql.968707a4.js',
    imports: [ '_vendor.2ab1f7ad.js' ]
  },
  'pages/onboard.page.tsx': {
    file: 'assets/onboard.page.a6f81a5a.js',
    src: 'pages/onboard.page.tsx',
    isDynamicEntry: true,
    imports: [
      '_TwoPanelLayout.2282149a.js',
      'pages/_default/_default.page.client.tsx',
      '_graphql.4e80b5a8.js',
      '_vendor.2ab1f7ad.js',
      '_use-graphql.968707a4.js',
      '_logo.31f1c087.js',
      '_types.b4659228.js'
    ],
    assets: [
      'assets/airtablekey900k.534aaf1b.mp4',
      'assets/airtablekey900k.5770f3fb.webm',
      'assets/airtableshare700k.bc2dac47.mp4',
      'assets/airtableshare700k.2685e756.webm',
      'assets/googleoutput700k.cbf09c54.mp4',
      'assets/googleoutput700k.0d8460f6.webm'
    ]
  },
  '_graphql.4e80b5a8.js': {
    file: 'assets/graphql.4e80b5a8.js',
    imports: [ '_vendor.2ab1f7ad.js' ]
  },
  '_logo.31f1c087.js': {
    file: 'assets/logo.31f1c087.js',
    imports: [ '_vendor.2ab1f7ad.js' ]
  },
  'pages/session.page.tsx': {
    file: 'assets/session.page.205b7aa6.js',
    src: 'pages/session.page.tsx',
    isDynamicEntry: true,
    imports: [
      '_TwoPanelLayout.2282149a.js',
      '_graphql.4e80b5a8.js',
      '_use-graphql.968707a4.js',
      '_logo.31f1c087.js',
      '_vendor.2ab1f7ad.js',
      '_useEffectOnce.9167af87.js'
    ]
  },
  '_useEffectOnce.9167af87.js': {
    file: 'assets/useEffectOnce.9167af87.js',
    imports: [ '_vendor.2ab1f7ad.js' ]
  },
  'pages/shops.page.tsx': {
    file: 'assets/shops.page.9ce44a2b.js',
    src: 'pages/shops.page.tsx',
    isDynamicEntry: true,
    imports: [
      '_use-graphql.968707a4.js',
      '_logo.31f1c087.js',
      '_vendor.2ab1f7ad.js'
    ]
  },
  'pages/all.page.route.js': {
    file: 'assets/all.page.route.56b20769.js',
    src: 'pages/all.page.route.js',
    isDynamicEntry: true
  },
  'pages/onboard.page.route.js': {
    file: 'assets/onboard.page.route.d1d214e5.js',
    src: 'pages/onboard.page.route.js',
    isDynamicEntry: true
  },
  'pages/session.page.route.js': {
    file: 'assets/session.page.route.5daa49cd.js',
    src: 'pages/session.page.route.js',
    isDynamicEntry: true
  },
  'pages/shops.page.route.js': {
    file: 'assets/shops.page.route.6973bf40.js',
    src: 'pages/shops.page.route.js',
    isDynamicEntry: true
  },
  'components/PageEditor.tsx': {
    file: 'assets/PageEditor.df7c5aa1.js',
    src: 'components/PageEditor.tsx',
    isDynamicEntry: true,
    imports: [
      '_all.page.15209e07.js',
      '_vendor.2ab1f7ad.js',
      '_use-graphql.968707a4.js',
      '_useEffectOnce.9167af87.js',
      '_types.b4659228.js',
      'pages/_default/_default.page.client.tsx',
      'pages/_error.page.tsx',
      '_TwoPanelLayout.2282149a.js'
    ]
  }
}

Let me know if you need some additional info to hunt this one down...

@vueuse/head not working properly

Hello
Thanks for this perfect library. It is amazing. I am working on this vue-router example and need to use vueuse/head package to manage titles dynamically but not made work it. Are there any configs etc. about this?

Here are my app.js

import { createSSRApp } from "vue";
import { createRouter } from "./router";
import { createStore } from "../store/store";
import { createHead } from "@vueuse/head";

export { createApp };

function createApp({ Page }) {
  const app = createSSRApp(Page);
  const router = createRouter();
  const store = createStore();
  const head = createHead();
  app.use(store);
  app.use(router);
  app.use(head);
  return { app, router, store, head };
}

all.page.server.js

import { renderToString } from "@vue/server-renderer";
import { html } from "vite-plugin-ssr";
import { createHead, renderHeadToString } from "@vueuse/head";

import { createApp } from "./app";

export { render };
export { addContextProps };
export { setPageProps };

async function render({ contextProps }) {
  const { appHtml } = contextProps;

  const head = createHead();
  const { headTags, htmlAttrs, bodyAttrs } = renderHeadToString(head);

  return html`<!DOCTYPE html>
    <html>
      <head>
        ${html.dangerouslySetHtml(headTags)}
      </head>
      <body>
        <div id="app">${html.dangerouslySetHtml(appHtml)}</div>
      </body>
    </html>`;
}

async function addContextProps({ Page, contextProps }) {
  const { app, store, router } = createApp({ Page });

  await router.push(contextProps.url);
  await router.isReady();
  const appHtml = await renderToString(app);

  const INITIAL_STATE = store.state;

  return {
    INITIAL_STATE,
    appHtml,
  };
}

function setPageProps({ contextProps }) {
  const { INITIAL_STATE } = contextProps;
  return { INITIAL_STATE };
}

About.vue component

<template>
  <p>The count is preserved when switching between "Home" and "About".</p>
</template>

<script setup>
import { useHead } from "@vueuse/head";

useHead({
  title: "My About Page",
});
</script>

I cant see my title in SSR rendered code.

Can't get @vitejs/plugin-legacy working

Me again 😅

I (think) I can't get @vitejs/plugin-legacy working properly, I've set up helmet for express to generate the Content-Security-Policy headers for the script hashes and it's generating the legacy bundles, but I think it's not actually referencing anything in my html not in <head/> nor in <body/>

My vite.config.js plugins looks like this

plugins: [legacy(), reactRefresh(), ssr()],

Also tried different ordering just to make sure.

Do I have to include anything in my _default.page.server.tsx manually?

I guess it's due to vite-plugin-ssr not using Vites static index.html file 🤔

UI Framework

Well done for your work, I really appreciate your effort towards DX.
Is it possible to add a CSS/UI framework of choice?
PrimeVue, ant-design-vue, etc!

client-side navigation with a quote causes internal failure

[Error] Unhandled Promise Rejection: Error: [[email protected]][Internal Failure] You stumbled upon an bug in `vite-plugin-ssr`'s source code (an internal assertion failed). This should definitely not be happening, and you should create a new issue at https://github.com/brillout/vite-plugin-ssr/issues/new that includes this error stack (the error stack is enough to debug this). Or reach out on Discord. A fix will be written promptly.
	(anonymous function) (vite-plugin-ssr_client_router.js:1029)
	asyncFunctionResume
	(anonymous function)
	promiseReactionJobWithoutPromise
	promiseReactionJob

Screenshot 2021-04-25 at 11 01 01@2x

Reproduction is something like:

const searchQuery = '"a"';
navigate(`/?q=${searchQuery}`);

Note changing it to:

navigate(`/?q=${encodeURIComponent(searchQuery)}`);

...works fine, so it may just be a matter of documentation / a better error message.

(this is a minor issue)

Sitemap Generation

Sitemaps are an extremely common need. Basically every application should have one for SEO purposes. Since this plugin is taking on responsibility for rendering out all the routes of an application, I feel like there should be a solution (or at least guidance) facilitating the generation of a sitemap file.

One possibility would be to simply treat a sitemap as any other page file. There may be issues around it showing up as a route alongside "real" application routes though, not sure. Sitemaps are also xml, generally placed at root as sitemap.xml, so I'm not sure if the prerendering logic could currently handle that.

Another option would be to automatically generate sitemaps for users based on their prerender routes. There would need to be some additional configurability in order to facilitate things like i18n, lastmod, etc. This also means users who didn't bother to fill in prerender hooks (perhaps they're just using straight SSR) won't get a sitemap. Otherwise though, it seems like a more user-friendly option.

Thoughts / ideas?

Support ESM

To reproduce

  1. Create the starter Vue app (npm init vite-plugin-ssr)

  2. Change the project type to ESM ("type": "module" in package.json)

  3. Update server.js to use import syntax:

     import express from 'express'
     import { createPageRender } from 'vite-plugin-ssr/dist'
     import vite from 'vite'
  4. Run it (npm run dev)

What should happen

It should run.

What actually happens

internal/process/esm_loader.js:74
    internalBinding('errors').triggerUncaughtException(
                              ^

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /home/aral/small-tech/small-web/sitekit/sandbox/vite-ssr-project/node_modules/vite-plugin-ssr/index.ts
    at Loader.defaultGetFormat [as _getFormat] (internal/modules/esm/get_format.js:71:15)
    at Loader.getFormat (internal/modules/esm/loader.js:102:42)
    at Loader.getModuleJob (internal/modules/esm/loader.js:231:31)
    at async ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:58:21)
    at async Promise.all (index 1)
    at async link (internal/modules/esm/module_job.js:63:9) {
  code: 'ERR_UNKNOWN_FILE_EXTENSION'
}

Use case

My Node server project uses ESM, not CommonJS.

Vue-router with vite-ssr

The problem was when using sсoped styles together with a router-link in one component, I took a ready-made example that was here but it gave an error

file: pages/Home.vue

<template>
  <h1>Home</h1>
  <p>This content is rendered to HTML.</p>
  <router-link to="/lol">Home</router-link>
</template>

<style scoped>
h1 {
  color: green;
}
</style>

Error

Error: Unable to parse {"file":"/","line":4,"column":299}
2  |      <html>
3  |        <body>
4  |          <div id="app"><!--[--><div><a aria-current="page" href="/" class="router-link-active router-link-exact-active">Home</a> | <a href="/about" class="">About</a><!--[--><h1 data-v-7f245110>Home</h1><p data-v-7f245110>This content is rendered to HTML.</p><a href="/lol" class="" data-v-7f245110 data-v-7f245110>Home</a><!--]--></div><div><button>count is: 0</button></div><!--]--></div>
   |
                                                                                     ^
5  |        </body>
6  |      </html>
    at traverseHtml (D:\vite-plugin-ssr-master\vite-plugin-ssr-master\examples\vue-router\node_modules\vite\dist\node\chunks\dep-efe32886.js:23936:15)
    at async devHtmlHook (D:\vite-plugin-ssr-master\vite-plugin-ssr-master\examples\vue-router\node_modules\vite\dist\node\chunks\dep-efe32886.js:59458:5)
    at async applyHtmlTransforms (D:\vite-plugin-ssr-master\vite-plugin-ssr-master\examples\vue-router\node_modules\vite\dist\node\chunks\dep-efe32886.js:24202:21)
    at async applyViteHtmlTransform (D:\vite-plugin-ssr-master\vite-plugin-ssr-master\examples\vue-router\node_modules\vite-plugin-ssr\dist\renderPage.node.js:227:20)
    at async renderPageId (D:\vite-plugin-ssr-master\vite-plugin-ssr-master\examples\vue-router\node_modules\vite-plugin-ssr\dist\renderPage.node.js:114:20)
    at async renderPage (D:\vite-plugin-ssr-master\vite-plugin-ssr-master\examples\vue-router\node_modules\vite-plugin-ssr\dist\renderPage.node.js:63:24)
    at async D:\vite-plugin-ssr-master\vite-plugin-ssr-master\examples\vue-router\server\index.js:28:20
[vite-plugin-ssr][Warning] No `_error.page.js` found. We recommend creating a `_error.page.js` file. (This warning is not shown in production.)

Pages sharing a common word in their identifier cause errors to be thrown

Reproduction Steps:

  1. Create pages with a common word as their identifier, e.g. article.page.vue and articles.page.vue
  2. Attempt to run the server
  3. Observe that an error is thrown indicating a path conflict: Error: [vite-plugin-ssr][Wrong Usage] Conflicting /pages/article.page.vue /pages/articles.page.vue

Expected Results:
I'm guessing this is guarding against some known bad / ambiguous state in the pages configuration, but being able to use plural words seems like fair use and should be supported(?)

Errors encountered during prerender do not exit the process with failure code

Reproduction Steps:

  1. Execute prerender command for a site that throws an error in a used prerender hook, followed by another command e.g. npm run prerender && echo 'hi'
  2. Observe that after the error is thrown and the prerender process fails, the second command is executed.

Expected Results:
Any error encountered during prerender should immediately exit the process via process.exit(1) to prevent operations downstream (e.g. deploying a broken site).

Allow `addContextProps()` to be called on the client-side. (For page transitions that happen 100% in the client and where the server is not invovled at all.)

Currently addContextProps() is defined in .page.server.js and always called in Node.js which is an important invariant for people who use SQL/ORM queries in their addContextProps() functions.

This ticket is about enabling addContextProps() to be called in the browser by defining it in .page.js instead of .page.server.js. It would still always be called in Node.js when rendering a page to HTML, but for any susequent page navigation addContextProps() would be called in the browser (when using useClientRouter()).

Redirect loop when navigating to a 404 with a `#`

Hello again 👋

I'm seeing a fun redirect loop when navigating to a 404 page that has a # in the URL.

Screenshot.2021-04-16.at.18.46.43.mp4

Vite: 2.1.4
vite-plugin-ssr: 0.1.0-beta.32 (also an issue in 0.1.0-beta.31, did not test beyond that)

Reproduction steps:

Checkout example at https://github.com/brillout/vite-plugin-ssr/tree/master/examples/react install & run.
Navigate to a 404 page with a # at the end, like /aaa#.
Notice the page continually loads, and %23 gets added onto the URL over and over again.

Issue upgrading from from 0.1.0-beta.17 to 0.1.0-beta.18

running vite build && vite build --ssr in beta.17 works great, on beta.18 I'm seeing:

yarn build
yarn run v1.22.10
$ vite build && vite build --ssr
vite v2.1.2 building for production...
✓ 739 modules transformed.
dist/client/assets/logo.3cedc8da.svg                                     0.70kb
dist/client/manifest.json                                                1.54kb
dist/client/assets/_error.page.b5099f66.js                               0.34kb / brotli: 0.18kb
dist/client/assets/all.page.92fdd9ff.js                                  0.20kb / brotli: 0.12kb
dist/client/assets/index.page.e794d9eb.js                                0.44kb / brotli: 0.21kb
dist/client/assets/all.page.route.75506379.js                            0.05kb / brotli: 0.05kb
dist/client/assets/signup.page.route.774ca72d.js                         0.08kb / brotli: 0.08kb
dist/client/assets/signup.page.993c3da0.js                               29.28kb / brotli: 9.13kb
dist/client/assets/pages/_default/_default.page.client.tsx.cc6ca426.js   243.40kb / brotli: 67.29kb
vite v2.1.2 building SSR bundle for production...
 > node_modules/vite/dist/node/chunks/dep-efe32886.js:31549:7: error: [vite:dep-scan] No known conditions for "." entry in "vite-plugin-ssr" package
    31549 │   throw new Error(
          ╵         ^
    at bail (/Users/chrismcc/workspace/ss/node_modules/vite/dist/node/chunks/dep-efe32886.js:31549:8)
    at resolve$1 (/Users/chrismcc/workspace/ss/node_modules/vite/dist/node/chunks/dep-efe32886.js:31605:32)
    at resolveExports (/Users/chrismcc/workspace/ss/node_modules/vite/dist/node/chunks/dep-efe32886.js:32022:12)
    at resolvePackageEntry (/Users/chrismcc/workspace/ss/node_modules/vite/dist/node/chunks/dep-efe32886.js:31950:22)
    at tryNodeResolve (/Users/chrismcc/workspace/ss/node_modules/vite/dist/node/chunks/dep-efe32886.js:31847:11)
    at Context.resolveId (/Users/chrismcc/workspace/ss/node_modules/vite/dist/node/chunks/dep-efe32886.js:31730:28)
    at Object.resolveId (/Users/chrismcc/workspace/ss/node_modules/vite/dist/node/chunks/dep-efe32886.js:43592:55)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async resolve (/Users/chrismcc/workspace/ss/node_modules/vite/dist/node/chunks/dep-efe32886.js:43786:26)
    at async /Users/chrismcc/workspace/ss/node_modules/vite/dist/node/chunks/dep-efe32886.js:43871:34

   node_modules/vite/dist/node/chunks/dep-efe32886.js:43861:18: note: This error came from the "onResolve" callback registered here
    43861 │             build.onResolve({
          ╵                   ~~~~~~~~~
    at setup (/Users/chrismcc/workspace/ss/node_modules/vite/dist/node/chunks/dep-efe32886.js:43861:19)
    at handlePlugins (/Users/chrismcc/workspace/ss/node_modules/esbuild/lib/main.js:686:7)
    at Object.buildOrServe (/Users/chrismcc/workspace/ss/node_modules/esbuild/lib/main.js:903:44)
    at /Users/chrismcc/workspace/ss/node_modules/esbuild/lib/main.js:1436:17
    at new Promise (<anonymous>)
    at Object.build (/Users/chrismcc/workspace/ss/node_modules/esbuild/lib/main.js:1435:14)
    at Object.build (/Users/chrismcc/workspace/ss/node_modules/esbuild/lib/main.js:1326:51)
    at /Users/chrismcc/workspace/ss/node_modules/vite/dist/node/chunks/dep-efe32886.js:43740:54
    at Array.map (<anonymous>)

   pages/_default/_default.page.server.tsx:6:21: note: The plugin "vite:dep-scan" was triggered by this import
        6 │ import { html } from 'vite-plugin-ssr';
          ╵                      ~~~~~~~~~~~~~~~~~

error during build:
Error: Build failed with 1 error:
node_modules/vite/dist/node/chunks/dep-efe32886.js:31549:7: error: [vite:dep-scan] No known conditions for "." entry in "vite-plugin-ssr" package
    at failureErrorWithLog (/Users/chrismcc/workspace/ss/node_modules/esbuild/lib/main.js:1216:15)
    at buildResponseToResult (/Users/chrismcc/workspace/ss/node_modules/esbuild/lib/main.js:936:32)
    at /Users/chrismcc/workspace/ss/node_modules/esbuild/lib/main.js:1035:20
    at /Users/chrismcc/workspace/ss/node_modules/esbuild/lib/main.js:568:9
    at handleIncomingPacket (/Users/chrismcc/workspace/ss/node_modules/esbuild/lib/main.js:657:9)
    at Socket.readFromStdout (/Users/chrismcc/workspace/ss/node_modules/esbuild/lib/main.js:535:7)
    at Socket.emit (events.js:315:20)
    at addChunk (internal/streams/readable.js:309:12)
    at readableAddChunk (internal/streams/readable.js:284:9)
    at Socket.Readable.push (internal/streams/readable.js:223:10)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Seems like it may stem from this change: 4cfe4ef#diff-cc5a2f170768969f124108ad3be7fdbcbed774c11774d99a87a3a78fef4ab97bR24

Support Cloudflare Workers

In principle, vite-pluign-ssr can be used with Cloudflare Workers; there are no hard dependencies on Node.js APIs.

If I remember correctly, a Cloudlare Worker is defined as a single JS file, which means that the entire runtime needs to be bundled in a single file. Super neat would be a vite-plugin-cloudflare that does this and which is compatible with vite-plugin-ssr.

cc @schickling

Deep Integration with Vue Router

The docs indicate that this plugin can be used with Vue Router for client-side routing, but does not go into any more detail. Is an example planned for this integration? Curious to see how one might get the file-based routing information into Vue Router routes.

Built in Vite env vars seem incorrect in prerender hook

Repro Steps:

  1. Add a console.log of import.meta.env from inside a page's prerender hook
  2. Run prerender process, e.g. cross-env NODE_ENV=production && npm run build && vite-plugin-ssr prerender --clientRouter
  3. Observe that logged env indicates the following:
MODE: 'production'
DEV: true
PROD: false

Expected Results:
Having specified NODE_ENV=production, I would expect DEV=false, PROD=true. Additionally, I would expect SSR=true to come through, but it is not showing up at all.

How can I map parameterized route in homepage?

Hello People,

I'm trying to create blog on this tool with vue, but I don't know how to map /posts/:post in homepage? my setup: WindiCSS, Markdown, Vue (without TS) and of course vite-plugin-ssr. Is it possible to do this using tools I have?

If you don't understand something, please write, then I will describe this.

Thank You

Getting Stuck with Apollo

Dear @brillout,

Thank you for this plugin, it looks very promising.

update: seems to be working perfectly now!

If you have time, would you mind creating a very basic example using apollo client? I am probably doing something stupid but I don't think I can figure it out on my own.

// apollo/index.ts
import 'cross-fetch/polyfill';
import { ApolloClient } from '@apollo/client'
import { InvalidationPolicyCache } from 'apollo-invalidation-policies';

export const client = new ApolloClient({
  cache: new InvalidationPolicyCache({}),
  uri: 'https://countries.trevorblades.com'
})
// pages/tests/index.page.server.ts
import { gql } from '@apollo/client'
import {client} from '../../apollo'

export { addContextProps }
export { setPageProps }

export const LIST_COUNTRIES = gql`
  {
    countries {
      name
      code
    }
  }
`;

async function addContextProps({ contextProps }) {
  const response = await client.query({query: LIST_COUNTRIES})

  return { countries: response.data.countries }
}

function setPageProps({ contextProps: { countries } }) {
  return { countries }
}
// pages/tests/index.page.tsx
import React from "react";
import { useQuery } from '@apollo/client'
import "./index.css";
import {client} from '../../apollo'
import {LIST_COUNTRIES} from './index.page.server'

export { Page };

function Page({countries}) {
  const {data} = useQuery(LIST_COUNTRIES, {client});
  console.log('countries', countries) // This is not working
  console.log('data', data) // This works 
  return (
    <>
      <h1>TEsts</h1>
      <p>A okay text.</p>
    </>
  );
}

Thank you very much,

Lydia

Add unit tests

As discussed in #24, the project has e2e tests, but granular unit tests are still on the todo list.

Prerender fails when Vite build.assetsDir option is specified

Steps to Reproduce:

  1. add build.assetsDir option to vite.config.js with any path other than the default "assets"
  2. run vite build followed by prerender command
  3. Observe that an error is thrown originating in collectAssets in /dist/getPreloadTags.node.js

Expected Results:

Customizing the assetsDir should successfully prerender the site into the customized directory

"Something unexpected happened" when navigating to a url that ends in `#`

It seems like any URL ending in # will easily trigger this error if you useClientRouter, like http://localhost:3000/signup#. Don't see any negative impact really, just saw the console message and figured I'd let ya know!

I'm on v0.1.0-beta.26, vite 2.1.4.

Uncaught (in promise) Error: [vite-plugin-ssr][Internal Error] Something unexpected happened. Please open a new issue at https://github.com/brillout/vite-plugin-ssr/issues/new and include this error stack.
    at newError2 (newError.ts:18)
    at assert (assert.ts:20)
    at getUrl (getUrl.client.ts:13)
    at fetchAndRender (useClientRouter.client.ts:78)
    at useClientRouter.client.ts:55
    at useClientRouter.client.ts:219

Single File Page. (Being able to define everything in a single file `.page.js`.)

Instead of having several page files (.page.js, .page.route.js, .page.server.js, .page.client.js), we would define everything in .page.js (while vite-plugin-ssr automatically statically extracts the relevant parts like in https://next-code-elimination.vercel.app.)

Many people have expressed a longing for this, but I'm on the fence. Simply because I highly value clarity and simplicity: it's obvious and simple what the .page.js, .page.route.js, .page.server.js, and .page.client.js files are about, whereas if we merge everything in .page.js it becomes less clear what is run in what environment.

How to redirect + `useClientRouter` ?

As far as I can tell, the render function isn't called during client-side routing, so the current way to redirect outlined in the Readme doesn't seem to work when also using client-side routing. I tried using navigate, which worked well for client-side, but errors out when accessing the URL directly because navigate cannot be called on the server (see also #21). Is there a universal way to use client-side routing + redirects?

I could do something like this but it feels tacky:

// movie.page.server.js
export { render }

function render({ contextProps }) {
  if (contextProps.movieId === null) {
    return { redirectTo: '/movie/add' }
  }
}

// movie.page.js
import { navigate } from "vite-plugin-ssr/client/router";

export { Page };

const Page = ({ movieId }) => {
  if (typeof window !== 'undefined' && movieId === null) {
    navigate('/movie/add');
  }

  return ...;
};

Thanks in advance!

Having `tsconfig.server.json` crashes SSR

I have a seperate tsconfig for code in server/ called tsconfig.server.json.

This crashes the SSR.

    err: {
      "type": "Error",
      "message": "[vite-plugin-ssr][Wrong Usage] The file /tsconfig.server.json should be name `*.page.server.*`. Add the missing `.page`.",
      "stack":
          Error: [vite-plugin-ssr][Wrong Usage] The file /tsconfig.server.json should be name `*.page.server.*`. Add the missing `.page`.
              at /Users/moeriki/Projects/flex-template/node_modules/vite-plugin-ssr/user-files/getUserFiles.shared.ts:66:7
              at Array.forEach (<anonymous>)
              at /Users/moeriki/Projects/flex-template/node_modules/vite-plugin-ssr/user-files/getUserFiles.shared.ts:64:46
              at Array.forEach (<anonymous>)
              at assertExtensions (/Users/moeriki/Projects/flex-template/node_modules/vite-plugin-ssr/user-files/getUserFiles.shared.ts:59:34)
              at Object.getUserFiles (/Users/moeriki/Projects/flex-template/node_modules/vite-plugin-ssr/user-files/getUserFiles.shared.ts:20:3)
              at getPageIds (/Users/moeriki/Projects/flex-template/node_modules/vite-plugin-ssr/route.node.ts:141:21)
              at Object.route (/Users/moeriki/Projects/flex-template/node_modules/vite-plugin-ssr/route.node.ts:24:22)
              at render (/Users/moeriki/Projects/flex-template/node_modules/vite-plugin-ssr/render.node.ts:29:22)
    }

Work around

Renamed tsconfig.server.json to tsconfig.backend.json.

Let me know if I should PR. 💛

Can't get WindiCSS working

Hey there, your plugin looks very promising, thanks a lot for your efforts 🙏
I'm completely new to vite, worked only with Gatsby and Next so far with Tailwind.

I tried WindiCSS in a "raw" Vite scaffold (using the CLI) then installing Windi according to the vite-plugin-windicss docs which worked just as expected.

Trying to do replicate this in my beforehand scaffolded vite-plugin-ssr project using the CLI failed to import the CSS styles (only the custom properties --tw-* are included in the final build .css).

I've put the import "virtual:windi.css"; "everywhere" starting in _default.page.client.tsx than added to index.page.tsx without any changes.

Uh I'm also using useClientRouter in _default.page.client.tsx.

What am I missing or doing wrong?

Using a different "base" in vite.config.js

I would like to use prerender function with a different base set in vite.config.json. Prerendering works except the paths to the rendered css/js/asset files is nog pre-pended with the base.

Example result with a base set to /tests/vite/:

<!DOCTYPE html>
<html lang="en">
  <head>
    <link rel="icon" href="/tests/vite/assets/logo.bebe2e90.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite App</title>
    <link rel="modulepreload" crossorigin href="/assets/pages/_default/_default.page.client.ts.e43e8364.js">
    <link rel="stylesheet" href="/assets/pages/_default/_default.page.client.ts.824b1405.css">
    <link rel="preload" href="/assets/logo.bebe2e90.svg">
  </head>
  <body>
    <div id="app">
      <div class="layout" data-v-0d0df46e>
        <div class="navigation" data-v-0d0df46e><a href="/" class="logo" data-v-0d0df46e><img src="/tests/vite/assets/logo.bebe2e90.svg" height="64" width="64" data-v-0d0df46e></a><a href="/" data-v-0d0df46e>Home</a><a href="/about" data-v-0d0df46e>About</a><a href="/star-wars" data-v-0d0df46e>Star Wars</a></div>
        <div class="content" data-v-0d0df46e>
          <!--[--><!--[-->
          <h1>Star Wars Movies</h1>
          <ol>
            <!--[-->
            <li><a href="/star-wars/1">A New Hope</a> (1977-05-25) </li>
            <li><a href="/star-wars/2">The Empire Strikes Back</a> (1980-05-17) </li>
            <li><a href="/star-wars/3">Return of the Jedi</a> (1983-05-25) </li>
            <li><a href="/star-wars/4">The Phantom Menace</a> (1999-05-19) </li>
            <li><a href="/star-wars/5">Attack of the Clones</a> (2002-05-16) </li>
            <li><a href="/star-wars/6">Revenge of the Sith</a> (2005-05-19) </li>
            <!--]-->
          </ol>
          <p> Source: <a href="https://swapi.dev/api/films/">swapi.dev/api/films/</a>. </p>
          <p> Data can be fetched by using <code>addContextProps</code> and <code>setPageProps</code>. </p>
          <!--]--><!--]-->
        </div>
      </div>
    </div>
    <script>window.__vite_plugin_ssr = {pageId: "\u002Fpages\u002Fstar-wars\u002Findex", pageProps: {movies:[{title:"A New Hope",release_date:"1977-05-25",id:"1"},{title:"The Empire Strikes Back",release_date:"1980-05-17",id:"2"},{title:"Return of the Jedi",release_date:"1983-05-25",id:"3"},{title:"The Phantom Menace",release_date:"1999-05-19",id:"4"},{title:"Attack of the Clones",release_date:"2002-05-16",id:"5"},{title:"Revenge of the Sith",release_date:"2005-05-19",id:"6"}],docTitle:"6 Star Wars Movies"}}</script><script type="module" src="/assets/pages/_default/_default.page.client.ts.e43e8364.js"></script>
  </body>
</html>

As you can see only the svg is using the correct path.

Thanks for the great plugin!

Getting "TypeError: __getAllUserFiles is not a function" when running production server

Hi there,

When I run yarn server:prod the server starts fine (I see the server running at http://localhost:3000 message) but, when I try to make a request from the browser I get an error message in the console and the browser never receives a response.

The dev server (yarn dev) does not have this problem.

I followed the "Manual Installation" section of the README for React + TypeScript so it's possible I missed something but, as far as I can tell, what I have is the same as the react-typescript boilerplate.

Error message:

(node:27112) UnhandledPromiseRejectionWarning: TypeError: __getAllUserFiles is not a function
    at Object.getAllUserFiles (.../node_modules/vite-plugin-ssr/user-files/infra.node.ts:13:10)
    at Object.getUserFiles (.../node_modules/vite-plugin-ssr/user-files/getUserFiles.shared.ts:18:38)
    at Object.getPageIds (.../node_modules/vite-plugin-ssr/route.node.ts:166:21)
    at renderPage (.../node_modules/vite-plugin-ssr/renderPage.node.ts:48:22)
    at .../index.ts:25:20

package.json script:

"scripts": {
    // ...
    "server:prod": "cross-env NODE_ENV=production ts-node ./server",
},

server/index.ts:

import express from 'express'
import { createPageRender } from 'vite-plugin-ssr'
import * as vite from 'vite'

const isProduction = process.env.NODE_ENV === 'production'
const root = `${__dirname}/..`

async function startServer() {
  const app = express()

  let viteDevServer: vite.ViteDevServer | undefined

  if (isProduction) {
    app.use(express.static(`${root}/dist/client`, { index: false }))
  } else {
    viteDevServer = await vite.createServer({ root, server: { middlewareMode: true }})
    app.use(viteDevServer.middlewares)
  }

  const renderPage = createPageRender({ viteDevServer, isProduction, root })

  app.get('*', async (req, res, next) => {
    const url = req.originalUrl
    const contextProps = {}
    const result = await renderPage({ url, contextProps })
    if (result.nothingRendered) return next()
    res.status(result.statusCode).send(result.renderResult)
  })

  const port = 3000
  app.listen(port, () => {
    console.log(`🚀 server running at http://localhost:${port}`)
  })
}

startServer()

Any help would be appreciated. Thanks in advance.

Issues with ESM module import syntax and endless loop during load in SSR

JSDB is a 100% JavaScript database. The latest version is written in ESM. Simply importing it causes errors that do not otherwise exist in other contexts.

To reproduce

  1. Create an instance of the vite-plugin-ssr vue starter app:
npm init vite-plugin-ssr
  1. Install JSDB:
npm i @small-tech/jsdb
  1. Add the following line to pages/_default.page.server.js:
import JSDB from '@small-tech/jsdb'

What should happen

There should not be any errors.

What actually happens

Initially, you get the following error:

Error: Failed to resolve import "fs/promises" from "pages/_default/_default.page.server.js". Does the file exist?
    at formatError (/home/aral/small-tech/small-web/sitekit/sandbox/vite-ssr-project/node_modules/vite/dist/node/chunks/dep-2c03f3f9.js:43582:46)

This is because the JSTable.js file in JSDB has the following import:

import fsPromises from 'fs/promises'

I don’t know if this is an issue with vite-plugin-ssr or vite itself. The workaround is to change the import to:

import fs from 'fs'
const fsPromises = fs.promises

Needless to say, while I can do this in a module I control, this would mean I’d have to update all third-party modules that might use these sorts of imports in the future to make them compatible.

Once that error is out of the way, you get several related errors:

1:53:15 PM [vite] error while updating dependencies:
Error: Build failed with 3 errors:
node_modules/@small-tech/jsdb/lib/JSTable.js:26:9: error: No matching export in "browser-external:perf_hooks" for import "performance"
node_modules/@small-tech/jsdb/lib/Time.js:15:9: error: No matching export in "browser-external:perf_hooks" for import "performance"
node_modules/@small-tech/jsdb/lib/Util.js:15:9: error: No matching export in "browser-external:util" for import "types"
    at failureErrorWithLog (/home/aral/small-tech/small-web/sitekit/sandbox/vite-ssr-project/node_modules/esbuild/lib/main.js:1224:15)
    at buildResponseToResult (/home/aral/small-tech/small-web/sitekit/sandbox/vite-ssr-project/node_modules/esbuild/lib/main.js:936:32)
    at /home/aral/small-tech/small-web/sitekit/sandbox/vite-ssr-project/node_modules/esbuild/lib/main.js:1035:20
    at /home/aral/small-tech/small-web/sitekit/sandbox/vite-ssr-project/node_modules/esbuild/lib/main.js:568:9
    at handleIncomingPacket (/home/aral/small-tech/small-web/sitekit/sandbox/vite-ssr-project/node_modules/esbuild/lib/main.js:657:9)
    at Socket.readFromStdout (/home/aral/small-tech/small-web/sitekit/sandbox/vite-ssr-project/node_modules/esbuild/lib/main.js:535:7)
    at Socket.emit (events.js:315:20)
    at addChunk (internal/streams/readable.js:309:12)
    at readableAddChunk (internal/streams/readable.js:284:9)
    at Socket.Readable.push (internal/streams/readable.js:223:10)

This time it’s clearly an issue with esbuild. The previous error did not have the same stack trace but it might also be with vite’s use of esbuild. (If this is unreleated to vite-plugin-ssr, I’ll open separate issues on vite and/or esbuild.)

(Although I don’t think it’s esbuild as I bundle Place using esbuild and it imports JSDB without issues. And I just tried it with esbuild 0.9.3 – the same version used here – also and it worked without issues.)

Again, the fix is to rewrite the imports:

So import { performance } from 'perf_hooks' becomes:

import perfHooks from 'perf_hooks'
const performance = perfHooks.performance

etc.

Once those changes have been made, I no longer get errors but loading the index page causes the browser to enter an infinite loading loop with no warnings or errors either in the browser or on the console.

I’m opening the issue here as I have a straightforward way of reproducing the error and want to document it somewhere.

If this is an issue with vite and/or esbuild (which seems likely) and not due to anything vite-plugin-ssr is doing specifically, I’ll open issues on the vite and/or esbuild trackers to point to this one.

System details

  • Node: 14.16.0
  • Vite: 2.2.4
  • Esbuild (via Vite): 0.9.3
  • vite-plugin-ssr: 0.1.0-beta.40
  • JSDB: 2.0.2

Dealing With Circular Dependencies

Dear @brillout,

We are encountering circular dependencies when using recursive functions. I was wondering if this is something to do with vite & ssr, or whether it was perhaps your package. I thought it might be just vite & ssr because there is an issue about it, but I thought it might be your package as all the circular dependencies begin with this: /Users/home1/code/lt/csvite/node_modules/vite-plugin-ssr/user-files/infra.node.vite-entry.ts -> /src/pages/tests/index.page.tsx -> ...

I tried putting this in vite.config.ts, but it didn't do anything.

build: {
    rollupOptions: {
      onwarn(warning, rollupWarn) {
        if (warning.code !== 'CIRCULAR_DEPENDENCY') {
          rollupWarn(warning)
        }
      },
    },
  },

Thank you (again!) for any pointers and apologies if this is nothing to do with vite-plugin-ssr!

Unnecessary contextProps fetch with `#` in URL, and incorrect routing via function

You can just call me the # guy...

Vite 2.1.4
vite-plugin-ssr 0.1.0-beta.33 (really appreciate all the previous fixes, library is looking really good!)

Two things I'm seeing:

  1. On vite-plugin-ssr/examples/react, isOriginalUrl is returning false when navigating to /#, which leads to a fetch of /index.contextProps.json, because /# !== /. I believe this is an unnecessary and not expected fetch. https://github.com/brillout/vite-plugin-ssr/blob/a91ffcae2d8fc525202855887b7b409b752de328/src/client/navigationState.client.ts#L16-L18

  2. Somewhat related as I think this would be resolved if 1 is resolved, but might be a different underlying issue. On vite-plugin-ssr/examples/react, define a file index.page.route.js that contains:

export default function ({ contextProps }) {
  if (contextProps.url === "/") {
    return {
      match: -1
    };
  }
  return { match: false };
}

Loading the index with a hash at the end, /#, you'll see it correctly SSRs, but during hydration it is actually matching and hydrating the error page and not the index page, which leads to a hydration error as the html doesn't match. I believe this is because contextProps aren't being passed to the route function during the client side routing.

require is not defined error when using cjs dependency in page server files

Reproduction Steps

  1. Ensure using vite-plugin-ssr@version 0.1.0-beta.21 with [email protected]
  2. import any cjs dependency using require statements into a *.page.server.js file. E.g.:
// my-page.page.server.js
import { foo } from './bar';

export async function addContextProps() {}
export function setPageProps() {}

// bar.js
const baz = require('./baz')
exports.foo = baz

// baz.js
module.exports = 'foo';
  1. Run dev server and visit page
  2. Observe that Vite throws an error:
[vite] Error when evaluating SSR module /pages/bar.js:
  ReferenceError: require is not defined

Expected Results:
Commonjs dependencies should be transpiled to ES per Vite documentation and supported without throwing errors.

Notes:

How to pass active url into template component

Hi, at first thanks for your job!
But I have some question about pass some routing props into components to render active link or etc.

As example, I have a navigation component with set of links, and one of link need to have an active class.

Via Vue-Router I have a global props $router or $route.path into templates scope, but I don't know how to do that with your tool.

<a  :class="{active: $route.path === href }" ></a>

Pre-rendered site serves some routes as generic index

As an example, my generated site yields:

index.html
news.html
/news
  news-article-1.html

When I point a basic HTTP server at the generated files, /news/ resolves to a generic HTML index of the /news directory. This is because the news directory takes precedence over the news.html file, so news.html is ignored and there is no /news/index.html so it uses a generic index.

My suggestion would be to just name all HTML files index.html in directories with their identifiers. This should lead to more predictable routing.

Route params in ssr

Forgive me for opening a new problem, but I did not understand how it is possible to get on the server in the lower levels of components where I will call ServerPrefetch () and receive data in Vieks and transfer data from the router there.
Example:

<script>
import { mapState, mapActions } from 'vuex'

export default {
  name: 'SearchBar',
  serverPrefetch() {
    return this.getSearch()
  },
  mounted() {
    if(!this.searchLocation && !this.searchCategory)
        this.getSearch()
  },
  computed: {
    ...mapState('application', ['viewPort', 'categories']),
    ...mapState('search', ['searchCategory', 'searchLocation', 'searchLoading'])
  },
  methods: {
    ...mapActions('search', ['setSearch']),
    getSearch() {
      if(this.$route && this.$route.params && (!this.searchCategory || !this.searchLocation))
        return this.setSearch({
          location: this.$route.params.location ? this.$route.params.location : null,
          category: this.$route.params.category ? this.$route.params.category : null
        })
      else return null
    },
    toSearch() {
      window.location.href = `/search/${
        this.searchLocation && this.searchLocation.nameEnLowercase
          ? this.searchLocation.nameEnLowercase : 'all_cities'
      }/${
        this.searchCategory && this.searchCategory.translit
          ? this.searchCategory.translit : 'all_categories'
      }`
    }
  }
}
</script>

I see route params in *.page.server.js contextProps.url but how I can recive this parameters in components in serverPrefetch()

Expose open file limit option for prerender command

With very large sites, it is possible that the prerender process will fail with an EMFILE, too many open files error. Currently this can be mitigated only be editing os configuration to increase open file limit. If we exposed an option for configuring the max number of open files, users would have more control over this issue, making the plugin more scalable.

Suggestion: global addContextProps hook

I have a need for global data that is available to all pages. I am aware that this is possible within the server entrypoint of the application, however that is not a perfect solution in all cases for the following reasons:

  • The server file entrypoint is not a module context, so does not have access to env variables via import.meta.env. One could maybe run dotenv.config to get around this, but it feels inconsistent and hacky to be accessing env vars in two different ways
  • Since the server entrypoint is not processed by Vite, it complains when attempting to import files using ES module syntax. This can lead to inconsistencies, confusion around which files can / are supposed to be used where.
  • Data populated in the server entrypoint is not available in prerender hooks. This means any logic used here to populate the initial contextProps needs to be replicated in prerender hooks.

I am proposing the addition of API that would allow for global additions to context props covering all of these areas. I don't have a specific API in mind yet, just opening the discussion as I see a need here.

Vite version out of date

What is the plan for getting Vite up to date? We're currently pinned to 2.1.4, 2.1.5 has been out for a while and 2.2.1 just dropped. Also what is the deal with vite-fix-2390? We expect that to go away eventually?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.