pbonnefoi
pbonnefoi

Reputation: 275

Vue CLI and Server-Side Rendering

I'm using Vue CLI which uses main.js to mount the app versus Server-Side Rendering (according to the tutorial I follow here) which uses app.js, entry-client.js and entry-server.js.

I tried to bypass main.js, but I'm having an error since its seems its required some how.

How can I work to keep main.js with app.js, entry-client.js and entry-server.js.

It might be a very basic question and I could maybe use the content of app.js in main.js, be I want to do things right.

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 }
}

server-client.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)
    })
}

Any help is greatly appreciated.

Upvotes: 3

Views: 2227

Answers (1)

pbonnefoi
pbonnefoi

Reputation: 275

I just found how. By default, Vue CLI 3 comes with no vue.config.js. I had to create one at the root of the folder to override the entry which was set to /src/main.js.

I used the vue.config.js found on this github and onverwrittes the entry to ./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
      })
    )
  }
}

Upvotes: 3

Related Questions