美文网首页
108.webpack+vue服务端渲染

108.webpack+vue服务端渲染

作者: wo不是黄蓉 | 来源:发表于2022-05-25 11:26 被阅读0次

    为什么使用ssr?

    • 单页应用对SEO不友好,页面信息是从打包后再渲染过去的。服务端渲染使用服务端渲染页面,将结果返回到浏览器。

    • 内网速度比外网渲染更快

    来自Vue官方的一张图:

    image.png

    实现过程:

    • 实现两个entry,因为服务端没有渲染的概念,因此client entry实现客户端挂载功能,server entry实现获取到应用信息。

    • 使用webpack分别打包client entryclient.bundle.jsserver entryserver.bundle.js

    • 服务端获取打包好的bundle信息,服务端budnle负责渲染vue模板将获取的模板插入到模板文件,客户端Bundle负责将js信息插入到模板文件进行事件调用。

    目录结构

    image-20220526100933382.png
    需要安装的依赖:
    webpack webpack-cli webpack-merge
    vue @vue/server-render vue-loader
    babel-core babel-loader@7
    html-webpack-plugin
    express

    实现过程:

    1.安装vuevue ssrvue版本要和vue-server-renderer版本一致,否则会提示版本不一致报错。

    npm install vue
    npm install @vue/server-renderer
    

    2.实现渲文件和通用代码

    App.vue

    <template>
      <div id="app"><div class="demo" @click="handleClick">一段内容</div></div>
    </template>
    
    <script>
    export default {
      methods: {
        handleClick() {
          console.log(111);
        },
      },
    };
    </script>
    

    app.js

    //vue3引入vue的方式
    import { createApp } from 'vue';
    import App from './App.vue';
    
    export function createSsrApp() {
      const app = createApp(App);
      return { app };
    }
    

    3.实现模板文件和编写 client-entry.jsserver-entry.js

    <!DOCTYPE html>
    <html lang="en">
      <head></head>
      <body>
        <div id="app"></div>
      </body>
    </html>
    

    client-entry.js

    //客户端实现方式使用$mount进行挂载,获取到vue信息,直接对齐进行挂载
    import { createSsrApp } from './app';
    const { app } = createSsrApp();
    app.mount('#app');
    

    server-entry.js

    import { createSsrApp } from './app';//将创建的app信息暴露给服务端
    export default () => {  const { app } = createSsrApp();  return app;};
    

    4.编写package.json打包命令

     "scripts": {
        "client": "webpack --config ./build/webpack.client.js",
        "server": "webpack --config ./build/webpack.server.js",
        "build": "npm run client && npm run server",
        "test": "echo \"Error: no test specified\" && exit 1"
      },
    

    5.编写webpack.config.js,区分客户端和服务端,合并配置信息需要使用webpack-merge

    npm install webpack-merge --save-dev
    

    webpack.base.js

    const path = require('path');
    //使用vueloader需要引入vueloaderplugin
    const { VueLoaderPlugin } = require('vue-loader');
    module.exports = {
      mode: 'production',
      //不配置entry信息,entry信息在不同的配置文件中来加载
      //解析js和vue文件,安装vue-loader
      resolve: {
        extensions: ['.js', '.vue'],
      },
      //解析vue文件,配置loader
      module: {
        rules: [
          // 使用Vueloader编译vue文件
          {
            test: /\.vue$/,
            loader: 'vue-loader',
          },
          // 它会应用到普通的 `.js` 文件
          // 以及 `.vue` 文件中的 `<script>` 块
          {
            test: /\.js$/,
            exclude: /(node_modules)/,
            loader: 'babel-loader',
          },
        ],
      },
      plugins: [new VueLoaderPlugin()],
    };
    

    webpack.client.js

    const path = require('path');
    const { merge } = require('webpack-merge');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const baseConfig = require('./webpack.base');
    
    module.exports = merge(baseConfig, {
      entry: path.resolve(__dirname, '../src/entry-client.js'),
      output: {
        path: path.resolve(__dirname, '../dist'),
        filename: 'client.bundle.js',
      },
      plugins: [
        new HtmlWebpackPlugin({
        //指定打包后的html文件
          filename: 'index.ssr.html',
          //指定模板文件
          template: path.resolve(__dirname, '../dist/index.ssr.html'),
          excludeChunks: ['server'],
          minify: {
            removeComments: false,
          },
        }),
      ],
    });
    

    webpack.server.js

    const path = require('path');
    const { merge } = require('webpack-merge');
    const baseConfig = require('./webpack.base');
    //使用merge合并配置信息
    module.exports = merge(baseConfig, {
        //指定entry为entry.server.js
      entry: path.resolve(__dirname, '../src/entry-server.js'),
      output: {
          //打包到项目的dist目录下面
        path: path.resolve(__dirname, '../dist'),
          //指定打包后Bundle的名字
        filename: 'server.bundle.js',
          //需要打包为commonjs规范的代码,服务端在使用,不支持使用es module的规范
        libraryTarget: 'commonjs2',
      },
      plugins: [],
    });
    

    6.打包文件,打包

    npm run server
    //生成server.bundle.js
    
    npm run client
    //生成index.ssr.html和cliet.bundle.js文件
    

    7.使用express编写服务器createServer.js

    npm install express
    
    //引入ssr
    const { renderToString, render } = require('@vue/server-renderer');
    //创建server
    const server = require('express')();
    const fs = require('fs');
    const path = require('path');
    const express = require('express');
    // Cannot use import statement outside a module
    //node服务端不能使用import语法
    
    //获取模板文件
    const indexTemplate = fs.readFileSync(
      path.resolve(__dirname, './dist/index.ssr.html'),
      'utf-8'
    );
    //使用sever.bundle.js创建vue app,配置webpack.server.js时如果不指定目标为commonjs会提示报错不支持module语法
    const createApp = require('./dist/server.bundle').default;
    //使用express.static将dist目录下的文件设置为静态资源,否则打包到index.ssr.html中的文件虽然可以看到已经引入了client.bundle.js,但是并不能够访问。引入成功之后,访问http://localhost:8080/client.bundle.js可以看到打包后的js信息
    server.use(express.static(path.join(__dirname, './dist')));
    
    server.get('*', async (req, res) => {
      const app = createApp();
      //renderToString将获取到的应用信息返回为字符串,使用将<div id="app">替换为新打包的内容信息
      const appContent = await renderToString(app);
      const html = indexTemplate
        .toString()
        .replace('<div id="app">', `<div id="app">${appContent}`);
    //设置返回的文件格式
      res.setHeader('Content-Type', 'text/html');
      res.send(html);
    });
    //启动服务
    server.listen(8080);
    

    验证:打开http://localhost:8080 点击一段内容文件,可以发现打印了111

    image-20220526105822056.png
    没有将client.bundle.js资源静态化会出现的报错信息:
    image-20220526110114189.png
    参考1:视频
    参考2:vue官方
    源码资源->github

    相关文章

      网友评论

          本文标题:108.webpack+vue服务端渲染

          本文链接:https://www.haomeiwen.com/subject/aqruprtx.html