Skip to content
This repository has been archived by the owner on Apr 9, 2023. It is now read-only.

Vue.js => style tags are rendered twice #103

Closed
o-alexandrov opened this issue Sep 12, 2017 · 12 comments
Closed

Vue.js => style tags are rendered twice #103

o-alexandrov opened this issue Sep 12, 2017 · 12 comments
Assignees

Comments

@o-alexandrov
Copy link
Contributor

Thank you for a nice plugin!

When using with Vue.js, the plugin, unfortunately, inlines the <style> tags from Vue.js single file components twice.

Please let me know, if such behavior is intended and the only choices for now are to either remove the duplicates by running regex on them:

postProcessHtml: function (context) {
    return context.html.replace(
        /(<style(.*?)<\/style>)/i,
        ''
    )
}

or to extract css in a separate file.

I'm currently using the regex method, but please let me know, if there is a way to not duplicate the <style> tags.
Also, if you need a reproduction repo, I could quickly prepare that as well, if there's a need for it.

Thank you very much!

@thorning
Copy link

I have the same problem (I think). The spa-plugin does not add the styles twice, but they are added again by Vue when you mount on top of the prerendered dom.

@o-alexandrov
Copy link
Contributor Author

o-alexandrov commented Sep 14, 2017

@thorning yeah, my bad, thank you for the correction.
That's exactly what is happening: The style tags are rendered again by Vue, when the components are mounted

@hackuun
Copy link

hackuun commented Sep 19, 2017

I have the same issue.

@drewlustro
Copy link
Collaborator

This is normal. It is similar to issues #105 and (loosely) #107.

Your endpoints are rendering and capturing the HTML verbatim. If Vue injects more on dynamic mount, it will be duplicate <style> markup.

Use postProcessHtml to sanitize your HTML into one unique set of CSS or JSS markup.


From the README doc:

// Manually transform the HTML for each page after prerendering,
// for example to set the page title and metadata in edge cases
// where you cannot handle this via your routing solution.
//
// The function's context argument contains two properties:
//
// - html :: the resulting HTML after prerendering)
// - route :: the route currently being processed
//            e.g. "/", "/about", or "/contact")
//
// Whatever is returned will be printed to the prerendered file.
postProcessHtml: function (context) {
  var titles = {
    '/': 'Home',
    '/about': 'Our Story',
    '/contact': 'Contact Us'
  }
  return context.html.replace(
    /<title>[^<]*<\/title>/i,
    '<title>' + titles[context.route] + '</title>'
  )
}

@o-alexandrov
Copy link
Contributor Author

@drewlustro That is totally inconvenient and is exactly what I have described in more detail in the original comment of this ticket.

IMO, this package should have a leading zero in its version, since it doesn't solve one of the foundational necessities, basic CSS usage.

@thorning
Copy link

I'm pretty sure the issue is not with this package, but with the vue remounting (I think they call it hydration).

The output from this plugin is as I want it, html and stylus to show the rendered page correct independent of Vue. The problem is that when mounting Vue on top of the prerender, it does not detect that the styles are already injected, and injects them again.

You could try to make a issue in the Vue repository, to see if there is a way to improve loading vue on top of a prerendered DOM.

I must admit that my solution so far is to ignore it, and let the double style tags exist, though it is not optimal.

@o-alexandrov
Copy link
Contributor Author

o-alexandrov commented Sep 26, 2017

@thorning
You can use regular expression to get rid of duplicates as described in my comment at the top and by @drewlustro as well, but it gets extremely inconvenient if there are more than two components that output style tags.

One of the solutions is to import all styles from one component. - That way you can get rid of the only style tag, using regexp and postProcessHtml, no matter how big your static website grows.

@chrisvfritz However, I believe this ticket should still be open for those, who are familiar enough with this package to add a check on existing style tags in the document, before processing output.

@o-alexandrov
Copy link
Contributor Author

o-alexandrov commented Sep 26, 2017

@thorning sorry, just realized that you still want to have your styles prerendered and my solution would bring you a CSS flash. Since there are no styles loaded before rendering.

The actual solution for us would be to use extract-text-webpack-plugin and then inject css using html-webpack-plugin.

That way there won't be any styles in the JS bundle. And the styles would still be prerendered, since they would be present in the index.template.html

P.S. for more details on CSS extraction, check SSR guide

@o-alexandrov
Copy link
Contributor Author

o-alexandrov commented Sep 26, 2017

@chrisvfritz Please check out my previous comment, it might help you to resolve this issue.
The styles have to be extracted from the processed JS bundle and only injected in the prerendered .html files

@chrisvfritz
Copy link
Owner

chrisvfritz commented Sep 26, 2017

The actual solution for us would be to use extract-text-webpack-plugin and then inject css using html-webpack-plugin.

@OlzhasAlexandrov I think it's worth adding a note about this to the README - PR welcome. 🙂 As you said, the problem doesn't have anything to do with this plugin specifically (or even Vue actually), but simply a reality of prerendering. If you inject styles into the body during render (or modify the HTML in any other way), we'll capture that. If that's not intended, it shouldn't be part of the render process.

@o-alexandrov
Copy link
Contributor Author

o-alexandrov commented Sep 26, 2017

@chrisvfritz okay, added a note here: #110

@chrisvfritz
Copy link
Owner

@OlzhasAlexandrov Thanks!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants