Mar*_*nik 6 node.js typescript server-side-rendering vuejs3 vue-cli-4
我正在尝试创建 Vue.js 3 SSR 应用程序(包括 ts、@vue/cli、babel)。我使用 Nodejs + Express 作为后端。SSR 工作正常(我从服务器正确渲染了 html),但在客户端水合作用期间发生错误。我的客户端构建似乎不包含组件的模板,因为我在浏览器中收到这些错误
\nVue warn]: Component is missing template or render function. \n at <App> \n at <App>\n\nVue warn]: Hydration node mismatch:\n- Client vnode: Symbol(Comment) \n- Server rendered DOM: <div class=\xe2\x80\x8b"hello-world">\xe2\x80\x8bhello\xe2\x80\x8b</div>\xe2\x80\x8b \n at <App> \n at <App>\n\nruntime-core.cjs.js:2942 Hydration completed but contains mismatches.\nRun Code Online (Sandbox Code Playgroud)\n我发现当我用渲染函数替换模板时错误消失了,但它再次出现在子组件上(为简单起见,HelloWorld没有子组件)。
\n这是我的 github 存储库,我在其中重现了我的问题。
index.html
Vue warn]: Component is missing template or render function. \n at <App> \n at <App>\n\nVue warn]: Hydration node mismatch:\n- Client vnode: Symbol(Comment) \n- Server rendered DOM: <div class=\xe2\x80\x8b"hello-world">\xe2\x80\x8bhello\xe2\x80\x8b</div>\xe2\x80\x8b \n at <App> \n at <App>\n\nruntime-core.cjs.js:2942 Hydration completed but contains mismatches.\nRun Code Online (Sandbox Code Playgroud)\npackage.json
{\n "name": "ssr3",\n "version": "0.1.0",\n "private": true,\n "scripts": {\n "serve": "vue-cli-service serve",\n "build": "rimraf dist && yarn build:server && yarn build:client",\n "build:server": "cross-env SSR=true vue-cli-service build --dest dist/server --mode development",\n "build:client": "vue-cli-service build --dest dist/client --mode development",\n "lint": "vue-cli-service lint"\n },\n "dependencies": {\n "core-js": "^3.6.5",\n "vue": "^3.0.0",\n "vue-router": "^4.0.0-0",\n "@vue/server-renderer": "^3.0.0",\n "class-transformer": "^0.3.1",\n "express": "^4.17.1",\n "reflect-metadata": "^0.1.13",\n "webpack-manifest-plugin": "^2.2.0",\n "webpack-node-externals": "^2.5.2"\n },\n "devDependencies": {\n "@typescript-eslint/eslint-plugin": "^2.33.0",\n "@typescript-eslint/parser": "^2.33.0",\n "@vue/cli-plugin-babel": "~4.5.0",\n "@vue/cli-plugin-eslint": "~4.5.0",\n "@vue/cli-plugin-router": "~4.5.0",\n "@vue/cli-plugin-typescript": "~4.5.0",\n "@vue/cli-service": "~4.5.0",\n "@vue/compiler-sfc": "^3.0.0",\n "@vue/eslint-config-prettier": "^6.0.0",\n "@vue/eslint-config-typescript": "^5.0.2",\n "eslint": "^6.7.2",\n "eslint-plugin-prettier": "^3.1.3",\n "eslint-plugin-vue": "^7.0.0-0",\n "node-sass": "^4.12.0",\n "prettier": "^1.19.1",\n "sass-loader": "^8.0.2",\n "typescript": "~3.9.3",\n "cross-env": "^7.0.2",\n "husky": "^4.2.5",\n "lint-staged": "^10.2.11"\n },\n "eslintConfig": {\n "root": true,\n "env": {\n "node": true\n },\n "extends": [\n "plugin:vue/vue3-essential",\n "eslint:recommended",\n "@vue/typescript/recommended",\n "@vue/prettier",\n "@vue/prettier/@typescript-eslint"\n ],\n "parserOptions": {\n "ecmaVersion": 2020\n },\n "rules": {}\n },\n "prettier": {\n "semi": false,\n "singleQuote": true,\n "tabWidth": 4,\n "arrowParens": "avoid",\n "printWidth": 100\n },\n "browserslist": [\n "> 1%",\n "last 2 versions",\n "not dead"\n ]\n}\nRun Code Online (Sandbox Code Playgroud)\nvue.config.js
const ManifestPlugin = require(\'webpack-manifest-plugin\')\nconst nodeExternals = require(\'webpack-node-externals\')\nconst webpack = require(\'webpack\')\n\nmodule.exports = {\n configureWebpack: {\n resolve: { mainFields: [\'main\', \'module\'] }\n },\n\n chainWebpack: webpackConfig => {\n const isSSR = process.env.SSR\n webpackConfig\n .entry(\'app\')\n .clear()\n .add(isSSR ? \'./src/entry-server.ts\' : \'./src/entry-client.ts\')\n\n webpackConfig.plugin(\'manifest\').use(new ManifestPlugin({ fileName: \'manifest.json\' }))\n\n if (!isSSR) {\n return\n }\n\n webpackConfig.target(\'node\')\n webpackConfig.output.libraryTarget(\'commonjs2\')\n\n webpackConfig.externals(nodeExternals({ allowlist: /\\.(css|vue)$/ }))\n\n webpackConfig.optimization.splitChunks(false).minimize(false)\n\n webpackConfig.plugins.delete(\'hmr\')\n webpackConfig.plugins.delete(\'preload\')\n webpackConfig.plugins.delete(\'prefetch\')\n webpackConfig.plugins.delete(\'progress\')\n webpackConfig.plugin(\'limit\').use(\n new webpack.optimize.LimitChunkCountPlugin({\n maxChunks: 1\n })\n )\n }\n}\nRun Code Online (Sandbox Code Playgroud)\nApp.vue
<template>\n <HelloWorld />\n</template>\n\n<script lang="ts">\n import { defineComponent } from \'vue\'\n import HelloWorld from \'@/components/HelloWorld.vue\'\n\n export default defineComponent({\n components: { HelloWorld }\n })\n</script>\nRun Code Online (Sandbox Code Playgroud)\nHelloWorld.vue
<template>\n <div class="hello-world">hello</div>\n</template>\n\n<script lang="ts">\n import { defineComponent } from \'vue\'\n export default defineComponent({})\n</script>\nRun Code Online (Sandbox Code Playgroud)\napp.ts
import { createSSRApp, h } from \'vue\'\nimport App from \'@/App.vue\'\n\nexport const createApp = () => {\n const rootComponent = {\n render: () => h(App),\n components: { App }\n }\n const app = createSSRApp(rootComponent)\n return { app }\n}\nRun Code Online (Sandbox Code Playgroud)\nentry-server.ts
import { createApp } from \'@/app\'\n\nexport default async () => {\n const { app } = createApp()\n return app\n}\nRun Code Online (Sandbox Code Playgroud)\nentry-client.ts
import { createApp } from \'@/app.ts\'\n\nconst { app } = createApp()\napp.mount(\'#app\', true)\nRun Code Online (Sandbox Code Playgroud)\nserver.js
const path = require(\'path\')\nconst fs = require(\'fs\')\nconst express = require(\'express\')\nconst { renderToString } = require(\'@vue/server-renderer\')\nconst serverManifest = require(\'./dist/server/manifest.json\')\n\nconst server = express()\n\nconst appPath = path.join(__dirname, \'/dist/server\', serverManifest[\'app.js\'])\nconst createApp = require(appPath).default\n\nserver.use(\'/img\', express.static(path.join(__dirname, \'/dist/client\', \'img\')))\nserver.use(\'/js\', express.static(path.join(__dirname, \'/dist/client\', \'js\')))\nserver.use(\'/css\', express.static(path.join(__dirname, \'/dist/client\', \'css\')))\n\nserver.get([\'/*\'], async (req, res) => {\n const app = await createApp()\n const appContent = await renderToString(app)\n\n fs.readFile(path.join(__dirname, \'/dist/client/index.html\'), (err, html) => {\n if (err) {\n throw err\n }\n\n html = html.toString().replace(\'SSR_APP_CONTENT\', `${appContent}`)\n res.setHeader(\'Content-Type\', \'text/html\')\n res.send(html)\n })\n})\n\nserver.listen(80)\nRun Code Online (Sandbox Code Playgroud)\n- macOS Catalina 10.15.5\n- Nodejs v12.19.0\n- Google Chrome v86.0.4240.111\nRun Code Online (Sandbox Code Playgroud)\n
我终于发现这cache-loader导致了我的问题。
通过运行yarn build:server && yarn build:client,客户端构建使用服务器构建中的缓存组件,然后就没有render函数了,因为 ssr 构建ssrRender仅生成函数。我已经通过禁用中的函数的
缓存加载器来修复它。chainWebpackvue.config.js
chainWebpack: webpackConfig => {
...
webpackConfig.module.rule('vue').uses.delete('cache-loader')
webpackConfig.module.rule('js').uses.delete('cache-loader')
webpackConfig.module.rule('ts').uses.delete('cache-loader')
...
}
Run Code Online (Sandbox Code Playgroud)
参考: https: //forum.vuejs.org/t/disable-cache-loader-in-webpack-4-vue-cli-3/57561
| 归档时间: |
|
| 查看次数: |
9340 次 |
| 最近记录: |