【问题标题】:Vue CLI and Server-Side RenderingVue CLI 和服务器端渲染
【发布时间】:2018-12-13 19:00:40
【问题描述】:

我正在使用 Vue CLI,它使用 main.js 来挂载应用程序,而不是使用 app.js、entry-client.js 和 entry-server 的服务器端渲染(根据我遵循的教程 here)。 js.

我试图绕过 main.js,但我遇到了一个错误,因为它似乎需要一些方法。

我如何才能将 main.js 与 app.js、entry-client.js 和 entry-server.js 保持一致。

这可能是一个非常基本的问题,我可能会在 main.js 中使用 app.js 的内容,因为我想做正确的事情。

main.js:

import Vue from 'vue'
import bootstrap from 'bootstrap'
import App from './App.vue'
import router from './router'
import store from './store'
import VueResource from 'vue-resource'
import BootstrapVue from 'bootstrap-vue'
import './registerServiceWorker'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'

Vue.config.productionTip = false
Vue.use(VueResource)
Vue.use(BootstrapVue)

new Vue({
  bootstrap,
  router,
  store,
  render: h => h(App)
}).$mount('#app')

app.js:

import Vue from 'vue'
import App from './App.vue'
import bootstrap from 'bootstrap'
import { createRouter } from './router'
import store from './store'
import VueResource from 'vue-resource'
import BootstrapVue from 'bootstrap-vue'
import './registerServiceWorker'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'

Vue.config.productionTip = false
Vue.use(VueResource)
Vue.use(BootstrapVue)

export function createApp () {
    // create router instance
    const router = createRouter()

    const app = new Vue({
        bootstrap,
        router,
        store,
        render: h => h(App)
    })

    return { app, bootstrap, router, store }
}

服务器客户端.js

import { createApp } from './app'

const { app, router } = createApp()

router.onReady(() => {
    app.$mount('#app')
})

entry-server.js

import { createApp } from './app'

export default context => {
    // since there could potentially be asynchronous route hooks or components,
    // we will be returning a Promise so that the server can wait until
    // everything is ready before rendering.
    return new Promise((resolve, reject) => {
        const { app, router } = createApp()

        // set server-side router's location
        router.push(context.url)

        // wait until router has resolved possible async components and hooks
        router.onReady(() => {
            const matchedComponents = router.getMatchedComponents()
            // no matched routes, reject with 404
            if (!matchedComponents.length) {
                return reject({ code: 404 })
            }

            // the Promise should resolve to the app instance so it can be rendered
            resolve(app)
        }, reject)
    })
}

非常感谢任何帮助。

【问题讨论】:

    标签: javascript node.js vue.js


    【解决方案1】:

    我刚刚找到了方法。默认情况下,Vue CLI 3 没有 vue.config.js。我必须在文件夹的根目录创建一个来覆盖设置为/src/main.js 的条目。

    我使用了在这个github 上找到的vue.config.js 并将entry 写入到./src/entry-${target}

    const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
    const VueSSRClientPlugin = require('vue-server-renderer/client-plugin')
    const nodeExternals = require('webpack-node-externals')
    const merge = require('lodash.merge')
    
    const TARGET_NODE = process.env.WEBPACK_TARGET === 'node'
    
    const createApiFile = TARGET_NODE 
      ? './create-api-server.js'
      : './create-api-client.js'
    
    const target = TARGET_NODE 
      ? 'server' 
      : 'client'
    
    module.exports = {
      configureWebpack: () => ({
        entry: `./src/entry-${target}`,
        target: TARGET_NODE ? 'node' : 'web',
        node: TARGET_NODE ? undefined : false,
        plugins: [
          TARGET_NODE 
            ? new VueSSRServerPlugin()
            : new VueSSRClientPlugin()
        ],
        externals: TARGET_NODE ? nodeExternals({
          whitelist: /\.css$/
        }) : undefined,
        output: {
          libraryTarget: TARGET_NODE 
            ? 'commonjs2' 
            : undefined
        },
        optimization: {
          splitChunks: undefined
        },
        resolve:{
          alias: {
            'create-api': createApiFile
          }
        }
      }),
      chainWebpack: config => {
        config.module
        .rule('vue')
        .use('vue-loader')
        .tap(options =>
          merge(options, {
            optimizeSSR: false
          })
        )
      }
    }
    

    【讨论】: