lbwa / set.sh-stale

✍A place which is used to share my programming experiences in Chinese. 一个分享代码经历的地方。
https://set.sh
0 stars 0 forks source link

开发时 SSR server 端静态资源的路径处理 #13

Open lbwa opened 6 years ago

lbwa commented 6 years ago

缘由

在 SSR server 中可通过 ajax 请求 client server 获得渲染信息。

// ctx 为 koa 请求生成的 context 对象,它作为中间件的接收器,这里即作为渲染上下文使用
const handleSSR = async (ctx) => {
  // ...

  // 获取客户端构建清单,即客户端 bundle(另一个 server 的数据)
  // vue-ssr-client-manifest.json 是 webpack.dev.config 中 VueClientPlugin 默认生成文件名
  const clientManifestResp = await axios.get(
    // http://koajs.com/#context
    // 因为 Koa 将 Node request 对象封装至 ctx 上,所以此处 ctx 对象被赋予了请求地址,即此时存在了 ctx.path(ctx.request.path 的别名)
    'http://127.0.0.1:8080/public/vue-ssr-client-manifest.json'
  )

  // 在 await resolved 后,即得到 clientManifestResp,继续执行
  const clientManifest = clientManifestResp.data

  // ...
}

因为 SSR server 中 HTML 的 script 地址是渲染自 client server 中 HTML 的 script 地址(server-render.jscontext.url 和插入的 scripts 标签配置),那么 SSR server 在访问 client server 的静态资源 'a.js' 时的地址也是和 client server 访问 a.js 的地址相同,即 '/自定义基路径/a.js',那么 SSR server 在访问 'a.js' 时,SSR server 实际访问的地址也是 '/自定义基路径/a.js',那么自然 SSR server 无法正确访问到 client server 静态资源 a.js 的正确地址。

(以上隐含了一个服务端没有跨域限制的知识点)

配置:

// SSR server 渲染请求地址
const context = { url: ctx.path }

// ...

const html = ejs.render(template, {
  // ...

  /**
   * 1. context.renderScripts() 返回引导客户端应用所需的 <script> 标签
   * 2. 需要 clientManifest,即客户端 bundle
   * 3. 此处插入的地址将与 client server 插入的 script 标签地址一样
   */
  scripts: context.renderScripts()
})

解决方案:

  1. webpack.server.config.js 设置代理,即 SSR server 设置代理。

  2. 直接设置补全 client server 访问静态资源地址,即将 '/自定义基路径' 补全为 'http://127.0.0.1:8080',那么此时不管是 client server 还是 SSR server 访问 a.js 的地址都是一个源下的静态资源,即 client server 下的静态资源。(点我查看示例配置,其中 webpack output 地址必须引用该配置中的 assetPublicPath)