fastify-vite icon indicating copy to clipboard operation
fastify-vite copied to clipboard

Domain Expired: Docs Unavailable / Question Re: Relative base: ./

Open jamcalli opened this issue 2 months ago • 9 comments

Prerequisites

  • [x] I have written a descriptive issue title
  • [x] I have searched existing issues to ensure the issue has not already been raised

Issue

As the title states, it would appear your domain has expired and the docs are unavailable.

I was exploring how to get dynamic runtime base paths to work using fastify-vite and was trying several things, including setting:

base: './'

Which errors out:

node:internal/process/promises:394
    triggerUncaughtException(err, true /* fromPromise */);
    ^

AssertionError [ERR_ASSERTION]: The first character of a path should be `/` or `*`
    at Router.on (/watchlist-v2/node_modules/find-my-way/index.js:118:3)
    at Object.addNewRoute (/watchlist-v2/node_modules/fastify/lib/route.js:352:16)
    at Object.route (/watchlist-v2/node_modules/fastify/lib/route.js:263:19)
    at Object._route [as route] (/watchlist-v2/node_modules/fastify/fastify.js:301:27)
    at fastifyStatic (/watchlist-v2/node_modules/@fastify/static/index.js:115:15)
    at Plugin.exec (/watchlist-v2/node_modules/avvio/lib/plugin.js:125:28)
    at Boot._loadPlugin (/watchlist-v2/node_modules/avvio/boot.js:432:10)
    at process.processTicksAndRejections (node:internal/process/task_queues:90:21) {
  generatedMessage: false,
  code: 'ERR_ASSERTION',
  actual: false,
  expected: true,
  operator: '==',
  diff: 'simple'
}

Any suggestions on subfolder deployments?

jamcalli avatar Sep 29 '25 08:09 jamcalli

To follow up, and for anyone trying to implement something similar, I did manage to get this working albeit perhaps there's a more elegant solution.

Vite Configuration

Add to vite.config.js:

export default {
  base: '/',
  build: {
    experimental: {
      renderBuiltUrl(filename, { hostType }) {
        // For JS and CSS, use runtime base path resolution
        if (hostType === 'js' || hostType === 'css') {
          return {
            runtime: `window.__assetBase(${JSON.stringify(filename)})`,
          }
        }
        // For other assets (images, fonts), use relative paths
        return { relative: true }
      },
    },
  },
}

Server Hook

Add an onSend hook to inject the base path into HTML responses:

// Inject runtime base path into HTML responses
fastify.addHook('onSend', async (_request, reply, payload) => {
  // Only modify HTML responses for the SPA
  const contentType = reply.getHeader('content-type')
  if (
    typeof contentType === 'string' &&
    contentType.includes('text/html') &&
    typeof payload === 'string'
  ) {
    // Get normalized base path from config
    const normalizedBasePath = normalizeBasePath(process.env.BASE_PATH)

    // Inject base path and asset helper as inline script before any other scripts
    const injectedScript = `<script>
      window.__BASE_PATH__ = ${JSON.stringify(normalizedBasePath)};
      window.__assetBase = function(filename) {
        return window.__BASE_PATH__ === '/' ? '/' + filename : window.__BASE_PATH__ + '/' + filename;
      };
    </script>`
    const modifiedPayload = payload.replace(
      '<head>',
      `<head>${injectedScript}`,
    )

    return modifiedPayload
  }
  return payload
})

Server Registration

Register your app with the base path prefix:

const basePath = normalizeBasePath(process.env.BASE_PATH)
if (basePath !== '/') {
  await app.register(fp(serviceApp), { prefix: basePath })
} else {
  await app.register(fp(serviceApp))
}

Client-Side Usage

Wrap all API calls with a helper that prepends the base path:

export function api(path: string): string {
  const basePath = window.__BASE_PATH__ || '/'
  const normalizedBase = basePath.endsWith('/') && basePath !== '/'
    ? basePath.slice(0, -1)
    : basePath
  const normalizedPath = path.startsWith('/') ? path : `/${path}`
  return normalizedBase === '/' ? normalizedPath : `${normalizedBase}${normalizedPath}`
}

// Usage
fetch(api('/v1/users/me'))

Configure React Router with the base path:

function getBasename(): string {
  const basePath = window.__BASE_PATH__ || '/'
  if (basePath === '/') return ''
  return basePath.endsWith('/') ? basePath.slice(0, -1) : basePath
}

export const router = createBrowserRouter(routes, { basename: getBasename() })

Result

Set BASE_PATH via environment variable:

  • BASE_PATH=/http://localhost:3000/
  • BASE_PATH=/subfolderhttp://localhost:3000/subfolder/

Same build works for all deployment paths.

jamcalli avatar Sep 30 '25 08:09 jamcalli

The domain issue will need to wait until @galvez returns.

onlywei avatar Oct 03 '25 20:10 onlywei

@mcollina

onlywei avatar Oct 12 '25 03:10 onlywei

It seems @galvez is unresponsive. We should look into deploying this at vite.fastify.dev.

mcollina avatar Oct 12 '25 10:10 mcollina

@mcollina Any update on where redeploying the docs stands? I've been looking at fastify-vite as a starting point for my next project, between https://blog.platformatic.dev/exploring-react-ssr-with-fastify and docs in the repo, fine enough getting started, but having docs to reference / point teammates at would be really useful

zemccartney avatar Oct 24 '25 18:10 zemccartney

@mcollina what's the process to change the deploy target?

onlywei avatar Oct 24 '25 20:10 onlywei

It's on my todo list.

mcollina avatar Oct 26 '25 09:10 mcollina

@onlywei can you identify where this should be deployed to and what infrastructure would be needed?

mcollina avatar Oct 26 '25 09:10 mcollina

@mcollina I don't have an opinion on where it should be deployed to, but as far as I can tell the docs site is just a static site generated by vitepress. It should be deployable anywhere, and likely doesn't even need a "server" -- just a static file server.

onlywei avatar Nov 04 '25 00:11 onlywei