Просмотр исходного кода

dom结构不匹配问题排查

wangtao 1 год назад
Родитель
Сommit
3ce194c7d7

+ 1 - 0
.gitignore

@@ -1,6 +1,7 @@
 # Logs
 logs
 *.log
+.history
 npm-debug.log*
 yarn-debug.log*
 yarn-error.log*

+ 1 - 3
index.html

@@ -9,9 +9,7 @@
 </head>
 
 <body>
-    <div id="app">
-        <!--ssr-outlet-->
-    </div>
+    <div id="app"><!--ssr-outlet--></div>
     <script type="module" src="/src/entry-client.ts"></script>
 </body>
 

+ 28 - 0
package-lock.json

@@ -17,6 +17,7 @@
             "devDependencies": {
                 "@typescript-eslint/eslint-plugin": "^6.21.0",
                 "@vitejs/plugin-vue": "^5.0.4",
+                "cross-env": "^7.0.3",
                 "eslint": "^8.56.0",
                 "eslint-config-standard-with-typescript": "^43.0.1",
                 "eslint-plugin-import": "^2.29.1",
@@ -1781,6 +1782,24 @@
             "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
             "dev": true
         },
+        "node_modules/cross-env": {
+            "version": "7.0.3",
+            "resolved": "https://registry.npmmirror.com/cross-env/-/cross-env-7.0.3.tgz",
+            "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
+            "dev": true,
+            "dependencies": {
+                "cross-spawn": "^7.0.1"
+            },
+            "bin": {
+                "cross-env": "src/bin/cross-env.js",
+                "cross-env-shell": "src/bin/cross-env-shell.js"
+            },
+            "engines": {
+                "node": ">=10.14",
+                "npm": ">=6",
+                "yarn": ">=1"
+            }
+        },
         "node_modules/cross-spawn": {
             "version": "7.0.3",
             "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -6349,6 +6368,15 @@
             "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
             "dev": true
         },
+        "cross-env": {
+            "version": "7.0.3",
+            "resolved": "https://registry.npmmirror.com/cross-env/-/cross-env-7.0.3.tgz",
+            "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
+            "dev": true,
+            "requires": {
+                "cross-spawn": "^7.0.1"
+            }
+        },
         "cross-spawn": {
             "version": "7.0.3",
             "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz",

+ 8 - 3
package.json

@@ -1,12 +1,16 @@
 {
-    "name": "airbnb-ssr",
+    "name": "usky-ssr",
     "private": true,
     "version": "0.0.0",
     "type": "module",
     "scripts": {
-        "dev": "vite",
+        "dev": "node server",
+        "dev:ssr": "cross-env NODE_ENV=development  node server",
+        "prod:ssr": "cross-env NODE_ENV=production  node server",
         "build": "vue-tsc && vite build",
-        "preview": "vite preview"
+        "preview": "vite preview",
+        "build:client": "vite build --outDir dist/client",
+        "build:server": "vite build --outDir dist/server --ssr src/entry-server.ts"
     },
     "dependencies": {
         "axios": "^1.6.7",
@@ -18,6 +22,7 @@
     "devDependencies": {
         "@typescript-eslint/eslint-plugin": "^6.21.0",
         "@vitejs/plugin-vue": "^5.0.4",
+        "cross-env": "^7.0.3",
         "eslint": "^8.56.0",
         "eslint-config-standard-with-typescript": "^43.0.1",
         "eslint-plugin-import": "^2.29.1",

+ 53 - 33
server.js

@@ -2,56 +2,74 @@ import fs from 'fs'
 import path from 'path'
 import { fileURLToPath } from 'url'
 import express from 'express'
+import serverStatic from 'serve-static'
 import { createServer as createViteServer } from 'vite'
-
+const isProd = process.env.NODE_ENV  === 'production'
 const __dirname = path.dirname(fileURLToPath(
     import.meta.url))
 
 async function createServer() {
     const app = express()
-
     // 以中间件模式创建 Vite 应用,并将 appType 配置为 'custom'
-    // 这将禁用 Vite 自身的 HTML 服务逻辑
-    // 并让上级服务器接管控制
-    const vite = await createViteServer({
-        server: { middlewareMode: true },
-        appType: 'custom'
-    })
+        // 这将禁用 Vite 自身的 HTML 服务逻辑
+        // 并让上级服务器接管控制
+        const vite = await createViteServer({
+            server: { middlewareMode: 'ssr' },
+            // appType: 'custom'
+        })
+    if(!isProd){
+        
+        // 使用 vite 的 Connect 实例作为中间件
+        // 如果你使用了自己的 express 路由(express.Router()),你应该使用 router.use
+        // 当服务器重启(例如用户修改了 vite.config.js 后),
+        // `vite.middlewares` 仍将保持相同的引用
+        // (带有 Vite 和插件注入的新的内部中间件堆栈)。
+        // 即使在重新启动后,以下内容仍然有效。
+        app.use(vite.middlewares)
+    }else{
+        app.use(serverStatic(path.resolve(__dirname,'dist/client')))
+    }
 
-    // 使用 vite 的 Connect 实例作为中间件
-    // 如果你使用了自己的 express 路由(express.Router()),你应该使用 router.use
-    // 当服务器重启(例如用户修改了 vite.config.js 后),
-    // `vite.middlewares` 仍将保持相同的引用
-    // (带有 Vite 和插件注入的新的内部中间件堆栈)。
-    // 即使在重新启动后,以下内容仍然有效。
-    app.use(vite.middlewares)
 
     app.use('*', async(req, res, next) => {
         const url = req.originalUrl
-
+        let template
+        let render
         try {
-            // 1. 读取 index.html
-            let template = fs.readFileSync(
-                path.resolve(__dirname, 'index.html'),
-                'utf-8',
-            )
-
-            // 2. 应用 Vite HTML 转换。这将会注入 Vite HMR 客户端,
-            //    同时也会从 Vite 插件应用 HTML 转换。
-            //    例如:@vitejs/plugin-react 中的 global preambles
-            template = await vite.transformIndexHtml(url, template)
+            if(!isProd){
+                 // 1. 读取 index.html
+                template = fs.readFileSync(
+                    path.resolve(__dirname, 'index.html'),
+                    'utf-8',
+                )
+                // 2. 应用 Vite HTML 转换。这将会注入 Vite HMR 客户端,
+                //    同时也会从 Vite 插件应用 HTML 转换。
+                //    例如:@vitejs/plugin-react 中的 global preambles
+                template = await vite.transformIndexHtml(url, template)
 
-            // 3a. 加载服务器入口。vite.ssrLoadModule 将自动转换
-            //    你的 ESM 源码使之可以在 Node.js 中运行!无需打包
-            //    并提供类似 HMR 的根据情况随时失效。
-            const { render } = await vite.ssrLoadModule('/src/entry-server.ts')
+                // 3a. 加载服务器入口。vite.ssrLoadModule 将自动转换
+                //    你的 ESM 源码使之可以在 Node.js 中运行!无需打包
+                //    并提供类似 HMR 的根据情况随时失效。
+                render  = (await vite.ssrLoadModule('/src/entry-server.ts')).render
                 // 3b. 从 Vite 5.1 版本开始,你可以试用实验性的 createViteRuntime
                 // API。
                 // 这个 API 完全支持热更新(HMR),其工作原理与 ssrLoadModule 相似
                 // 如果你想尝试更高级的用法,可以考虑在另一个线程,甚至是在另一台机器上,
                 // 使用 ViteRuntime 类来创建运行环境。
-            const runtime = await vite.createViteRuntime(server)
-            const { render } = await runtime.executeEntrypoint('/src/entry-server.js')
+                // const runtime = await vite.createViteRuntime(server)
+                // const { render } = await runtime.executeEntrypoint('/src/entry-server.ts')
+            }else{
+                template = fs.readFileSync(
+                    path.resolve(__dirname, 'dist/client/index.html'),
+                    'utf-8',
+                )
+                render  = require('./dist/entry-server.ts').render
+            }
+           
+            
+
+
+
 
             // 4. 渲染应用的 HTML。这假设 entry-server.js 导出的 `render`
             //    函数调用了适当的 SSR 框架 API。
@@ -71,7 +89,9 @@ async function createServer() {
         }
     })
 
-    app.listen(5173)
+    app.listen(5173, () => {
+        console.log("node server.js",isProd ? 'pro' : 'dev')
+    })
 }
 
 createServer()

+ 8 - 9
src/components/layout/footer.vue

@@ -1,17 +1,16 @@
 <script setup lang="ts">
 import { ref } from 'vue'
-import indexedDb from '../../utils/indexedDb'
+// import indexedDb from '../../utils/indexedDb'
 const menuList:any = ref([])//菜单列表
 
 
-const uskyDb = new indexedDb("uskyDb") //创建或连接DB数据库
-uskyDb.openStore("menu","id",['list'])//打开数据库menu
-setTimeout(()=>{
-    uskyDb.getItem('menu',1).then((res:any)=>{
-        menuList.value = res.list
-    })
-},50)
-uskyDb
+// const uskyDb = new indexedDb("uskyDb") //创建或连接DB数据库
+// uskyDb.openStore("menu","id",['list'])//打开数据库menu
+// setTimeout(()=>{
+//     uskyDb.getItem('menu',1).then((res:any)=>{
+//         menuList.value = res.list
+//     })
+// },50)
 </script>
 <template>
     <footer>

+ 11 - 10
src/components/layout/header.vue

@@ -1,11 +1,11 @@
 <script setup lang="ts">
 import { ref } from 'vue'
 import { getMenu } from '../../api'
-import indexedDb from '../../utils/indexedDb'
+// import indexedDb from '../../utils/indexedDb'
 const currentone:any= ref("") //当前页
 const menuList:any = ref([])//菜单列表
-const uskyDb = new indexedDb("uskyDb") //创建或连接DB数据库
-uskyDb.openStore("menu","id",['list'])//打开数据库menu
+// const uskyDb = new indexedDb("uskyDb") //创建或连接DB数据库
+// uskyDb.openStore("menu","id",['list'])//打开数据库menu
 getMenuList()
 currentone.value = "/"
 
@@ -14,20 +14,21 @@ function getMenuList(){
     getMenu().then((res:any)=>{
         menuList.value = res.data
         setTimeout(()=>{
-            addOrEditDb("menu",res.data)
+            // addOrEditDb("menu",res.data)
         },10)
     })
 }
 //新增、修改数据
-function addOrEditDb(storeName:string,data:any){
-    uskyDb.updateItem(storeName,{
-        id:1,
-        list:data
-  })
-}
+// function addOrEditDb(storeName:string,data:any){
+//     uskyDb.updateItem(storeName,{
+//         id:1,
+//         list:data
+//   })
+// }
 </script>
 <template>
   <header class="header-absolute sticky-header">
+    <span v-if="menuList.length>0">    {{ menuList }}</span>
             <div class="custom-container-one">
                 <div class="mainmenu-area  d-flex align-items-center justify-content-center">
                     <div class="logo">

+ 9 - 2
src/entry-client.ts

@@ -1,5 +1,12 @@
 import { createApp } from './main'
+// import indexedDb from './utils/indexedDb'
 const { app, router } = createApp()
+// router.beforeEach((to,from,next)=>{
+//     const uskyDb = new indexedDb("uskyDb") //创建或连接DB数据库
+//     uskyDb.openStore("menu","id",['list']).then((res:any)=>{
+//         next()
+//     })
+// })
 router.isReady().then(() => {
-    app.mount("#app")
-})
+    app.mount('#app')
+})

+ 0 - 1
src/main.ts

@@ -8,7 +8,6 @@ import i18n from './langes/i18n'
 
 
 
-
 export function createApp() {
     const app = createSSRApp(App)
     app.use(router)

+ 0 - 14
src/main2.ts

@@ -1,14 +0,0 @@
-import { createApp } from 'vue'
-import './style.css'
-import App from './App.vue'
-import router from './router'
-import ElementPlus from 'element-plus'
-import 'element-plus/dist/index.css'
-import i18n from './langes/i18n'
-
-
-const app = createApp(App)
-app.use(router)
-app.use(ElementPlus)
-app.use(i18n)
-app.mount('#app')

+ 11 - 11
src/router/index.ts

@@ -1,5 +1,5 @@
 import home from '../views/home/index.vue'
-import mine from '../views/mine/index.vue'
+// import mine from '../views/mine/index.vue'
 import { createRouter, createWebHashHistory, createMemoryHistory, createWebHistory } from 'vue-router'
 
 const routes = [
@@ -12,19 +12,19 @@ const routes = [
             keepAlive: false
         }
     },
-    {
-        path: "/mine",
-        name: "mine",
-        component: mine,
-        meta: {
-            title: "",
-            keepAlive: false
-        }
-    },
+    // {
+    //     path: "/mine",
+    //     name: "mine",
+    //     component: mine,
+    //     meta: {
+    //         title: "",
+    //         keepAlive: false
+    //     }
+    // },
 ]
 
 const router = createRouter({
-    history: createWebHistory(),
+    history:  import.meta.env.SSR ? createMemoryHistory() : createWebHistory(),
     routes
 })
 

+ 1 - 46
src/views/home/index.vue

@@ -1,51 +1,6 @@
 <script setup lang="ts">
-// import indexedDb from '../../utils/indexedDb'
-// import { ref } from 'vue'
-// import  { fetchElephant,get1 } from '../../api'
-// import { useI18n } from 'vue-i18n'
-// const size = ref<'default' | 'large' | 'small'>('default')
-// const value2 = ref('')
-// get1().then(res=>{
-//   console.log(res)
-// })
-// const { t } = useI18n()
-
-
-// 数据库相关操作
-// fetchElephant().then(res=>{
-//   console.log(111,res)
-// })
-// const airbnbDB = new indexedDb("airbnb")
-// airbnbDB.openStore("elephant","id",['nose','ear'])
-// function addOrEditDb(storeName:string){
-//   airbnbDB.updateItem(storeName,{
-//     // id:1,(修改)
-//     nose:'44m',
-//     ear:"比较大"
-//   })
-// }
-// function deleteDb(storeName:string,key:number | string){
-//   airbnbDB.deleteItem(storeName,key)
-// }
-// function getObjectStore(storeName:string){
-//   airbnbDB.getList(storeName)
-// }
-// function getOne(storeName:string,key:number | string){
-//   airbnbDB.getItem(storeName,key)
-// }
 
 </script>
 <template>
-  <!-- <span style="color:blue">{{ t('message.home') }}</span>
-  <el-button @click="addOrEditDb('elephant')">增/改</el-button>
-  <el-button @click="deleteDb('elephant',2)">删除</el-button>
-  <el-button @click="getObjectStore('elephant')">查询所有数据</el-button>
-  <el-button @click="getOne('elephant',1)">查询某一条数据</el-button> -->
-  <!-- <el-button>首页</el-button>
-  <el-date-picker
-        v-model="value2"
-        type="date"
-        placeholder="Pick a day"
-        :size="size"
-      /> -->
+  <div>首页</div>
 </template>

+ 0 - 2
src/views/mine/index.vue

@@ -3,5 +3,3 @@
 <template>
   <div>我的</div>
 </template>
-<style scoped>
-</style>

+ 9 - 9
vite.config.ts

@@ -1,19 +1,19 @@
 import { defineConfig } from 'vite'
 import vue from '@vitejs/plugin-vue'
 import path from 'path'
-import AutoImport from 'unplugin-auto-import/vite'
-import Components from 'unplugin-vue-components/vite'
-import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
+// import AutoImport from 'unplugin-auto-import/vite'
+// import Components from 'unplugin-vue-components/vite'
+// import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
 // https://vitejs.dev/config/
 export default defineConfig({
   plugins: [
     vue(),
-    AutoImport({
-      resolvers: [ElementPlusResolver()]
-    }),
-    Components({
-      resolvers: [ElementPlusResolver()]
-    })
+    // AutoImport({
+    //   resolvers: [ElementPlusResolver()]
+    // }),
+    // Components({
+    //   resolvers: [ElementPlusResolver()]
+    // })
   ],
   resolve: {
     alias: {

+ 0 - 0
vite.config.ts.timestamp-1709621285787-5fe57e033a66c.mjs