vikejs / vike

🔨 Flexible, lean, community-driven, dependable, fast Vite-based frontend framework.
https://vike.dev
MIT License
4.1k stars 346 forks source link

Empty page assets upgrading from v0.3.64 to v0.4.x #446

Closed npacucci closed 1 year ago

npacucci commented 2 years ago

Description

Hi guys, I'm using this plugin to create a custom engine capable of render (server side) some pages of different web sites (apps) that are later partial hydrated properly depending on the necessities. The JS library I have chosen is SolidJS.

I've been using the v0.3.64 successfully but now trying to upgrade to v0.4.x (currently tested on v0.4.32) I'got some problems with the page assets (also upgraded Vite to v3.1.0).

The problem

I noticed that all the server-side pages returned by the "renderPage" method, have not anymore the links and scripts of the page assets needed to display the page correctly.

Every style imported into the page client entry, the client entry script itself, and also the serialized pageContext are not anymore attached to the page.

🔴 Missing in head

<link rel="stylesheet" type="text/css" href="/assets/Header.491f808b.css">
<link rel="modulepreload" as="script" type="text/javascript" href="/assets/getPage.b45249b9.js">

🔴 Missing in body

<script type="module" src="/assets/apps/app1/pages/home/ home.page.client.tsx.7c3ce049.js"></script>
<script id="vite-plugin-ssr_pageContext" type="application/json">{"pageContext":{"_pageId":"/apps/app1/pages/home/home"}}</script>

Project Structure

I'm following the Domain Driven structure suggested by the documentation, the overall result is something like this:

As you can see, I'm not using _default pages neither Page, and every app page has its own server and client entry points (that's why I'm not using xxx.page.tsx but only xxx.page.server.tsx and xxx.page.client.tsx).

Inside each xxx.page.server.tsx entry point I'm building the page (reusing something like BasePage for header and fonts imports, page utils, ...):

home.page.server.tsx (app1) - v0.3.64 and v0.4.32

import { renderToString } from 'solid-js/web';
import { PageContext } from '../../../../lib/types/page-context.type';
import { htmlPage, initPage } from '../../../../lib/utils/page.utils';
import BasePage from '../BasePage';

export { passToClient };
export { onBeforeRender };
export { render };

const { passToClient, onBeforeRender } = initPage();

const render = async (pageContext: PageContext) => {
  const title: string = 'Home Page';
  const description: string = '';

  const pageHtml = renderToString(() => (
    <BasePage title={title} description={description} pageContext={pageContext}>
      <h1> The App1 Home Page! </h1>
      <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed consequat tempor ex, ac lobortis nulla gravida a. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer aliquam tortor vel semper euismod. Fusce eu ultrices augue. Proin vitae porttitor nibh. Curabitur faucibus consequat mi sed imperdiet. Proin eu enim in eros euismod iaculis. Nulla eget massa ut quam fringilla congue. Nullam egestas mi eros. Mauris sed erat rhoncus, consequat diam et, fringilla nunc. Vestibulum blandit id neque non lobortis. Sed sed placerat leo, a pellentesque nibh. Quisque nec imperdiet diam. </p>
    </BasePage>
  ));

  return htmlPage(pageHtml);
};

page.utils.ts (lib) - v0.3.64 and v0.4.32

import { dangerouslySkipEscape, escapeInject } from 'vite-plugin-ssr';

 // reusing pageContext and hooks - now empty for demo purposes
export const initPage = () => {
  const passToClient: any = [];

  const onBeforeRender = () => {
    return {
      pageContext: {},
    };
  };

  return {
    passToClient,
    onBeforeRender,
  };
};

export const htmlPage = (html: string) => escapeInject`<!DOCTYPE html>
  ${dangerouslySkipEscape(html)}`;

Instead, in the client entry, I'm importing every style needed for that page and I'm doing my custom partial hydration

home.page.client.tsx (app1) - v0.4.32

import '../../styles/main.css'
import '../../components/header/Header.scss'

export { render }

async function render(pageContext: any) {
  console.log(pageContext);
  setTimeout(() => alert('Hi! This is the home page script of the App1 running!'), 1000);

  // custom hydration ...
}

Previously it was:

home.page.client.tsx (app1) - v0.3.64

import { getPage } from 'vite-plugin-ssr/client';
import '../../styles/main.css'
import '../../components/header/Header.scss'

const Main = async () => {
  const pageContext = await getPage<any>();

  console.log(pageContext);
  setTimeout(() => alert('Hi! This is the home page script of the App1 running!'), 1000);

  // custom hydration ...
};

Main();

Finally in the route file, I'm customizing the routing path of each page of every app

home.page.route.ts (app1) - v0.3.64 and v0.4.32 export default '/app1/home';

detail.page.route.ts (app1) - v0.3.64 and v0.4.32 export default '/app1/detail';

home.page.route.ts (app2) - v0.3.64 and v0.4.32 export default '/app2/home';

detail.page.route.ts (app2) - v0.3.64 and v0.4.32 export default '/app2/detail';

Instead my set of dependencies is:

package.json - v0.4.32

{
  "scripts": {
    "dev": "npm run server",
    "prod": "npm run build && npm run server:prod",
    "build": "vite build",
    "server": "ts-node ./server",
    "server:prod": "cross-env NODE_ENV=production ts-node ./server"
  },
  "dependencies": {
    "@types/express": "^4.17.12",
    "@types/node": "^15.12.1",
    "cross-env": "^7.0.3",
    "express": "^4.18.1",
    "moment-timezone": "^0.5.34",
    "solid-js": "~1.4.2",
    "ts-node": "^9.1.1",
    "typescript": "~4.7.2",
    "vite": "~3.1.0",
    "vite-plugin-solid": "~2.3.0",
    "vite-plugin-ssr": "~0.4.32"
  },
  "devDependencies": {
    "sass": "^1.43.2",
    "vite-plugin-checker": "~0.4.9"
  }
}

Previously: package.json - v0.3.64

{
  "scripts": {
    "dev": "npm run server",
    "prod": "npm run build && npm run server:prod",
    "build": "vite build && vite build --ssr",
    "server": "ts-node ./server",
    "server:prod": "cross-env NODE_ENV=production ts-node ./server"
  },
  "dependencies": {
    "@types/express": "^4.17.12",
    "@types/node": "^15.12.1",
    "cross-env": "^7.0.3",
    "express": "^4.18.1",
    "moment-timezone": "^0.5.34",
    "solid-js": "~1.4.2",
    "ts-node": "^9.1.1",
    "typescript": "~4.7.2",
    "vite": "~2.9.9",
    "vite-plugin-solid": "~2.2.6",
    "vite-plugin-ssr": "~0.3.64"
  },
  "devDependencies": {
    "sass": "^1.43.2",
    "vite-plugin-checker": "~0.4.9"
  }
}

I'm also attaching here the prototype of my application so you can directly test it.

ctf-prototype-09-09-2022.zip

I thought it can be a bug of the v0.4.x version since previously it was working very well, but I'm happy to know if I'm missing something :)

This is the compare about the server page returned by the v0.3.64 and v0.4.32:

0.3.x vs 0.4.x.pdf

Let me know if you need more information about this.

Error Stack

No errors during the build and neither at runtime, but the assets are missing in the page returned by the "renderPage" method.
brillout commented 2 years ago

I'll need a minimal reproduction for this.

Closing in the meantime. I'll look into this and re-open once I've a minimal reproduction.

npacucci commented 2 years ago

Sure, to reproduce it you can easily download the .zip file I've attached above and run to the "feature/upgrade-to-04x-version" branch.

Let me know if you need additional information 😃

brillout commented 2 years ago

It's not a minimal reproduction :-).

See https://antfu.me/posts/why-reproductions-are-required and https://gist.github.com/Rich-Harris/88c5fc2ac6dc941b22e7996af05d70ff.

npacucci commented 2 years ago

Sorry for this, I managed now to run the minimal reproduction on Stackblitz:

🔴 The prototype with v0.4.32 https://stackblitz.com/edit/ctf-prototype-v0-4-32?file=README.md

Opening the url above, your application will run under: https://ctf-prototype-v0-4-32--3000.local.webcontainer.io/app1/home (other available routes in README.md)

🔴 As you can see, assets are not available into the page (both in develop and prod mode)

Instead, in the previous version of the plugin it was working very well.

🟢 The prototype with v0.3.64 https://stackblitz.com/edit/ctf-prototype-v0-3-64?file=README.md

Application running under: https://ctf-prototype-v0-3-64--3000.local.webcontainer.io/app1/home

There's no extra-code, just the minimal structure to raise the problem.

Let me know if I can do more than this.

brillout commented 2 years ago

I just released 0.4.33 which has a change about assets which may fix the problem.

Try with 0.4.33 and let me know, or publish the reproduction on GitHub and I'll try myself.

npacucci commented 2 years ago

Just tried the 0.4.33, but is still not working.

This is repro in Stackblitz and GitHub:

https://stackblitz.com/edit/ctf-prototype-v0-4-33?file=README.md

and

https://github.com/npacucci/ctf-prototype-v0-4-33

brillout commented 2 years ago

There is still a lot of code. Can you create a reproduction by doing minimal modifications to example/solid/?

npacucci commented 1 year ago

Ok, I think I've reproduced the same error starting from example/solid-ssr

It seems to be a problem with all the .page.client.tsx pages (not _default), in particular the export { Render } is not working in this scenario and it's also breaking any other .css import (counter style) or .js code (console.log) in the same file.

🔴 Any .css and .js <link> is added to the page.

Instead, if you try to remove export { Render } from the page.client.tsx, the .css import and console.log above will work.

Stackblitz: https://stackblitz.com/edit/solid-ssr-v0-4-34?file=pages/index/index.page.client.tsx

GitHub: https://github.com/npacucci/solid-ssr-v0-4-34

brillout commented 1 year ago

Neat, let me have a look.

brillout commented 1 year ago

Fix released in 0.3.35.

(In case you are curious: vps was wrongfully treating your pages as "HTML-only".)

Let me know if you still run into issues (the heuristic changed quite a lot in 0.4).

Btw. in case you(r company) is interested: https://github.com/sponsors/brillout. Any amount is appreciated :-).

npacucci commented 1 year ago

It works! Nice collaboration, thank you!! 🚀