Skip to content

03源码结构

源码结构

避免状态单例

当编写纯客户端client-only 代码时,我们习惯于每次在新的上下文中取值。但node服务器是一个长期运行的进程,当我们的代码进入该进程时,它将进行一次取值并留存在内存中。这意味着如果创建一个单例对象,它将在每个传入的请求之间共享。

如示例,我们为每个请求创建一个新的根Vue实例,这与每个用户在自己的浏览器中使用新应用程序的实例类似。如果我们在多个请求之间使用一个共享的实例,很容易导致交叉请求状态污染(cross-request state pollution)。因此,我们不应该直接创建一个应用程序实例,而是应该暴露一个可以重复执行的工厂函数,为每个请求创建新的应用程序实例:

js
const Vue = require('vue')

export default function createApp(context) {
  return new Vue({
    data: {
      url: context.url
    },
    template: `<div>访问的url是: {{url}}</div>`
  })
}

并将服务器代码变为:

js
const createApp = require('./app')
server.get('*', (req, res) => {
  const context = {url: req.url}
  const app = createApp(context)
  renderer.renderToString(app, (err, html) => {
    // 错误处理
    res.end(html)
  })
})

同样的规则也适用于 router、store 和 event bus 实例。你不应该直接从模块导出并将其导入到应用程序中,而是需要在 createApp 中创建一个新的实例,并从根 Vue 实例注入。

在使用带有 { runInNewContext: true } 的 bundle renderer 时,可以消除此约束,但是由于需要为每个请求创建一个新的 vm 上下文,因此伴随有一些显著性能开销。

介绍构建步骤

到目前为止,我们还没有讨论过如何将相同的 Vue 应用程序提供给客户端。为了做到这一点,我们需要使用 webpack 来打包我们的 Vue 应用程序。事实上,我们可能需要在服务器上使用 webpack 打包 Vue 应用程序,因为:

  • 通常 Vue 应用程序是由 webpack 和 vue-loader 构建,并且许多 webpack 特定功能不能直接在 Node.js 中运行(例如通过 file-loader 导入文件,通过 css-loader 导入 CSS)

  • 尽管 Node.js 最新版本能够完全支持 ES2015 特性,我们还是需要转译客户端代码以适应老版浏览器。这也会涉及到构建步骤

<img src="https://cloud.githubusercontent.com/assets/499550/17607895/786a415a-5fee-11e6-9c11-45a2cfdf085c.png">

共 20 个模块,1301 篇 Markdown 文档。