vite-plugin-vue icon indicating copy to clipboard operation
vite-plugin-vue copied to clipboard

热更新失效

Open ningbnii opened this issue 3 years ago • 17 comments

Describe the bug

在index.vue中import testClass,这时候修改testClass,可以输出console。但是修改index.vue后,再次修改testClass,就不会输出console了

Reproduction

https://github.com/ningbnii/vite2_vue3_hmr_test

System Info

  System:
    OS: Windows 10 10.0.17763
    CPU: (8) x64 Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
    Memory: 3.44 GB / 15.95 GB
  Binaries:
    Node: 16.12.0 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.5 - C:\Program Files (x86)\Yarn\bin\yarn.CMD
    npm: 8.1.3 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Internet Explorer: 11.0.17763.2145
  npmPackages:
    @vitejs/plugin-vue: ^2.0.1 => 2.0.1
    vite: ^2.7.10 => 2.7.10

Used Package Manager

yarn

Logs

No response

Validations

ningbnii avatar Jan 11 '22 07:01 ningbnii

would you need to rerun script when modifying template and style? 🤔

and modify script will hmr

poyoho avatar Jan 20 '22 15:01 poyoho

遇到typeError错误时,即使修复问题后,页面也是无法进行热更新,必须手动重新加载页面,之后的热更才是正常的

laola2013 avatar Jan 21 '22 02:01 laola2013

I guess vite call vue runtime interface to rerender the components, but got a error will destroy the component, so we can't rerender only reload 😂

poyoho avatar Jan 21 '22 14:01 poyoho

I guess vite call vue runtime interface to rerender the components, but got a error will destroy the component, so we can't rerender only reload 😂

应该是这样的,其实对于js文件而言,不存在这个问题,因为vite对于.js.vue 采用了不同的更新方式,前者用的是page reload,而后者采用的是hmr update。 目前我的解决方式是:对于.vue的文件添加了额外的文件监听器,更新时直接page reload,这样做比较难受的点是开发体验上稍微差了一点。

laola2013 avatar Jan 25 '22 09:01 laola2013

would you need to rerun script when modifying template and style? 🤔

and modify script will hmr

修改.vue文件后,再修改.js文件,就不会热更新了,重新启动一下项目,再更改.js文件,就又可以热更新了

ningbnii avatar Jan 27 '22 05:01 ningbnii

System:
    OS: Windows 10 10.0.17763
    CPU: (8) x64 Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
    Memory: 3.44 GB / 15.95 GB

would you need to rerun script when modifying template and style? 🤔 and modify script will hmr

修改.vue文件后,再修改.js文件,就不会热更新了,重新启动一下项目,再更改.js文件,就又可以热更新了

可能因为我是macOS,也有可能是因为我用的是@vitejs/[email protected],所以没有出现你说的这种情况,vite内部在采用的是chokidar的文件系统监听器,在不同系统之间的表现可能存在差异(bug),之后再看一下,有没有更好的处理方式

laola2013 avatar Jan 27 '22 06:01 laola2013

System:
    OS: Windows 10 10.0.17763
    CPU: (8) x64 Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
    Memory: 3.44 GB / 15.95 GB

would you need to rerun script when modifying template and style? 🤔 and modify script will hmr

修改.vue文件后,再修改.js文件,就不会热更新了,重新启动一下项目,再更改.js文件,就又可以热更新了

可能因为我是macOS,也有可能是因为我用的是@vitejs/[email protected],所以没有出现你说的这种情况,vite内部在采用的是chokidar的文件系统监听器,在不同系统之间的表现可能存在差异(bug),之后再看一下,有没有更好的处理方式

我测试了macOS,使用了@vitejs/[email protected],问题依然存在,我截图说明了一下测试流程 1、yarn dev image 2、修改index.vue image 3、修改testClass.js image

ningbnii avatar Jan 30 '22 02:01 ningbnii

Vite splits .vue into two files: .css / .js link

CSS error report only needs to re-insert the head node.

But the js error will cause the internal execution error of vue, because the template+script regenerated by vite will be updated and executed when updating (https://github.com/vuejs/core/blob/main/packages/runtime-core/src/ hmr.ts#L78-L99)

However, after the error is reported, the last vdom will be destroyed and the patch(instance.update()) of the rerender cannot be executed.


vite内部将.vue拆成两个文件 .css / .js

css报错只需要重新插入head节点。

但是js报错会导致vue内部执行错误,因为在更新的时候会将vite重新生成的template+script 更新执行 https://github.com/vuejs/core/blob/main/packages/runtime-core/src/hmr.ts#L78-L99

但是报错后会破坏上次的vdom 导致没办法执行rerender的patch(instance.update()).

poyoho avatar Jan 30 '22 02:01 poyoho

我测试了macOS,使用了@vitejs/[email protected],问题依然存在,我截图说明了一下测试流程

may be the rerender script don't exec the setup script again.

setup lifecycle will exec in the Component setup first time.and the Component is not exec the destroy so no exec the setup Script.

you can chance to destroy the <route-view> and mount the <route-view> that will be exec.😀

poyoho avatar Jan 31 '22 00:01 poyoho

我测试了macOS,使用了@vitejs/[email protected],问题依然存在,我截图说明了一下测试流程

may be the rerender script don't exec the setup script again.

setup lifecycle will exec in the Component setup first time.and the Component is not exec the destroy so no exec the setup Script.

you can chance to destroy the <route-view> and mount the <route-view> that will be exec.😀

但是不修改.vue,只修改.js的情况下,页面是可以热更新的,只有在修改了.vue的前提下,再修改.js才不会热更新

ningbnii avatar Jan 31 '22 11:01 ningbnii

我本地Mac ,js始终无法更新

enjoy-wind avatar Feb 07 '23 12:02 enjoy-wind

当我引入一些自定义组件的时候,页面会报出警告,提示我无法识别这个自定义组件,从而无法在页面显示。重启之后就显示正常!

wangjieBABA avatar Feb 08 '23 09:02 wangjieBABA

遇到同样问题,父组件引入新创建的子组件,热更新编译报错,提示不认识子组件;js文件添加变量引入到父组件也会报错,每次都要重新启动项目。@vitejs/plugin-vue版本3.1.0

feiyayshx avatar Apr 04 '23 07:04 feiyayshx

没有办法解决吗?

Gxmg avatar May 04 '23 03:05 Gxmg

快2年了,也没有解决呀,vite的hmr限制写法太多了 😂

little-buddy avatar Nov 13 '23 07:11 little-buddy

@vitejs/plugin-vue 有这段代码

// check if the template is the only thing that changed
if (prevDescriptor && isOnlyTemplateChanged(prevDescriptor, descriptor)) {
  output.push(`export const _rerender_only = true`)
}
output.push(
  `import.meta.hot.accept(mod => {`,
  `  if (!mod) return`,
  `  const { default: updated, _rerender_only } = mod`,
  `  if (_rerender_only) {`,
  `    __VUE_HMR_RUNTIME__.rerender(updated.__hmrId, updated.render)`,
  `  } else {`,
  `    __VUE_HMR_RUNTIME__.reload(updated.__hmrId, updated)`,
  `  }`,
  `})`,
)

中有一个_rerender_only的变量,当@vitejs/plugin-vue发现当前代码非首次构建,而且当前只有template标签中发生变化的时候,就会把_rerender_only 设置为true。

_rerender_only 为true时,热更新会执行 VUE_HMR_RUNTIME.rerender(xx) 这个函数并不会重新获取组件中的最新的状态值(例如重新执行setup函数得到最新的值),而从外面导入的值就在setup函数中。

其中判断是否只有template发生变化的isOnlyTemplateChanged代码如下:

export function isOnlyTemplateChanged(
  prev: SFCDescriptor,
  next: SFCDescriptor,
): boolean {
  return (
    !hasScriptChanged(prev, next) &&
    prev.styles.length === next.styles.length &&
    prev.styles.every((s, i) => isEqualBlock(s, next.styles[i])) &&
    prev.customBlocks.length === next.customBlocks.length &&
    prev.customBlocks.every((s, i) => isEqualBlock(s, next.customBlocks[i]))
  )
}

当script没有发生变化,styles没有发生变化,customBlock没有发生变化的时候,这边默认认为只有template发生了变化。但是当我们修改了外面引入的文件时候同样满足了上述情形,导致了插件认为我们只需要rerender,导致没有获取到最新的setup中的值。

YellRes avatar Jan 11 '24 09:01 YellRes

动画

  • 在使用最新版vite提供的vue模板项目中,也存在热更新问题。
  • 一旦修改了template中任意代码,就会导致外部引入的js热更新失效。
  • 修改script脚本中的任意代码,就可以恢复外部js文件的热更新
  • 具体操作可以看我上述动态图片

测试用到的版本如下:

{
  "name": "my-vite-vue-demo",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "vue": "^3.4.21"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.0.4",
    "sass": "^1.75.0",
    "vite": "^5.2.0"
  }
}

** 这是bug还是特性吗?为什么这么长时间没有解决这问题 **

ys3322 avatar Apr 23 '24 09:04 ys3322