Customizing html template
See original GitHub issueHistory: In Nuxt 2, we were supporting the ability to provide a custom HTML template used for the renderer. While it was simple, several issues:
- Only could be customized once by end-users (modules cannot hook to extend it and had to use other methods for injection)
- Can be outdated if we wanted to add a new placeholder for the built-in template
- Additional spaces or code format for customization can break hydration behavior
- With Nitro and moving to standalone server builds, we had to convert it into a JS function
- Different behavior for SSR/SPA is not covered
- Runtime level customizations are not possible
- Opaque behavior without ability to inspect by Nuxt
This is the anatomy of the built-in template as a standard HTML structure:
<!DOCTYPE html>
<html {{ HTML_ATTRS }}>
<head {{ HEAD_ATTRS }}>
{{ HEAD }}
</head>
<body {{ BODY_ATTRS }}>
{{ APP }}
</body>
</html>
The main use-case of providing a custom template is extending placeholders to add a global static script or style or attributes. With Nuxt 3, I’m proposing to have a configuration interface in order to extend template:
export default defineNuxtConfig({
template: {
htmlAttrs: [],
headAttrs: [],
headPrepend: [],
headPrepend: [],
bodyAttrs: [],
bodyPrepend: [],
bodyAppend: []
}
})
(note: we shall make it consistent with RenderResult.meta
interface)
This interface is forward-compatible, predictable, easily configurable and extandable by modules and always leads to a valid HTML output.
More dynamic customization and runtime behavior can be provided by nuxt:render
hooks (https://github.com/nuxt/framework/issues/5534).
There was also an initial discussion to provide the ability completely override the template as an escape hatch. I believe unless it is proven there is a valid use case that cannot be supported by the Object interface, it is probably safer to not expose it. There might be cases we want to compile something that is not HTML (like a Native output?) but this probably deserves better refactor on renderer implementation to expose an API and allow full overriding renderer file, taking into account it is not rendering HTML.
Issue Analytics
- State:
- Created a year ago
- Reactions:24
- Comments:45 (21 by maintainers)
Top GitHub Comments
@danielroe I have been using the app:templates hook to override the getContents method of views/document.template.mjs. Since https://github.com/nuxt/framework/commit/f58aa8114fe9286d89d0e70e1101b5103cd81304 this is no longer possible and the HTML template itself is hard coded.
Could you elaborate how the nitro hook render:html could be used?
To give some context: We use ESI tags to inject some HTML into each Document right before it is send to the user. This also means these tags will be replaced by some markup on the client. Therefore we cannot use anything that is managed by e.g. Vue on the client without triggering hydration mismatch.
An example:
EDIT I think I got a solution.
This should work. Similar to
html.bodyPreprend
andhtml.bodyAppend
it would be nice to pre- and append content to<head>
to influence loading of resources (lightly).Google GTM’s instructions asks you to place their script as first scripts in the head and firsts in the body:
I don’t believe it matters that much, but some users might want to follow guidelines as close as possible I think