我一直在努力使我的vuejs应用程序与SSR功能良好,但我的所有尝试都失败了.我真的需要帮助.
请注意,我使用普通的js文件,而不是使用es6的.vue文件,并且需要使用webpack require函数的html模板.
该应用程序在开发模式下工作正常,但是,当我使用'vue-server-renderer'开始执行它并转到任何路由时,将抛出此错误:
错误:在组件中未定义渲染函数或模板:在presentationComponent(/ Users/salaahassi /)上的normalizeRender(/Users/salaahassi/dev/vue/magicum/node_modules/vue-server-renderer/build.js:6015:13)中匿名dev/vue/magicum/node_modules/vue-server-renderer/build.js:6081:3)在renderNode(/Users/salaahassi/dev/vue/magicum/node_modules/vue-server-renderer/build.js:6065: 7)在渲染(/Users/salaahassi/dev/vue/magicum/node_modules/vue-server-renderer/build.js:6257:5)RenderStream.render(/ Users/salaahassi/dev/vue/magicum/node_modules /) vue-server-renderer/build.js:6312:9)RenderStream.tryRender(/Users/salaahassi/dev/vue/magicum/node_modules/vue-server-renderer/build.js:96:12)在RenderStream._read (/ Users/salaahassi/dev/vue/magicum/node_modules/vue-server-renderer/build.js:125:12)在RenderStream.Readable.read(_stream_readable.js:348:10)的resume_(_ stream_readable.js: 737:12)在_combinedTickCallback(internal/process/next_tick.js:74:11)
此外,当我在我的浏览器上禁用javascript时,即使主页也会消失(当然这是因为它不能通过SSR工作).
这是我的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;
这是我的服务器条目文件:
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 }) }
这是我的server.js:
'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( `` ) } 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}`) })
小智.. 5
您的index.html
模板是否有占位符?
您的index.html
模板是否有占位符?