Servue
Helping you serve vue with servue
Server-side rendering engine that renders vue files into html strings
- Servue
- Installation
- What is servue?
- Setup
- Layouts & Views
- Setting custom path variables
- Custom html body template
- Custom Preprocessor/Language Support
- Mode
- Head Management
- Passing data to vue from server-side
- Global State / Cross Component Data
- Precompiling Vue Pages
- Future Of This Package
- Package Changelog / Version
Installation
npm install servue --save
Then install peer dependencies (so you can control your vue version)
npm install vue --save
npm install vue-server-renderer --save
npm install vue-template-compiler --save
What is servue?
Servue server-side-renders Vue Single File Components (.vue
files) into html. It is a fully capable templating engine, and allows users to create nested layouts using slots and components.
The renderer provides the correct scripts, and styles on the client-side. It creates no extra build/compiled files. It's perfect for multi-page applications and great for users wanting to use Vue with Express or Koa
It's this easy to render .vue
files:
await servue // renders "home.vue" into html string
Requires Node 8+
Features
- Supports precompilation
- Supports layouts
- Supports templating
- Supports server-side Rendering
- Supports head management
- Supports imports CSS files and other assets
- Supports custom language preprocessors (less, pug, etc)
- No build or compile files, all in-memory
- Supports custom templating
Setup
Express Usage
const Servue = const express = var app = var servue = servueresources = path app app
Koa Usage
const Servue = const Koa = var app = var servue = servueresources = path app app
Layouts & Views
Servue fully supports templating features and allows for multiple and nested layouts using Vue slots.
Here's a simple example:
Ensure you wrap your app/root-level layout with
<servue>
. It is required for Servue to work.
layouts/parent.vue
The page title is:
This layout has a slot for content named content
and a slot for the title named title
Now, the home file can use this layout:
pages/home.vue
Home Hello
Rendered Result
Home <!-- CSS, state and head are all automatically injected here --> The page title is: Home Hello
Setting custom path variables
You may use your own custom paths for folders
//Sets views folder path which contains .vue .css .less .js and etcservueresources = path //path of node_modulesservuenodemodules = path
Custom html body template
servue `<!DOCTYPE html><html> <head> </head> <body> <script></script> </body></html>`
Custom Preprocessor/Language Support
Here we add support for the LESS/SCSS/Stylus/pug preprocessor language so it can be used in our .vue
files.
In this example, we use the stylus-loader
packagetop to add stylus support to our package.
servuewebpackCommonmodulerules
This will be red
Mode
For faster compilation, you can use the production version of vue.
servuemode = "production" //default = "development"
However, this will remove vue development warnings, so it is best to use development
for debugging & dev as it enables vue dev-tools.
Head Management
layouts/parent.vue
<!-- Pass slot for head in-case other child vues want to add additional elements to the head --> Page:
the head
template slot is rendered into the <head>
tags on the server-side. The head
tag can be nested, as shown in parent.vue
. This means that home.vue
may optionally pass it's own head to the user.
home.vue
Home Hello
head output
Home <!-- Other Servue injections here -->
Passing data to vue from server-side
asyncData()
in .vue file
Via asyncData()
is a custom feature provided by servue, it allows you to make asynchronous requests like API calls. It is called on the server-side.
Data returned from asyncData is merged into the data()
function, and then also passed onto the client.
It only works on the rendered file, and not inside subcomponents or layouts.
router
pages/home.vue
async { let ctx = ssrContextctx return url: ctxurl hello: "World" }
data
Via You can simply do this through the context argument
let data = "hello": "world" await servue
This data is merged with your vue component's data function (if there is one), and can then be accessed by your vue file:
{{ hello }}
Output:
world
Merge order
Data merges are shallow (via Object.assign
) and have this priority:
asyncData()
- If Providedservue.render('home', {data})
- If Provideddata()
- If Provided
Global State / Cross Component Data
To manage state globally (across components) and maintain reactivity, Servue has implemented a feature that easily allows you to do so.
All of your components will have access to a reactive object (including 3rd-party components)
this$state
Implementing it
In your root-level parent layout which you share across multiple pages, you must implement the following code:
/** * You must declare all properties that components will use up-front because * of the limitations of Vue's reactivity (which will be fixed in Vue 3.0) * * To add new properties, you should be able to use: * ```js * Vue.set(this.$state, 'name', val) * ``` */ ...
Example Use Case
async { // make async api request for user let me = firstName: "Steve" this$statefirstName = mefirstName }
async { // make async api request for user let me = firstName: "Steve" /** * * never reassign this.$state or it will lose reference to the global * object, and lose reactivity, if you want to assign a large number of * varibles to the global state, use Object.assign(this.$state, obj) */ Object }
Don't do this
this$state = foo: "bar" // this will lose reference to the original global state
Precompiling Vue Pages
It's a memory intensive process to compile the .vue
SFCs. After they are compiled once, they are cached and rerendered at a far greater speed.
This means that the first time a .vue
SFC is rendered, it will take a few seconds to do so. You don't want this in a production environment, so we have an option for you to precompile all .vue
files so your users get the fastest speeds when visiting your website.
You can do this with the precompile function
/** * ---------- * IMPORTANT: * ---------- * Make sure to only precompile the pages you need, eg: you don't need to * precompile header.vue` or footer.vue, only home.vue or about.vue, * so seperate the actual full pages into a seperate folder. */ /** * @param * @returns */await servue
Future Of This Package
I may be further developing this package into a full MPA (multi-page apps) and SPA (single-page apps) capable application with internal routing using Vue Router.
It does somewhat unalign with the original goals of the project which was to easily integrate with koa
and express
, but it still will, just in a different way.
To Do List
- Implement state management
- Reduce RAM usage by deleting virtual memory files after caching the renderers
- Make package more applicable for single page applications (SPAs)
- Potentially create an option for creating and serving build/dist files (as it takes a lot of ram and CPU to regenerate each SFC)
- Add hot-reloading
- Improve docs, create website
- Alternatively, create a nuxtjs "competitor" with servues head management system and layouts
Package Changelog / Version
2.2
You're no longer required to import the servue component in your master/parent layouts. It's automatically injected into every .vue
SFC
Your content
Now becomes
Your content
2.x
Passing data from server
We've changed the way data is passed from the server to the vue files
servue
becomes
servue
Instead of passing data through a typical route controller, you can now pass it inside from your .vue
files (see asyncData()
above)
This was done because req/res
or ctx
data is often required in .vue
files so we have made it easier to pass data like ctx to the views, and allow routing to be simpler.
router
Accessible in asyncData by
async { let ctx = ssrContextctx let url = ctxurl return url }
Used for
Future Australia Party Website - Promatia Government Website - Arkovia Government Website