Skip to content

feat(html): pass req + res to transformIndexHtml#14797

Draft
mxxk wants to merge 1 commit into
vitejs:mainfrom
mxxk:req-res-transform-index-html
Draft

feat(html): pass req + res to transformIndexHtml#14797
mxxk wants to merge 1 commit into
vitejs:mainfrom
mxxk:req-res-transform-index-html

Conversation

@mxxk

@mxxk mxxk commented Oct 30, 2023

Copy link
Copy Markdown

Fixes #14431.

Description

As discussed in #14431 (comment), it may be useful to pass req and res to transformIndexHtml during vite dev. This has no effect on vite preview or vite build.

Additional context

Original discussion: #14431 (comment)

What is the purpose of this pull request?

  • Bug fix
  • New Feature
  • Documentation update
  • Other

Before submitting the PR, please make sure you do the following

  • Read the Contributing Guidelines.
  • Read the Pull Request Guidelines and follow the PR Title Convention.
  • Check that there isn't already a PR that solves the problem the same way to avoid creating a duplicate.
  • Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves (e.g. fixes #123).
  • Ideally, include relevant tests that fail without this PR but pass with it.

@bolt-new-by-stackblitz

Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@mxxk
mxxk force-pushed the req-res-transform-index-html branch from a8479d5 to bc21e49 Compare October 30, 2023 01:42
@mxxk mxxk changed the title feat(html): Pass req + res to transformIndexHtml feat(html): pass req + res to transformIndexHtml Oct 30, 2023
Comment thread docs/guide/api-plugin.md
@@ -374,6 +374,9 @@ Vite plugins can also provide hooks that serve Vite-specific purposes. These hoo
server?: ViteDevServer

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Starting thread for open questions on this PR...

  • It was not immediately apparent to me where tests for this change would belong. Would appreciate some pointers!

  • Should this change also affect ViteDevServer.transformRequest?

    /**
    * Programmatically resolve, load and transform a URL and get the result
    * without going through the http request pipeline.
    */
    transformRequest(
    url: string,
    options?: TransformOptions,
    ): Promise<TransformResult | null>

    From looking at the implementation of transformRequest, my hunch is "no", but wanted to call this out.

  • Would an example of this feature in the playground folder be useful?

  • Should this change be back-ported this to 4.x? Or is 4.x feature-frozen as of now? (Happy to back-port if given the go-ahead.)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests can go into playground/html with a new plugin that uses this new property perhaps. e.g setting headers. We have a couple tests that tests x-served-by header for example.

transformRequest should not be affected. Those are use for JS mostly.

Yeah this would go into Vite 5. We don't usually backport features to 4.0

Comment thread docs/guide/api-plugin.md
server?: ViteDevServer
bundle?: import('rollup').OutputBundle
chunk?: import('rollup').OutputChunk
originalUrl?: string

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

originalUrl was added to IndexHtmlTransformContext in 13d41d8, but the docs still reflected the previous type signature. Taking this opportunity to roll in the fix.

Comment thread docs/guide/api-plugin.md
bundle?: import('rollup').OutputBundle
chunk?: import('rollup').OutputChunk
originalUrl?: string
req?: import('connect').IncomingMessage

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since transformIndexHtml is also called during dev server warmup, when there is no req / res to pass through, is this something which warrants additional documentation or comments?

if (file.endsWith('.html')) {
const url = htmlFileToUrl(file, server.config.root)
if (url) {
const html = await fs.readFile(file, 'utf-8')
await server.transformIndexHtml(url, html)
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be fine undocumented about this case, as long as we document that consumers can optionally pass req or res in dev, e.g. in SSR. So it's not a guarantee.

@@ -938,6 +940,8 @@ export interface IndexHtmlTransformContext {
bundle?: OutputBundle

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wanted to double check something... The type signature of IndexHtmlTransformContext currently permits some invalid values, such as objects with server and bundle. I wonder, why this type not a disjunction?

interface IndexHtmlTransformBuildContext {
  path: string
  filename: string
  // NOTE: `bundle` and `chunk` are optional because they are not set for
  // `transformIndexHtml` with `order: pre`.
  bundle?: OutputBundle
  chunk?: OutputChunk
}

interface IndexHtmlTransformDevContext {
  path: string
  filename: string
  server: ViteDevServer
  originalUrl: string
  // NOTE: `req` and `res` are optional because they are optional in
  // `ViteDevServer.transformIndexHtml`
  req?: Connect.IncomingMessage
  res?: http.ServerResponse
}

export type IndexHtmlTransformDevContext =
  IndexHtmlTransformBuildContext | IndexHtmlTransformDevContext;

Is it because such a change would break types for upstream dependents?

Alternatively, we could keep the existing type signature but group related fields together under commented groups, like:

export interface IndexHtmlTransformContext {
  /**
   * public path when served
   */
  path: string
  /**
   * filename on disk
   */
  filename: string

  // Parameters available during `vite dev` only
  server?: ViteDevServer
  originalUrl?: string
  req?: Connect.IncomingMessage
  res?: http.ServerResponse

  // Parameters available during `vite build only`
  bundle?: OutputBundle
  chunk?: OutputChunk
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably was easier implemented in the past that way 😄 But I think we could change that separately, but yeah I think it would break downstream quite a bit, so maybe not quite worth the change.

bundle?: OutputBundle
chunk?: OutputChunk
originalUrl?: string
req?: Connect.IncomingMessage

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since transformIndexHtml is also called during dev server warmup, when there is no req / res to pass through, is this something which warrants additional documentation or comments?

if (file.endsWith('.html')) {
const url = htmlFileToUrl(file, server.config.root)
if (url) {
const html = await fs.readFile(file, 'utf-8')
await server.transformIndexHtml(url, html)
}
}

@bluwy

bluwy commented Oct 31, 2023

Copy link
Copy Markdown
Member

Thanks for the PR! Just to set expectations, we haven't discussed this yet so there's a chance the PR might not go through. But appreciate the work here!

The point about "req and res could be optional in dev" does make the dev-server-only fields/api a little inbalance though, and I'm not quite sure if it's a nice behaviour. At least for originalUrl we were able to fallback to the original url. Would be something to discuss about.

@mxxk

mxxk commented Nov 1, 2023

Copy link
Copy Markdown
Author

Thanks for the PR! Just to set expectations, we haven't discussed this yet so there's a chance the PR might not go through. But appreciate the work here!

The point about "req and res could be optional in dev" does make the dev-server-only fields/api a little inbalance though, and I'm not quite sure if it's a nice behaviour. At least for originalUrl we were able to fallback to the original url. Would be something to discuss about.

Makes sense! I assume it's okay to leave this PR as-is for now pending the Vite team discussion, since even in its current state it shows the basic implementation and calls out gotchas to consider. Happy to implement the feedback per #14797 (comment) if the team wants to move ahead.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

transformIndexHtml hook params ctx add full request param

2 participants