preactjs / preset-vite

Preset for using Preact with the vite bundler
https://npm.im/@preact/preset-vite
MIT License
262 stars 26 forks source link

Prerendering incompatible with Vite 5.3 (5.2 is fine) #125

Closed mwszekely closed 5 months ago

mwszekely commented 5 months ago

Essentially, a new project created via npm init preact will error, but running npm install vite@~5.2 immediately after fixes it.

Steps to reproduce:

  1. npm init preact
  2. Select SSG along with any other options.
  3. Enter the new directory
  4. npm run build. The following error occurs:
error during build:
[preact:prerender] __VITE_PRELOAD__ is not defined
    at Qe (file:///*/test-site/node_modules/.pnpm/@preact+preset-vite@2.8.2_@babel+core@7.24.7_preact@10.22.0_vite@5.3.1/node_modules/@preact/preset-vite/headless-prerender/index-DcTxemPl.js:1:15974)
    at _t (file:///*/test-site/node_modules/.pnpm/@preact+preset-vite@2.8.2_@babel+core@7.24.7_preact@10.22.0_vite@5.3.1/node_modules/@preact/preset-vite/headless-prerender/index-DcTxemPl.js:1:19199)
    at Object.generateBundle (file:///*/test-site/node_modules/.pnpm/@preact+preset-vite@2.8.2_@babel+core@7.24.7_preact@10.22.0_vite@5.3.1/node_modules/@preact/preset-vite/dist/esm/prerender.mjs:239:38)
    at async Bundle.generate (file:///*/test-site/node_modules/.pnpm/rollup@4.18.0/node_modules/rollup/dist/es/shared/node-entry.js:18153:9)       
    at async file:///*/test-site/node_modules/.pnpm/rollup@4.18.0/node_modules/rollup/dist/es/shared/node-entry.js:20692:27
    at async catchUnfinishedHookActions (file:///*/test-site/node_modules/.pnpm/rollup@4.18.0/node_modules/rollup/dist/es/shared/node-entry.js:20119:16)
    at async build (file:///*/test-site/node_modules/.pnpm/vite@5.3.1/node_modules/vite/dist/node/chunks/dep-BcXSligG.js:65670:16)
    at async CAC.<anonymous> (file:///*/test-site/node_modules/.pnpm/vite@5.3.1/node_modules/vite/dist/node/cli.js:828:5)
  1. Reverting to an earlier version of Vite builds successfully:
    npm install vite@~5.2
    npm run build

Thank you for any time taken to look into it!

rschristian commented 5 months ago

Ah, cheers. Vite must've altered their preloader.

Will need to take some time to figure out how to disable it.

Quick hack, if you need to use 5.3: add globalThis.__VITE_PRELOAD__ = [] to your config file.

tkpte commented 5 months ago

Hey @rschristian, how would you add it to vite.config.js? I tried the following:

import { defineConfig } from 'vite';
import preact from '@preact/preset-vite';

export default defineConfig({
  plugins: [
    preact({ prerender: { enabled: true, renderTarget: '#app', additionalPrerenderRoutes: [ '/404' ] } })
  ],
  resolve: {
    alias: { 'src': '/src' }
  },
  define: {
    __VITE_PRELOAD__: JSON.stringify('[]'),
    // __VITE_PRELOAD__: JSON.stringify([]),
    // __VITE_PRELOAD__: '[]',
    // __VITE_PRELOAD__: [],
    // and all the above using an env var
    // __VITE_PRELOAD__: JSON.stringify(process.env.VITE_PRELOAD_VALUE), 
  },
});

I tried all possible combinations of versions of preact + preact-iso + @preact/preset-vite + vite, but the error error during build: [preact:prerender] __VITE_PRELOAD__ is not defined is there 9 times out of 10.

Sometimes, after a fresh npm install, it just works. However, if i delete node_modules, package-lock.json, empty cache, run npm install, and npm run build, it usually doesn't work anymore.

Hope it's just that my __VITE_PRELOAD__ config is wrong... I would be very grateful if someone could point me in the right direction!

rschristian commented 5 months ago

This will work:

import { defineConfig } from 'vite';
import preact from '@preact/preset-vite';

globalThis.__VITE_PRELOAD__ = []

export default defineConfig({
  plugins: [
    preact({ prerender: { enabled: true, renderTarget: '#app', additionalPrerenderRoutes: [ '/404' ] } })
  ],
});

This is a temporary hack of course, but I don't have time at the moment to address this.

tkpte commented 5 months ago

Works great! As long as the build output is the same, makes no difference to me. Thanks a lot!

rschristian commented 5 months ago

The HTML build output would be the same, JS definitely not. Their preloader is seemingly falling over, that hack I provide is filling in for the lack of a preload asset array (which means the preloader won't actually do anything).

I was totally wrong, not quite sure what they're doing but this works effectively w/out any change in build output. I was mistakenly looking at an intermediary representation.