Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing the output path parameter 'base' failed to build successfully? #80

Open
jedchang opened this issue Oct 16, 2023 · 8 comments
Open

Comments

@jedchang
Copy link

Hi,
When I change the output path parameter base, an error occurs during the build process

2023-10-16_11-27-37

@Tofandel
Copy link
Owner

Did you try to prepend /demo/ to the routes to render?

@jedchang
Copy link
Author

I'm not quite sure how to add it before the route to be rendered?
how to use

@Tofandel
Copy link
Owner

Just routes: ['/demo/', '/demo/about']

@faerics
Copy link

faerics commented Oct 9, 2024

This is not enough to work, because:

  • Assets in a bundle (like assets/index-Bx8wvD0a.js) are behind the base path, too, and the server simply wont serve them
  • There can be public assets (like locales in my case) that are not in a bundle at all, and they are behind the base path, too.

I managed to find a workaround at least for my case, Let's assume that base path is env.BASE_URL. Then, firstly, we define the following:

// We're behind the proxy. Thus, we need to define these for prerenderer:
// Strip base prefix from the urls. Prerenderer will take our base as /
const urlModifier = (s: string) => s.replace(env.BASE_URL.substr(1), '');
// Ensure prerenderer's server will serve our public assets correctly (they are not in rollup bundle|
const hookServer = (app: express.Application) => {
  app.use(env.BASE_URL || '/', express.static('./dist'));
};
// Make prerenderer output our files correctly, route by route. In my simple case we have only one route, so just output is where needed.
const postProcess = (r: RenderedRoute) => { r.outputPath = 'index.html'; }

(all three is needed. urlModifier is for assets in bundle, hookServer is for assets not in bundle, postProcess for output)
...and then use them configuring plugin in vite.config.ts:

prerenderer({ routes: [env.BASE_URL || '/'], rendererOptions: { renderAfterTime: 1000 },
                       server: { before: hookServer },
                       postProcess: postProcess,
                       urlModifier: urlModifier 
                     });

сс @Tofandel this is a closed issue so I ping you, (1) maybe it's useful to add basePath to prerenderer options, (2) idk how to do it without a deprecated before option (as in rollup plugin I dont have access to a prerenderer instance).
If you find a way to incorporate my work in the project, I'll be glad to help.

@Tofandel
Copy link
Owner

Tofandel commented Oct 9, 2024

The hookServer for static files is the correct approach, are you using a plugin to copy static files or someting? We can't make any assumptions there unless we start looking into other plugins like rollup-plugin-copy which would quickly become a mess I don't plan on maintaining, but we could have an option to make it easier to use. Normally static assets that are imported ( import imgUrl from './img.png') should still be able to be found because they are registered as assets in rollup, some plugins that copy files should also register as assets but not all of them do

To not use the deprecated option you simply need to do this

prerenderer({ routes: [env.BASE_URL || '/'], rendererOptions: { renderAfterTime: 1000 },
                       postProcess: postProcess,
                       urlModifier: urlModifier 
                     }).hookServer(hookServer);

I have access to the base url of vite (rollup doesn't have one) or webpack config so I should be able to alter the output path and make routes be relative to the base path (will be a breaking change but I can add an option basePath that can be set to true or a string to avoid one and allow plugins that change this to work), since I'm guessing the issue is the basePath is prepended twice to the output index.html right?

Could you share your full vite/rollup config so I can have a better understanding

@faerics
Copy link

faerics commented Oct 9, 2024

Thanks for the response! ❤️

some plugins that copy files should also register as assets but not all of them do

Ah, interesting. I use https://github.com/i18next/react-i18next, and it just uses json locales as they're needed, that's why assets aren't registered.
Then, hookServer might be excluded out of the scope.

To not use the deprecated option you simply need to do this <...>
This gives the following:

vite.config.ts:29:28 - error TS2339: Property 'hookServer' does not exist on type 'OutputPlugin'.

As for vite.config.ts, here it is

import react from '@vitejs/plugin-react';
import { defineConfig, loadEnv } from 'vite';
import svgr from 'vite-plugin-svgr';
import prerenderer from '@prerenderer/rollup-plugin';
import type { RenderedRoute } from '@prerenderer/prerenderer';
import express from 'express';

export default defineConfig(({ command, mode }) => {
  const env = loadEnv(mode, process.cwd(), '')

  // We're behind the proxy. Thus, we need to define these for prerenderer:
  // Strip base prefix from the urls. Prerenderer will take our base as /
  const urlModifier = (s: string) => s.replace(env.BASE_URL.substr(1), '');
  // Ensure prerenderer's server will serva our public assets correctly (they are not in rollup bundle|
  const hookServer = (app: express.Application) => {
    app.use(env.BASE_URL || '/', express.static('./dist'));
  };
  // Make prerenderer output our files correctly, route by route.
  const postProcess = (r: RenderedRoute) => { r.outputPath = 'index.html'; };
  


  return {
    plugins: [react(), svgr(),
              prerenderer({ routes: [env.BASE_URL || '/'], rendererOptions: { renderAfterTime: 1000 },
                            server: { before: hookServer },
                            postProcess: postProcess,
                            urlModifier: urlModifier 
                        })
              ],
    resolve: {
      alias: [{ find: '@', replacement: '/src' }],
    },
    base: env.BASE_URL || "/",
    esbuild: {
      supported: {
        'top-level-await': true
      },
    },
  }
  });

@Tofandel
Copy link
Owner

Tofandel commented Oct 9, 2024

Yes I see that https://github.com/i18next/react-i18next is using http to load locales instead of using the import.meta.glob build system so that's why it's outside the scope

Though in your config I don't see any plugin that would copy your locales over to /dist/, any idea?

Okay I see that vite has a publicDir option and this is what it does, copy the files to the dist (For my own reference https://github.com/vitejs/vite/blob/889bfc0ada6d6cd356bb7a92efdce96298f82fef/packages/vite/src/node/build.ts#L897-L916)

One thing to look out for is that we are building the page before it's output to the filesystem by rollup, that's why you won't see any express.static in this lib because the files don't exists at the time we prerender, we serve them entirely from memory, it's okay if you point it to the sources but pointing it to dist could cause problems, maybe they don't exist on the first build and then they will be one version behind (Vite seems to copy the files at the same time it cleans the outDir and so way before the build emits that's why your setup works)

I would still recommend changing to this app.use((env.BASE_URL || '/')+'public', express.static('./static/')); for the time being, I'll also look for integrating the static folder of vite into the build

vite.config.ts:29:28 - error TS2339: Property 'hookServer' does not exist on type 'OutputPlugin'.

My bad, that's only on the prerender instance not the plugins, I'll aim to fix this as well

@faerics
Copy link

faerics commented Oct 10, 2024

I would still recommend changing to this app.use((env.BASE_URL || '/')+'public', express.static('./static/')); for the time being,

This is essential. Didn't know anything about static. Very useful, thanks.


So, should we sum up and outline the new issues?

  • Add newhookServer API to plugins
  • Integrate static folder to build.
  • Respect Vite's base option in rollup plugin (both in routes and in output path).

Am I correct? Should we post them as new issues?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants