Vue.js Vue SSR将express server与Vue应用程序捆绑在一起,以便应用程序可以从复制到主机服务器的build dist文件夹运行
我已经创建了一个Vue SSR应用程序,我只读的所有说明/维基/博客都会告诉您如何在开发环境中运行该应用程序。它们不会告诉您如何在生产环境中运行应用程序 我以前在React SSR应用程序中编写过相同的应用程序。在该应用程序中,构建生成一个“dist”文件夹,其中包含捆绑包“server_bundle.js”。此捆绑包包含Express服务器(server.js)和React代码。我可以在“dist”文件夹中使用Vue.js Vue SSR将express server与Vue应用程序捆绑在一起,以便应用程序可以从复制到主机服务器的build dist文件夹运行,vue.js,server-side-rendering,Vue.js,Server Side Rendering,我已经创建了一个Vue SSR应用程序,我只读的所有说明/维基/博客都会告诉您如何在开发环境中运行该应用程序。它们不会告诉您如何在生产环境中运行应用程序 我以前在React SSR应用程序中编写过相同的应用程序。在该应用程序中,构建生成一个“dist”文件夹,其中包含捆绑包“server_bundle.js”。此捆绑包包含Express服务器(server.js)和React代码。我可以在“dist”文件夹中使用 node dist/server_bundle.js 在Vue SSR应用程序中
node dist/server_bundle.js
在Vue SSR应用程序中,构建还生成一个“dist”文件夹。但是,它包含一个“vue ssr bundle.json”文件,其中不包括express服务器(server.js)。要在开发中运行应用程序,我必须使用位于项目根目录中的Express server文件,而不是从“dist”目录运行所有内容
node ./server.js
这在开发中是可以的,因为我在我的项目中工作,但在生产中这将不起作用,因为我必须从“dist”文件夹运行所有内容
构建和运行
该应用程序是使用以下命令构建的(在devi中添加“--watch”参数)
这些生成脚本创建并填充dist(服务器)和public(客户端)文件夹
要运行应用程序,我使用
node ./server.js"
请注意,我正在项目的根目录中使用“server.js”。它不在dist文件夹中
问题
那么,如果应用程序没有我的项目代码,它只有我的构建生成的“dist”和“public”文件夹,我将如何在生产环境中运行该应用程序?
我的代码
项目结构
project_root
- src
- assets
- any static images, such as "myImage.jpg"
- client
- client_main.js
- components
- lots of files
- pages
- components which are top level pages
- server
- server_main.js
- vuex
- folders and files containing code pertaining to vuex
- app.js
- App.vue
- router.js
- index.html (the template html file to have content inserted into)
- server.js (the Express Server file)
- webpack.base.config.js
- webpack.client.config.js
- webpack.server.config.js
src/client/client_main.js
import { createApp } from '../app'
const { app, router, store } = createApp()
...
router.onReady(() => {
app.$mount('#app')
})
src/server/server_main.js
import { createApp } from '../app'
export default context => {
return new Promise((resolve, reject) => {
const { app, router, store } = createApp()
router.push(context.url)
router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
if (!matchedComponents.length) {
return reject({ code: 404 })
}
resolve(app)
}, reject)
})
}
src/app.js
import Vue from 'vue'
import App from './App.vue'
import { createStore } from './vuex/store'
import { createRouter } from './router'
import { sync } from 'vuex-router-sync'
export function createApp () {
const store = createStore()
const router = createRouter()
sync(store, router)
const app = new Vue({
router,
store,
render: h => h(App)
})
return { app, router, store }
}
server.js
const fs = require('fs');
const express = require('express');
const { createBundleRenderer } = require('vue-server-renderer');
const bundleRenderer = createBundleRenderer(
require('./dist/vue-ssr-bundle.json'),
{
template: fs.readFileSync('./index.html', 'utf-8')
}
);
const server = express();
server.use(express.static('public'));
server.get('*', (req, res) => {
const context = { url: req.url }
bundleRenderer.renderToString(context, (err, html) => {
if (err) {
if (err.code === 404) {
res.status(404).end('Page not found')
} else {
res.status(500).end('Internal Server Error')
}
} else {
res.end(html)
}
})
});
server.listen(8080);
webpack.base.config.js
const webpack = require('webpack')
module.exports = {
module: {
rules: I wont put them all here to reduce noise, but i am using 'vue-loader', 'babel-loader''file-loader'
},
resolve: {
alias: {'vue$': 'vue/dist/vue.esm.js'},
extensions: ['*', '.js', '.vue', '.json']
},
performance: {
hints: false
},
}
webpack.client.js
var path = require('path')
const merge = require('webpack-merge');
const baseConfig = require('./webpack.base.config.js');
const config = {
entry: './src/client/main.js',
output: {
filename: 'client-bundle.js',
path: path.resolve(__dirname, 'public'),
},
module: {
rules: I wont put them all here to reduce noise, but i am using 'vue-style-loader', 'css-loader'
},
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
devtool: '#eval-source-map'
}
module.exports = merge(baseConfig, config);
webpack.server.js
const path = require('path')
const merge = require('webpack-merge');
const baseConfig = require('./webpack.base.config.js');
const webpackNodeExternals = require('webpack-node-externals');
const VueSSRPlugin = require('vue-ssr-webpack-plugin')
const config = {
target: 'node',
entry: './src/server/main.js',
output: {
filename: 'server-bundle.js',
path: path.resolve(__dirname, './dist'),
libraryTarget: 'commonjs2'
},
externals: [webpackNodeExternals()],
devtool: '#source-map',
plugins: [
new VueSSRPlugin(),
]
}
module.exports = merge(baseConfig, config);
我尝试的
我希望服务器构建会像React一样将Express server与Vue应用程序代码捆绑在一起,因此我只需要从dist文件夹中运行捆绑包。我认为这是一个更好更干净的解决方案
我尝试将Vue应用程序更改为像React应用程序一样构建和运行,但未成功
删除VueSSRPlugin
我删除了webpack.server.config.js中的VueSSRPlugin引用,并看到在“dist”文件中,我现在有了包和图像,就像React一样。但是,此捆绑包中仍然没有Express server。我仍然不知道如何在dist文件夹中获取express服务器
将express文件移到src/server文件夹中
我考虑将express文件(server.js)移动到我的项目源代码中,希望它能添加到包中。但是,我不知道如何更改express文件,因为它引用了express服务器文件最终所在的JSON文件。我通过将以下内容复制到我的服务器,暂时解决了这个问题
- server-bundle.js
- index.html
- server.js
- “dist”文件夹(包含服务器包)
- “公共”文件夹(包含客户端包、样式表和其他文件)
node server.js
由于server.js和index.html已复制到服务器上
我仍然更喜欢React的构建方式,以便express server.js文件和index.html位于服务器捆绑包中,但至少这是可行的。我使用React SSR来确定如何将所有Vue SSR应用程序(包括express server)捆绑到服务器捆绑包中 这个解决方案的缺点是我不能再使用“index.html”模板和“bundlerender” 此解决方案的优点是,express服务器现在可以使用WebPack配置中设置的变量 项目结构 我的项目结构如下。我将express服务器文件移到src/server文件夹中,并删除了“index.html”文件 网页包配置更改 “webpack.base.config.js”不再需要
devtool: '#source-map',
“webpack.server.config.js”不再需要“VueSSRPlugin”,因此可以删除以下内容
const VueSSRPlugin = require('vue-ssr-webpack-plugin');
plugins: [
new VueSSRPlugin(),
],
将服务器条目更改为express服务器文件
entry: './src/server/server.js',
服务器主文件:src/Server/Server_main.js
返回VUEX应用商店和Vue应用程序。这是因为我们必须手动提取存储数据,序列化它并将其添加到返回给客户端的HTML中
import createApp from '../app';
export default (context) => new Promise((resolve, reject) => {
const { app, router, store } = createApp();
router.push(context.url);
router.onReady(() => {
const matchedComponents = router.getMatchedComponents();
if (!matchedComponents.length) {
return reject(new Error('404'));
}
context.rendered = () => {
context.state = store.state;
};
return resolve({ app, store });
}, reject);
});
import generateApp from './server_main.js';
import renderer from './renderer';
const express = require('express');
const vueServerRenderer = require('vue-server-renderer').createRenderer();
const server = express();
server.use(express.static('public'));
server.get('*', (req, res) => {
const context = { url: req.url };
generateApp(context).then((createdAppObj) => {
const { app, store } = createdAppObj;
vueServerRenderer.renderToString(
app,
(err, html) => {
if (err) {
if (err.code === 404) {
res.status(404).end('Page not found');
} else {
res.status(500).end('Internal Server Error');
}
} else {
// BUILD UP THE HTML TO RETURN
const content = renderer(store, html);
res.send(content);
}
},
);
});
});
server.listen(8080);
创建一个renderer.js文件,负责生成返回到客户端的HTML(即index.HTML的替换)
注意:您不必为此设置单独的文件,如果需要,可以将此代码包含在express server文件中
package.json更改
现在,当所有内容都构建好后,“dist”目录将包含以下内容
- server-bundle.js
这包含作为条目文件的express server文件,因此无法运行您执行的应用程序
node ./server.js
此解决方案的一个优点:Express Server可以使用在WebPack config中设置的变量
Vue支持使用模板插值将变量添加到“index.html”模板中,请参阅
然而,在我的例子中,我需要在我的网页配置中使用一个变量设置来放入“index.html”
我的网页包配置从“.env”文件设置变量,然后在我的Vue应用程序中使用该文件。我需要在我的“index.html”中的这个“.env”文件中使用一个变量。由于Express Server没有被Web包解析和绑定,因此它不会设置变量。我必须读取Express Server文件中的“.env”文件。这意味着我还必须有“.env”express server文件所在的生产环境中的文件,以便从中读取 根据此评论中所述的更改,网页
import generateApp from './server_main.js';
import renderer from './renderer';
const express = require('express');
const vueServerRenderer = require('vue-server-renderer').createRenderer();
const server = express();
server.use(express.static('public'));
server.get('*', (req, res) => {
const context = { url: req.url };
generateApp(context).then((createdAppObj) => {
const { app, store } = createdAppObj;
vueServerRenderer.renderToString(
app,
(err, html) => {
if (err) {
if (err.code === 404) {
res.status(404).end('Page not found');
} else {
res.status(500).end('Internal Server Error');
}
} else {
// BUILD UP THE HTML TO RETURN
const content = renderer(store, html);
res.send(content);
}
},
);
});
});
server.listen(8080);
- server-bundle.js
node ./server.js