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

Generate HTML Snippets for Backend Integration #19578

Open
4 tasks done
odanado opened this issue Mar 5, 2025 · 5 comments
Open
4 tasks done

Generate HTML Snippets for Backend Integration #19578

odanado opened this issue Mar 5, 2025 · 5 comments

Comments

@odanado
Copy link
Contributor

odanado commented Mar 5, 2025

Description

Background

Vite provides the build.manifest option, which helps integrate with backend frameworks by describing the relationships between built JavaScript and CSS files. Backend frameworks typically parse manifest.json and generate <script> and <link> tags accordingly, embedding them into their templating systems.

https://vite.dev/guide/backend-integration

Example manifest.json:

{
  "views/foo.js": {
    "file": "assets/foo-BRBmoGS9.js",
    "name": "foo",
    "src": "views/foo.js",
    "isEntry": true,
    "imports": ["_shared-B7PI925R.js"],
    "css": ["assets/foo-5UjPuW-k.css"]
  }
}

Feature Proposal

Instead of requiring backend frameworks to process manifest.json and generate HTML tags, Vite could provide an option to generate the necessary <script> and <link> tags directly. This would simplify integration with server-side frameworks, reducing the need for custom parsers or code generators on the backend side.

According to Conway’s Law, system design tends to mirror organizational structures. By allowing the frontend team to manage asset injection, we can reduce the friction between teams and streamline development.

Motivation

Our team consists of separate backend and frontend teams, working with different programming languages. Currently, backend engineers must understand Vite's manifest format and implement a custom code generator to inject the correct assets. Ideally, Vite-related concerns should be maintained by the frontend team, as this better reflects our team's structure and expertise.

Suggested solution

I propose introducing a new option: build.generateBackendIntegrationHtml.

When enabled, Vite will generate a file named .vite/backend-integration-html.json, which provides pre-generated HTML snippets for embedding assets into backend templates. This eliminates the need for backend frameworks to parse manifest.json and construct <script> and <link> tags manually.

Example .vite/backend-integration-html.json:

{
  "views/foo.js": {
    "head": {
      "afterBegin": "",
      "beforeEnd": "<link rel=\"stylesheet\" href=\"assets/foo-5UjPuW-k.css\" />\n<link rel=\"stylesheet\" href=\"assets/shared-ChJ_j-JJ.css\" />\n<script type=\"module\" src=\"assets/foo-BRBmoGS9.js\"></script>"
    },
    "body": { "afterBegin": "", "beforeEnd": "" }
  }
}

Each entry corresponds to an entry point in the project and contains predefined HTML snippets for different locations within a template (e.g., inside <head> or <body>).

The property names (afterBegin, beforeEnd) are inspired by insertAdjacentHTML, making it intuitive for developers familiar with DOM manipulation.

This structure allows backend frameworks to simply read and insert the required tags without additional processing.

Alternative

No response

Additional context

No response

Validations

@odanado
Copy link
Contributor Author

odanado commented Mar 6, 2025

In my current team, we found the need for this functionality. Initially, I considered implementing it as a Vite plugin, but after exploring the Plugin API, I realized that the available information was insufficient for generating the necessary HTML snippets. As a workaround, we developed and are currently using a CLI tool that loads manifest.json after running vite build to generate the required HTML tags. While this solution works, it would be much more convenient if this functionality were built into Vite itself.

If there are no objections to adding this feature, I would be happy to contribute it myself.

@sapphi-red
Copy link
Member

As a workaround, we developed and are currently using a CLI tool that loads manifest.json after running vite build to generate the required HTML tags.

I guess this can be a plugin by doing this exact transform in writeBundle hook. That said, I agree it is hard to generate the necessary <script> / <link> tags from the current manifest.json. Especially the crawling of importedChunks.


I think the things needs to consider are:

  1. Adding this feature as an option would increase the manifest related option to 3 (build.manifest, build.ssrManifest, build.generateBackendIntegrationHtml). I think it is difficult for users to find out the one they need. Probably grouping them under build.manifest could work.

    type BuildOptions = {
      // other options
    
      // string | boolean is for backward compat
      manifest: string | boolean | {
        // 'detailed': the current manifest
        // 'detailed': `build.ssrManifest`
        // 'backend': `build.generateBackendIntegrationHtml`
        type: 'detailed' | 'ssr' | 'backend'
        path?: string
      }
    }
  2. Having the tags directly as string makes it difficult to add additional attributes. Maybe good to have it as { tag: string, attributes: Record<string, string> }?

  3. Check if this new option is actually useful for others. If you can investigate some public repositories that uses build.manifest and check if the new option makes them easier to do what they need, it would help us consider this feature. Or we can wait for people to add +1 to this issue.


By the way, do you have any assets only used from the backend? I guess the current structure of this manifest (.vite/backend-integration-html.json) cannot handle those cases.
For example, generating an HTML containing a path to an asset that is meant to be pre-transformed by Vite at build time.

<img src="./path/to/image.png" />

@odanado
Copy link
Contributor Author

odanado commented Mar 6, 2025

By the way, do you have any assets only used from the backend? I guess the current structure of this manifest (.vite/backend-integration-html.json) cannot handle those cases.
For example, generating an HTML containing a path to an asset that is meant to be pre-transformed by Vite at build time.

In my project, there are certain script tags that are only used by the backend. However, these tags are managed by the server team and are not intended to be processed or transformed by Vite.

For example, we use a server-side templating engine like the following:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Example of Server Side Template</title>
    <script>
      // Embed a resource for i18n by the server side.
      window.i18n = {};
    </script>
    <!-- The following script tags are managed by the Server team. -->
    <script src="https://example.com/tracking-sdk.js"></script>

    <!-- The following script tags are generated from manifest.json. -->
    <script type="module" src="/path/to/index-abcd.js"></script>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

@odanado
Copy link
Contributor Author

odanado commented Mar 6, 2025

Adding this feature as an option would increase the manifest related option to 3 (build.manifest, build.ssrManifest, build.generateBackendIntegrationHtml).

Some projects specify both build.manifest and build.ssrManifest at the same time.
https://github.com/TanStack/bling/blob/62703ba3d204a0315ef6043d0f59c5b70c27e73d/packages/bling/src/astro.ts#L39-L42

In that case, it might be necessary to allow multiple configurations simultaneously, such as using an array like build.manifests.

type BuildOptions = {
  // other options

  // string | boolean is for backward compat
  manifests: string | boolean | {
    // 'detailed': the current manifest
    // 'ssr': `build.ssrManifest`
    // 'backend': `build.generateBackendIntegrationHtml`
    type: 'detailed' | 'ssr' | 'backend'
    path?: string
  }[]
}

However, introducing a new configuration option could also lead to confusion for users.

Check if this new option is actually useful for others.

If this feature is implemented, the following code in Vite Ruby and django-vite would be reduced to just parsing JSON.

Vite Ruby: https://github.com/ElMassimo/vite_ruby/blob/98d3d5f452d82cfc25720ed85be83f4b43b45d93/vite_ruby/lib/vite_ruby/manifest.rb#L27

django-vite: https://github.com/MrBin99/django-vite/blob/c6df9f5ab4d3aac8481abfcca010e2faa9653554/django_vite/core/asset_loader.py#L157

@bluwy
Copy link
Member

bluwy commented Mar 7, 2025

Can you show how the code would be reduced on the consumer side? If we account for flexibility, eg adding custom attributes to link/scripts, changing the base of the paths, where it's injected (how should vite know it should be injected in the head or body?), then the manifest would need to be generalised further more than what you have proposed. And for me, the very-base representation is what we have now.

Maybe it would be enough for the docs to show an example of generating these HTML instead of only explaining what to do? That would give a good starting point for most projects to customize however they want to, or port to another language.

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