Skip to content
On this page

vue-ssr 4.优化打包和支持preload


由于服务端渲染,写死了加载文件,所以改成动态形式

服务端渲染,自动关联到打包后的文件

通过VueSSRServerPlugin、VueSSRClientPlugin 打包,让服务端动态关联到打包配置

  • webpack.server.js

    jsx
    const VueSSRServerPlugin = require('vue-server-renderer/server-plugin');
    const HtmlWebpackPlugin = require("html-webpack-plugin");
    const { merge } = require("webpack-merge");
    const { resolve, ...base } = require("./webpack.base");
    
    module.exports = merge(base, {
    	mode: "development",
    	target: "node",
    	entry: {
    		server: resolve("../src/server-entry.js")
    	},
    	output: {
    		libraryTarget: "commonjs2"
    	},
    	plugins: [
    		new VueSSRServerPlugin(),
    		new HtmlWebpackPlugin({
    			filename: "index.ssr.html",
    			template: resolve("../public/index.ssr.html"),
    			excludeChunks: ['server'],
    			minify: false,
    			client: '/client.bundle.js'
    		}),
    	]
    })
    
  • webpack.client.js

    jsx
    const HtmlWebpackPlugin = require("html-webpack-plugin");
    const VueSSRClientPlugin = require('vue-server-renderer/client-plugin');
    
    const { merge } = require("webpack-merge");
    const { resolve, ...base } = require("./webpack.base");
    
    console.log(process.env.mode);
    
    module.exports = merge(base, {
    	mode: "development",
    	entry: {
    		client: resolve("../src/client-entry.js")
    	},
    	output: {
    		// clean: true,
    	},
    	plugins: [
    		new VueSSRClientPlugin(),
    		new HtmlWebpackPlugin({
    			filename: process.env.mode === 'development' ? "index.html" : "index.client.html",
    			template: resolve("../public/index.client.html")
    		}),
    	]
    })
    
  • webpack.base.js:将输出统一至base文件中

    jsx
    const path = require("path");
    const { VueLoaderPlugin } = require("vue-loader");
    
    const resolve = (p) => path.resolve(__dirname, p);
    
    let config = exports = module.exports;
    const ASSET_PATH = process.env.ASSET_PATH || '/';
    
    config = {
    	mode: "development",
    	entry: resolve("../src/client.js"),
    	output: {
    		filename: '[name].bundle.js',
    		path: resolve('../dist'),
    		//! 注意:需要添加publicPath, 否则会导致服务端渲染出来的html中preload预加载的client.bundle.js 会添加auto前缀,导致加载路径错误导致报错
    		publicPath: ASSET_PATH
    	},
    	resolve: {
    		extensions: [".js", ".json", ".vue"]
    	},
    	module: {
    		rules: [
    			{
    				test: /\.vue$/,
    				use: { loader: 'vue-loader' }
    			},
    			{
    				test: /\*.js/,
    				use: {
    					loader: 'babel-loader',
    					options: {
    						presets: ["@bable/preset-env"]
    					}
    				}
    			},
    			{
    				test: /\.css/,
    				use: [
    					"vue-style-loader",
    					{
    						loader: "css-loader",
    						options: {
    							esModule: false
    						}
    					}
    				]
    			}
    		]
    	},
    	plugins: [
    		new VueLoaderPlugin(),
    	]
    }
    
    config.resolve = resolve;
    module.exports = config;
    
  • server.js : 根据打包后的配置文件来关联打包文件

    jsx
    const Koa = require("koa");
    const Router = require("koa-router");
    const static = require("koa-static");
    const VueServerRender = require("vue-server-renderer");
    const fs = require("fs");
    const path = require("path");
    const resolve = (p) => path.resolve(__dirname, p);
    
    const serverTemplete = fs.readFileSync(resolve("dist/index.ssr.html"), "utf8");
    //! 通过vue-ssr-server-bundle.json 关联服务端打包文件server.bundle.js,避免写死读取的配置文件
    const serverBundle = require(resolve("dist/vue-ssr-server-bundle.json"));
    //! 通过vue-ssr-client-manifest.json 关联client打包文件client.bundle.js,避免写死读取的配置文件
    const clientManifest = require(resolve("dist/vue-ssr-client-manifest.json"));
    
    const render = VueServerRender.createBundleRenderer(serverBundle, { template: serverTemplete, clientManifest });
    
    const app = new Koa();
    const router = new Router();
    
    //! 说明:匹配非首页路径,否则会显示404页面
    router.get("/(.*)", async (ctx) => {
    	ctx.body = await new Promise((resolve) => {
    		render.renderToString({ url: ctx.url }, (err, html) => {
    			if (err && err.code == 404) resolve(`not found 404`);
    			resolve(html)
    		})
    	})
    })
    
    //! 特别注意:要先匹配static中间件,否则会导致全部进制get中然后渲染成html导致,请求client.bundle.js文件都是返回html内容
    app.use(static(resolve("dist")));
    app.use(router.routes());
    
    app.listen(4000, () => {
    	console.log("server start success port:", 4000);
    });
    

总结

  • 通过VueSSRServerPlugin、VueSSRClientPlugin 打包出来的json文件,然后让服务端通过打包后的固定json文件来关联client.bundle.js 和server.bundle.js,避免写死读取的配置文件
  • 需要添加publicPath, 否则会导致服务端渲染出来的html中preload预加载的client.bundle.js 会添加auto前缀,导致加载路径错误导致报错

以上:如发现有问题,欢迎留言指出,我及时更正

Released under the MIT License.