2017-01-13 8 views
1

Ich habe daran gearbeitet, meine Vuejs App funktioniert gut mit SSR, aber alle meine Versuche gescheitert. Ich brauche wirklich Hilfe dabei.Vuejs 2 Server-Side-Rendering - funktioniert nicht

Bitte beachten Sie, dass ich normale js-Dateien nicht .vue-Dateien mit es6 verwenden und die HTML-Vorlagen mit Webpack erfordern Funktion benötigen.

Die App arbeitet im Entwicklungsmodus in Ordnung, aber wenn ich es starten ausführen 'vue-Server-Renderer' mit und gehen Sie zu jeder Route, wird dieser Fehler ausgelöst:

Error: render function or template not defined in component: anonymous at normalizeRender (/Users/salaahassi/dev/vue/magicum/node_modules/vue-server-renderer/build.js:6015:13) at renderComponent (/Users/salaahassi/dev/vue/magicum/node_modules/vue-server-renderer/build.js:6081:3) at renderNode (/Users/salaahassi/dev/vue/magicum/node_modules/vue-server-renderer/build.js:6065:7) at render (/Users/salaahassi/dev/vue/magicum/node_modules/vue-server-renderer/build.js:6257:5) at RenderStream.render (/Users/salaahassi/dev/vue/magicum/node_modules/vue-server-renderer/build.js:6312:9) at RenderStream.tryRender (/Users/salaahassi/dev/vue/magicum/node_modules/vue-server-renderer/build.js:96:12) at RenderStream._read (/Users/salaahassi/dev/vue/magicum/node_modules/vue-server-renderer/build.js:125:12) at RenderStream.Readable.read (_stream_readable.js:348:10) at resume_ (_stream_readable.js:737:12) at _combinedTickCallback (internal/process/next_tick.js:74:11)

Auch wenn Ich deaktiviere Javascript in meinem Browser, sogar die Homepage wird verschwinden (das ist natürlich, weil es nicht vom SSR funktioniert).

Hier ist mein webpack:

var path = require('path') 
var webpack = require('webpack') 
var HTMLPlugin = require('html-webpack-plugin'); 
var CopyWebpackPlugin = require('copy-webpack-plugin'); 
var ExtractTextPlugin = require("extract-text-webpack-plugin"); 
var extractCSS = new ExtractTextPlugin('styles.css'); 

var options = { 
    // entry: './entry.client.js', 
    entry: { 
    app: './entry.client.js', 
    vendor: [ 
     'vue', 
     'vue-router', 
     'vuex', 
     'vuex-router-sync', 
     'moment', 
     'axios' 
    ] 
    }, 
    output: { 
    path: path.resolve(__dirname, './dist'), 
    publicPath: '/', 
    filename: '[name].[hash].js', 
    }, 
    module: { 
    noParse: /es6-promise\.js$/, // avoid webpack shimming process 
    rules: [ 
     { 
     test: /\.html$/, 
     loader: 'raw-loader' 
     }, 
     { 
     test: /\.js$/, 
     loader: 'babel-loader', 
     exclude: /node_modules/ 
     }, 
     { 
     test: /\.json$/, 
     loader: 'json-loader' 
     }, 
     { 
     test: /\.(png|jpg|gif|svg|woff|woff2|eot|ttf)$/, 
     loader: 'file-loader', 
     options: { 
      name: '[name].[ext]?[hash]' 
     } 
     }, 
     { 
     test: /\.scss$/, 
     loader: extractCSS.extract('css-loader!sass-loader') 
     } 
    ] 
    }, 
    plugins: [ 
    extractCSS, 
    new webpack.ContextReplacementPlugin(/moment[\\\/]locale$/, /^\.\/(en|zh-tw)$/), 
    new webpack.DefinePlugin({ 
     'process.env': { 
      'NODE_ENV': JSON.stringify(process.env.NODE_ENV) || 'development', 
      'VUE_ENV': JSON.stringify(process.env.VUE_ENV) || 'client', 
     } 
    }) 
    ], 
    resolve: { 
    alias: { 
     'vue$': 'vue/dist/vue' 
    } 
    }, 
    devServer: { 
    historyApiFallback: true, 
    noInfo: true 
    }, 
    devtool: '#eval-source-map' 
} 
console.log("xxxxx ---node env---- xxxx", process.env.NODE_ENV); 
console.log("xxxxx ---vue env---- xxxx", process.env.VUE_ENV); 
if (process.env.NODE_ENV != 'development') { 
    options.entry = './entry.server.js'; 
    options.target = 'node'; 
    options.output.filename = 'bundle-server.js'; 
    options.output.libraryTarget = 'commonjs2'; 
    options.externals = Object.keys(require('./package.json').dependencies); 
} 

if (process.env.NODE_ENV == 'development') { 
    options.plugins = (options.plugins || []).concat([ 
    new HTMLPlugin({ 
     template: './index.html' 
    }), 
    // extract vendor chunks for better caching 
    new webpack.optimize.CommonsChunkPlugin({ 
     name: 'vendor' 
    }) 
    ]); 
} 

if (process.env.VUE_ENV == 'server') { 
    options.devtool = '#source-map' 
    options.plugins = (options.plugins || []).concat([ 
    new webpack.optimize.UglifyJsPlugin({ 
     //sourceMap: true, 
     compress: { 
     warnings: false 
     } 
    }), 
    new webpack.LoaderOptionsPlugin({ 
     minimize: true 
    }), 
    new CopyWebpackPlugin([ 
     {from: './assets', to: 'assets'}, 
     {from: './index.html'} 
    ]) 
    ]) 
} 

module.exports = options; 

Und hier ist meine Server-Eintrag Datei:

'use strict' 
const fs = require('fs') 
const path = require('path') 
const resolve = file => path.resolve(__dirname, file) 
const express = require('express') 
// const favicon = require('serve-favicon') 
const serialize = require('serialize-javascript') 

const createBundleRenderer = require('vue-server-renderer').createBundleRenderer 

const app = express() 

// parse index.html template 
const template = fs.readFileSync(resolve('./dist/index.html'), 'utf-8') 


// create server renderer from real fs 
const bundlePath = resolve('./dist/bundle-server.js') 
let renderer = createRenderer(fs.readFileSync(bundlePath, 'utf-8')) 
console.log(renderer); 
function createRenderer (bundle) { 
    return createBundleRenderer(bundle, { 
    cache: require('lru-cache')({ 
     max: 1000, 
     maxAge: 1000 * 60 * 15 
    }) 
    }) 
} 

var options = { 
    maxAge: '60d', 
    setHeaders: function(res, path, stat) { 
     // Webfonts need to have CORS * set in order to work. 
     if (path.match(/ttf|woff|woff2|eot|svg/ig)) { 
      res.set('Access-Control-Allow-Origin', '*'); 
     } 
    } 
}; 

var dist_path = '/dist/'; 
app.use(express.static(path.join(__dirname, dist_path), options)); 
console.log("............"); 
app.get('*', (req, res) => { 
    console.log(".....ROUTE.......", req.url); 
    console.log('renderer', renderer); 
    if (!renderer) { 
    return res.end('waiting for compilation... refresh in a moment.') 
    } 
    var s = Date.now() 
    const context = { url: req.url } 
    const renderStream = renderer.renderToStream(context) 
    let firstChunk = true 
    // console.log(html.head); 
    // res.write(html.head) 

    renderStream.on('data', chunk => { 
    if (firstChunk) { 
     // embed initial store state 
     if (context.initialState) { 
     res.write(
      `<script>window.__INITIAL_STATE__=${ 
      serialize(context.initialState, { isJSON: true }) 
      }</script>` 
     ) 
     } 
     firstChunk = false 
    } 
    res.write(chunk) 
    }) 

    renderStream.on('end',() => { 
    res.end(template) 
    console.log(`whole request: ${Date.now() - s}ms`) 
    }) 

    renderStream.on('error', err => { 
    throw err 
    }) 
}) 

const port = process.env.PORT || 3000 
app.listen(port,() => { 
    console.log(`server started at http://localhost:${port}`) 
}) 
+0

Haben Sie versuchen, diese config von webpack zu entfernen: '' ' resolve: { alias: { 'vue $': 'vue/dist/vue' } }, ' '' – imcvampire

Antwort

0

Hat Ihre index.html Vorlage hat:

import { app, router, store } from './src/app' 

export default context => { 
    // set router's location 
    router.push(context.url) 
    // call prefetch hooks on components matched by the route 
    const s = Date.now() 
    return Promise.all(router.getMatchedComponents().map(component => { 
    if (component.prefetch) { 
     return component.prefetch(store) 
    } 
    })).then(() => { 
    console.log(`data pre-fetch: ${Date.now() - s}ms`) 
    // set initial store on context 
    // the request handler will inline the state in the HTML response. 
    context.initialState = store.state 
    return app 
    }) 
} 

Hier mein server.js ist der Platzhalter <!--vue-ssr-outlet-->?

index.html

+0

Wenn die index.html Vorlage nicht '_placeholder_ hat, würde die App' Error: Content placeholder not in template.' werfen – Webdevotion

Verwandte Themen