微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Vue.js 3 SSR-客户端水合作用期间缺少模板或渲染功能 我的设置

如何解决Vue.js 3 SSR-客户端水合作用期间缺少模板或渲染功能 我的设置

我正在尝试创建Vue.js 3 SSR应用程序(包括ts,@ vue / cli,babel)。我正在使用nodejs + express作为后端。 SSR工作正常(我正在从服务器正确渲染html),但是客户端水合作用时发生错误。似乎我的客户端构建不包含组件的模板,因为我在浏览器中遇到这些错误

Vue warn]: Component is missing template or render function. 
  at <App> 
  at <App>

Vue warn]: Hydration node mismatch:
- Client vnode: Symbol(Comment) 
- Server rendered DOM: <div class=​"hello-world">​hello​</div>​  
  at <App> 
  at <App>

runtime-core.cjs.js:2942 Hydration completed but contains mismatches.

我发现用render函数替换模板时该错误消失了,但是再次在子组件上发生(为简单起见,HelloWorld没有子组件)。
这里是my github repo,是我重现问题的地方。

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <Meta charset="utf-8">
    <Meta http-equiv="X-UA-Compatible" content="IE=edge">
    <Meta name="viewport" content="width=device-width,initial-scale=1.0">
  </head>
  <body>
    <div id="app">SSR_APP_CONTENT</div>
  </body>
</html>

package.json

{
    "name": "ssr3","version": "0.1.0","private": true,"scripts": {
        "serve": "vue-cli-service serve","build": "rimraf dist && yarn build:server && yarn build:client","build:server": "cross-env SSR=true vue-cli-service build --dest dist/server --mode development","build:client": "vue-cli-service build --dest dist/client --mode development","lint": "vue-cli-service lint"
    },"dependencies": {
        "core-js": "^3.6.5","vue": "^3.0.0","vue-router": "^4.0.0-0","@vue/server-renderer": "^3.0.0","class-transformer": "^0.3.1","express": "^4.17.1","reflect-Metadata": "^0.1.13","webpack-manifest-plugin": "^2.2.0","webpack-node-externals": "^2.5.2"
    },"devDependencies": {
        "@typescript-eslint/eslint-plugin": "^2.33.0","@typescript-eslint/parser": "^2.33.0","@vue/cli-plugin-babel": "~4.5.0","@vue/cli-plugin-eslint": "~4.5.0","@vue/cli-plugin-router": "~4.5.0","@vue/cli-plugin-typescript": "~4.5.0","@vue/cli-service": "~4.5.0","@vue/compiler-sfc": "^3.0.0","@vue/eslint-config-prettier": "^6.0.0","@vue/eslint-config-typescript": "^5.0.2","eslint": "^6.7.2","eslint-plugin-prettier": "^3.1.3","eslint-plugin-vue": "^7.0.0-0","node-sass": "^4.12.0","prettier": "^1.19.1","sass-loader": "^8.0.2","typescript": "~3.9.3","cross-env": "^7.0.2","husky": "^4.2.5","lint-staged": "^10.2.11"
    },"eslintConfig": {
        "root": true,"env": {
            "node": true
        },"extends": [
            "plugin:vue/vue3-essential","eslint:recommended","@vue/typescript/recommended","@vue/prettier","@vue/prettier/@typescript-eslint"
        ],"parserOptions": {
            "ecmaVersion": 2020
        },"rules": {}
    },"prettier": {
        "semi": false,"singleQuote": true,"tabWidth": 4,"arrowParens": "avoid","printWidth": 100
    },"browserslist": [
        "> 1%","last 2 versions","not dead"
    ]
}

vue.config.js

const ManifestPlugin = require('webpack-manifest-plugin')
const nodeExternals = require('webpack-node-externals')
const webpack = require('webpack')

module.exports = {
    configureWebpack: {
        resolve: { mainFields: ['main','module'] }
    },chainWebpack: webpackConfig => {
        const isSSR = process.env.SSR
        webpackConfig
            .entry('app')
            .clear()
            .add(isSSR ? './src/entry-server.ts' : './src/entry-client.ts')

        webpackConfig.plugin('manifest').use(new ManifestPlugin({ fileName: 'manifest.json' }))

        if (!isSSR) {
            return
        }

        webpackConfig.target('node')
        webpackConfig.output.libraryTarget('commonjs2')

        webpackConfig.externals(nodeExternals({ allowlist: /\.(css|vue)$/ }))

        webpackConfig.optimization.splitChunks(false).minimize(false)

        webpackConfig.plugins.delete('hmr')
        webpackConfig.plugins.delete('preload')
        webpackConfig.plugins.delete('prefetch')
        webpackConfig.plugins.delete('progress')
        webpackConfig.plugin('limit').use(
            new webpack.optimize.LimitChunkCountPlugin({
                maxChunks: 1
            })
        )
    }
}

App.vue

<template>
    <HelloWorld />
</template>

<script lang="ts">
    import { defineComponent } from 'vue'
    import HelloWorld from '@/components/HelloWorld.vue'

    export default defineComponent({
        components: { HelloWorld }
    })
</script>

HelloWorld.vue

<template>
    <div class="hello-world">hello</div>
</template>

<script lang="ts">
    import { defineComponent } from 'vue'
    export default defineComponent({})
</script>

app.ts

import { createSSRApp,h } from 'vue'
import App from '@/App.vue'

export const createApp = () => {
    const rootComponent = {
        render: () => h(App),components: { App }
    }
    const app = createSSRApp(rootComponent)
    return { app }
}

entry-server.ts

import { createApp } from '@/app'

export default async () => {
    const { app } = createApp()
    return app
}

entry-client.ts

import { createApp } from '@/app.ts'

const { app } = createApp()
app.mount('#app',true)

server.js

const path = require('path')
const fs = require('fs')
const express = require('express')
const { renderToString } = require('@vue/server-renderer')
const serverManifest = require('./dist/server/manifest.json')

const server = express()

const appPath = path.join(__dirname,'/dist/server',serverManifest['app.js'])
const createApp = require(appPath).default

server.use('/img',express.static(path.join(__dirname,'/dist/client','img')))
server.use('/js','js')))
server.use('/css','css')))

server.get(['/*'],async (req,res) => {
    const app = await createApp()
    const appContent = await renderToString(app)

    fs.readFile(path.join(__dirname,'/dist/client/index.html'),(err,html) => {
        if (err) {
            throw err
        }

        html = html.toString().replace('SSR_APP_CONTENT',`${appContent}`)
        res.setHeader('Content-Type','text/html')
        res.send(html)
    })
})

server.listen(80)

我的设置

- macOS Catalina 10.15.5
- Nodejs v12.19.0
- Google Chrome v86.0.4240.111

解决方法

我终于发现cache-loader引起了我的问题。
通过运行yarn build:server && yarn build:client,客户端版本正在使用服务器版本中的缓存组件,因此没有render函数,因为ssr版本仅产生ssrRender函数。
我已通过在chainWebpack的{​​{1}}函数中禁用缓存加载器来解决此问题。

vue.config.js

ref:https://forum.vuejs.org/t/disable-cache-loader-in-webpack-4-vue-cli-3/57561

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?