Jelajahi Sumber

update docs for ssr

Evan You 9 tahun lalu
induk
melakukan
92e91927f5
1 mengubah file dengan 117 tambahan dan 0 penghapusan
  1. 117 0
      packages/vue-server-renderer/README.md

+ 117 - 0
packages/vue-server-renderer/README.md

@@ -9,6 +9,7 @@ This package offers Node.js server-side rendering for Vue 2.0.
 - [Renderer Options](#renderer-options)
 - [Why Use `bundleRenderer`?](#why-use-bundlerenderer)
 - [Creating the Server Bundle](#creating-the-server-bundle)
+- [Creating the Client Manifest](#creating-the-client-manifest)
 - [Component Caching](#component-caching)
 - [Client Side Hydration](#client-side-hydration)
 
@@ -213,12 +214,60 @@ const renderer = createRenderer({
 
 > New in 2.2.0
 
+- only used in `createBundleRenderer`
+
 Explicitly declare the base directory for the server bundle to resolve node_modules from. This is only needed if your generated bundle file is placed in a different location from where the externalized NPM dependencies are installed.
 
 Note that the `basedir` is automatically inferred if you use `vue-ssr-webpack-plugin` or provide an absolute path to `createBundleRenderer` as the first argument, so in most cases you don't need to provide this option. However, this option does allow you to explicitly overwrite the inferred value.
 
 ---
 
+### clientManifest
+
+> New in 2.3.0
+
+- only used in `createBundleRenderer`
+- only used when the `template` option is also provided
+
+Provide a client build manifest object generated by `vue-ssr-webpack-plugin`. With the client manifest, the `bundleRenderer` has webpack build information of both the server and client, and thus will be able to automatically infer and inject asset links into the rendered HTML. For more details, see [Creating the Client Manifest](#creating-the-client-manifest).
+
+---
+
+### shouldPreload
+
+> New in 2.3.0
+
+- only used in `createBundleRenderer`
+- only used when the `template` and `clientManifest` options are also provided
+
+When a client manifest is present, the renderer will automatically inject [preload and prefetch directives](https://medium.com/reloading/preload-prefetch-and-priorities-in-chrome-776165961bbf) into the `<head>` section. By default, an asset will be preloaded when:
+
+- It is used during the render. For example, if your bundle uses code split, only assets used by the chunks that were used during a render will be injected.
+
+- It is of type `script` or `font`, because these are crucial for faster time-to-fisrt-paint / time-to-interaction. Images and other types of assets are **not** preloaded by default.
+
+If you do want to preload assets other than scripts and fonts, `shouldPreload` gives you full control:
+
+``` js
+const renderer = createBundleRenderer(serverBundle, {
+  template,
+  clientManifest,
+  shouldPreload: (file, type) => {
+    // type is inferred based on the file extension.
+    // https://fetch.spec.whatwg.org/#concept-request-destination
+    if (type === 'script' || type === 'font') {
+      return true
+    }
+    if (type === 'image') {
+      // only preload important images
+      return file === 'hero.jpg'
+    }
+  }
+})
+```
+
+---
+
 ### directives
 
 Allows you to provide server-side implementations for your custom directives:
@@ -307,6 +356,74 @@ module.exports = {
 
 Since externalized modules will be shared across every request, you need to make sure that the dependency is **idempotent**. That is, using it across different requests should always yield the same result - it cannot have global state that may be changed by your application. Interactions between externalized modules are fine (e.g. using a Vue plugin).
 
+## Creating the Client Manifest
+
+`vue-server-renderer` 2.2 supports rendering the entire HTML page with the `template` option. 2.3 introduces another new feature, which allows us to pass a manifest of our client-side build to the `bundleRenderer`. This provides the renderer with information of both the server AND client builds, so it can automatically infer and inject preload / prefetch directives and script tags into the rendered HTML. This is particularly useful when rendering a bundle that leverages webpack's on-demand code splitting features: we can ensure the right chunks are preloaded / prefetched, and also directly embed `<script>` tags for needed async chunks in the HTML to avoid waterfall requests on the client, thus improving TTI (time-to-interactive).
+
+To generate a client manifest, you need to add the client plugin to your client webpack config. In addition:
+
+- Make sure to use `CommonsChunkPlugin` to split the webpack runtime into its own entry chunk, so that async chunks can be injected **after** the runtime and **before** your main app code.
+
+- Since in this case `vue-server-renderer` will be dynamically injecting the asset links, you don't need to use `html-webpack-plugin`. However, the setup only handles JavaScript. If you want to use `html-webpack-plugin` for embedding other types of assets (e.g fonts), you can still use it - just make sure to configure it with `inject: false` so that it doesn't duplicate-inject the scripts.
+
+``` js
+// in your webpack client bundle config
+const webpack = require('webpack')
+const { VueSSRClientPlugin } = require('vue-ssr-webpack-plugin')
+
+module.exports = {
+  // ...
+  plugins: [
+    // this splits the webpack runtime into a leading chunk
+    // so that async chunks can be injected right after it.
+    // this also enables better caching for your app/vendor code.
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'manifest',
+      minChunks: Infinity
+    }),
+    // this will generate the client manifest JSON file.
+    new VueSSRClientPlugin()
+  ]
+}
+```
+
+This will generate an additional `vue-ssr-client-manifest.json` file in your build output. Simply require and pass it to the `bundleRenderer`:
+
+``` js
+const { createBundleRenderer } = require('vue-server-renderer')
+
+const template = require('fs').readFileSync('/path/to/template.html', 'utf-8')
+const serverBundle = require('/path/to/vue-ssr-bundle.json')
+const clientManifest = require('/path/to/vue-ssr-client-manifest.json')
+
+const renderer = createBundleRenderer(serverBundle, {
+  template,
+  clientManifest
+})
+```
+
+With this setup, your server-rendered HTML for a build with code-splitting will look something like this:
+
+``` html
+<html><head>
+  <!-- chunks used for this render should have preload -->
+  <link rel="preload" href="/manifest.js" as="script">
+  <link rel="preload" href="/main.js" as="script">
+  <link rel="preload" href="/0.js" as="script">
+  <!-- unused async chunks should have prefetch -->
+  <link rel="prefetch" href="/1.js" as="script">
+</head><body>
+  <div data-server-rendered="true"><div>async</div></div>
+  <!-- manifest chunk should be first -->
+  <script src="/manifest.js"></script>
+  <!-- async chunks should be before main chunk -->
+  <script src="/0.js"></script>
+  <script src="/main.js"></script>
+</body></html>`
+```
+
+You can also control precisely what to preload with the [shouldPreload](#shouldpreload) option.
+
 ## Component Caching
 
 You can easily cache components during SSR by implementing the `serverCacheKey` function: