Is it possible to compile Vue.js templates to stat

2020-05-25 08:06发布

问题:

Recently I've fallen in love with Vue.js's single file components. It's so much nicer to have a component's template and styles close to each other, and I'm finding I write a lot fewer bugs now that it's so easy to componentise part of a page and use it in multiple places.

I'm wondering if I could extend this single-file component structure to generating static HTML pages, with no Vue involved.

For example, say I want to have a page that has a main "content" div containing a header, a section, and a footer. Using Vue.js, I can create 'header', 'section', and 'footer' components, and use JavaScript to have them instantiated after the page loads. Because each part of the page is in its own component, there's no chance of CSS in one component affecting another, and I have a much cleaner tree of files to edit.

However, this seems a little wasteful, as these components aren't actually interactive: I'm not using v-model or v-bind or v-on, I'm just using Vue.js because it lets me separate pieces of pages out. It also means my page won't work at all if JavaScript is disabled, since every single element (save the main content div) is dependent on Vue being available.

So is there any way I can compile .vue files, not to a page that loads these components at runtime using Vue.js, but to separate HTML and CSS files that render without any JavaScript?

Ideally, I'd have a component 'greeting.vue':

<template>
    <p class="greeting">Hello!</p>
</template>
<style scoped>
    .greeting { color: red; }
</style>

Used within a page:

<html>
    <body>
        <greeting></greeting>
    </body>
</html>

And these would compile into two files: an HTML page with the template compiled and pre-rendered, and a CSS file that contains the styles for all the components. I could then include the generated stylesheet in the page, and all the components would be styled.

I've looked at vue-loader and vueify, but I can't understand what they're doing since I haven't used Webpack or Browserify enough.

Is what I'm trying to do possible?

回答1:

What you are looking for is Server Side rendering. I would suggest you to have a look at Nuxt.js.

From VueJS docs:

Properly configuring all the discussed aspects of a production-ready server-rendered app can be a daunting task. Luckily, there is an excellent community project that aims to make all of this easier: Nuxt.js. Nuxt.js is a higher-level framework built on top of the Vue ecosystem which provides an extremely streamlined development experience for writing universal Vue applications. Better yet, you can even use it as a static site generator (with pages authored as single-file Vue components)! We highly recommend giving it a try.

It is super simple to get it started. If you use vue-cli:

$ vue init nuxt/starter <project-name>

It comes with all you normally need (Vuex, Router,..). Just keep in mind that it enforces some folder structure, that you have to follow.

Here is the list of commands that are included in the starter.

"scripts": {
  "dev": "nuxt",
  "build": "nuxt build",
  "start": "nuxt start",
  "generate": "nuxt generate"
}

You will probably be mostly iterested in generate, as it

Build the application and generate every route as a HTML file (used for static hosting).

Also cool thing to note is that the project seems to be (at the time of writing this) under active development and we can look forward to more great features!



回答2:

From the official vuejs guide:

If you’re using Webpack, you can easily add prerendering with the prerender-spa-plugin. It’s been extensively tested with Vue apps - and in fact, the creator is a member of the Vue core team.



回答3:

I would say that you can't do this because Vue uses a virtual DOM, it doesn't compile templates to HTML but to JavaScript render functions which is necessary to efficiently patch the DOM when data is updated.

I'm sure it's possible to do what you want to do with a bit of node magic to parse and output files, but that would be quite a large undertaking for something that would only have a minimal effect.