question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Customizing html template

See original GitHub issue

History: 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:open
  • Created a year ago
  • Reactions:24
  • Comments:45 (21 by maintainers)

github_iconTop GitHub Comments

3reactions
pierrescommented, Sep 9, 2022

@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:

<!DOCTYPE html>
<html ${joinAttrs(html.htmlAttrs)} data-custom="value">
<head>${joinTags(html.head)}<!--esi <esi:include src="/some/stuff" /> --></head>
<body ${joinAttrs(html.bodyAttrs)}><!--esi <esi:include src="/more/stuff" /> -->${joinTags(html.bodyPreprend)}${joinTags(html.body)}${joinTags(html.bodyAppend)}</body>
</html>

EDIT I think I got a solution.

  • Put a Nitro plugin into /server/plugins
  • e.g.
import { defineNitroPlugin } from 'nitropack/runtime/plugin'

export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('render:html', (html, { event }) => {
    html.head.push('<!--esi <esi:include src="/some/stuff" /> -->')
  })
})

This should work. Similar to html.bodyPreprend and html.bodyAppend it would be nice to pre- and append content to <head> to influence loading of resources (lightly).

3reactions
Rigo-mcommented, Jun 23, 2022

Google GTM’s instructions asks you to place their script as first scripts in the head and firsts in the body: Screenshot 2022-06-23 at 15 29 51

I don’t believe it matters that much, but some users might want to follow guidelines as close as possible I think

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to Customize an HTML Template - Web Design TutsPlus
1. Canvas - The Multipurpose HTML5 Template · 2. Porto - HTML5 Responsive Template · 3. BeTheme - Responsive Multipurpose HTML Template ·...
Read more >
How to Customize an HTML Template - A Step By Step Guide
Download the template you want to edit. · Right-click on the name where it is reading 'Noah Henderson' by default. · Now open...
Read more >
Custom HTML Templates - Anvil Works
As well as using pre-built templates, Anvil lets you use HTML to design your app exactly as you want it, then configure drop...
Read more >
Customize HTML templates - Knowledge Center - Zuora
After an HTML template is created, you can start customizing it in the online HTML template editor as needed. For example, you can...
Read more >
Customize your template using your browser HTML/CSS editor
Customize your template using your browser HTML/CSS editor. This tutorial will show you how to edit the predesigned templates for YAMM in the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found