为了简化这些,你可以直接在创建renderer时提供一个页面模板。多数时候,我们会将页面模板放在特有的文件中:
- <!DOCTYPE html>
- <html lang="en">
- <head><title>Hello</title></head>
- <body>
- <!--vue-ssr-outlet-->
- </body>
- </html>
然后,我们可以读取和传输文件到Vue renderer中:
- const tpl = fs.readFileSync(path.resolve(__dirname, './index.html'), 'utf-8');
- const renderer = vssr.createRenderer({
- template: tpl,
- });
Webpack配置
然而在实际项目中,不止上述例子那么简单,需要考虑很多方面:路由、数据预取、组件化、全局状态等,所以服务端渲染不是只用一个简单的模板,然后加上使用vue-server-renderer完成的,如下面的示意图所示:
如示意图所示,一般的Vue服务端渲染项目,有两个项目入口文件,分别为entry-client.js和entry-server.js,一个仅运行在客户端,一个仅运行在服务端,经过Webpack打包后,会生成两个Bundle,服务端的Bundle会用于在服务端使用虚拟DOM生成应用程序的“快照”,客户端的Bundle会在浏览器执行。
因此,我们需要两个Webpack配置,分别命名为webpack.client.config.js和webpack.server.config.js,分别用于生成客户端Bundle与服务端Bundle,分别命名为vue-ssr-client-manifest.json与vue-ssr-server-bundle.json,关于如何配置,Vue官方有相关示例vue-hackernews-2.0
开发环境搭建
我所在的项目使用Koa作为Web Server Frame,项目使用koa-webpack进行开发环境的构建。如果是在产品环境下,会生成vue-ssr-client-manifest.json与vue-ssr-server-bundle.json,包含对应的Bundle,提供客户端和服务端引用,而在开发环境下,一般情况下放在内存中。使用memory-fs模块进行读取。
- const fs = require('fs')
- const path = require( 'path' );
- const webpack = require( 'webpack' );
- const koaWpDevMiddleware = require( 'koa-webpack' );
- const MFS = require('memory-fs');
- const appSSR = require('./../../app.ssr.js');
- let wpConfig;
- let clientConfig, serverConfig;
- let wpCompiler;
- let clientCompiler, serverCompiler;
- let clientManifest;
- let bundle;
- // 生成服务端bundle的webpack配置
- if ((fs.existsSync(path.resolve(cwd,'webpack.server.config.js')))) {
- serverConfig = require(path.resolve(cwd, 'webpack.server.config.js'));
- serverCompiler = webpack( serverConfig );
- }
- // 生成客户端clientManifest的webpack配置
- if ((fs.existsSync(path.resolve(cwd,'webpack.client.config.js')))) {
- clientConfig = require(path.resolve(cwd, 'webpack.client.config.js'));
- clientCompiler = webpack(clientConfig);
- }
- if (serverCompiler && clientCompiler) {
- let publicPath = clientCompiler.output && clientCompiler.output.publicPath;
- const koaDevMiddleware = await koaWpDevMiddleware({
- compiler: clientCompiler,
- devMiddleware: {
- publicPath,
- serverSideRender: true
- },
- });
- app.use(koaDevMiddleware);
- // 服务端渲染生成clientManifest
- app.use(async (ctx, next) => {
- const stats = ctx.state.webpackStats.toJson();
- const assetsByChunkName = stats.assetsByChunkName;
- stats.errors.forEach(err => console.error(err));
- stats.warnings.forEach(err => console.warn(err));
- if (stats.errors.length) {
- console.error(stats.errors);
- return;
- }
- // 生成的clientManifest放到appSSR模块,应用程序可以直接读取
- let fileSystem = koaDevMiddleware.devMiddleware.fileSystem;
- clientManifest = JSON.parse(fileSystem.readFileSync(path.resolve(cwd,'./dist/vue-ssr-client-manifest.json'), 'utf-8'));
- appSSR.clientManifest = clientManifest;
- await next();
- });
- // 服务端渲染的server bundle 存储到内存里
- const mfs = new MFS();
- serverCompiler.outputFileSystem = mfs;
- serverCompiler.watch({}, (err, stats) => {
- if (err) {
- throw err;
- }
- statsstats = stats.toJson();
- if (stats.errors.length) {
- console.error(stats.errors);
- return;
- }
- // 生成的bundle放到appSSR模块,应用程序可以直接读取
- bundle = JSON.parse(mfs.readFileSync(path.resolve(cwd,'./dist/vue-ssr-server-bundle.json'), 'utf-8'));
- appSSR.bundle = bundle;
- });
- }
渲染中间件配置 (编辑:南平站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|