Open zwj9297 opened 2 years ago
备注一点:在禁用了externals之后是正常的
我这边碰到同样的问题。我的场景是因为vue-loader开发环境热更新是通过文件相对路径生成hash值,嵌套子应用的时候hash值相同所以导致主应用被覆盖,设置webpack的mode或者NODE_ENV为production都可以解决
这个问题在我们 monorepo 项目下,我们调整了vue-loader, 这里版本号 "vue-loader": "17.2.2", 底层代码调整如下:
调整源码:node_modules/vue-loader/dist/hotReload.js
'use strict'
// __VUE_HMR_RUNTIME__ is injected to global scope by @vue/runtime-core
Object.defineProperty(exports, '__esModule', { value: true })
exports.genHotReloadCode = void 0
function genHotReloadCode(id, templateRequest) {
return `
/* hot reload */
if (module.hot) {
__exports__.__hmrId = "${id}"
const api = __VUE_HMR_RUNTIME__
module.hot.accept()
if (!api.createRecord('${id}', __exports__)) {
api.reload('${id}', __exports__)
}
${templateRequest ? genTemplateHotReloadCode(id, templateRequest) : ''}
}
`
}
exports.genHotReloadCode = genHotReloadCode
function genTemplateHotReloadCode(id, request) {
return `
module.hot.accept(${request}, () => {
api.rerender('${id}', render)
})
`
}
改成:
'use strict'
// __VUE_HMR_RUNTIME__ is injected to global scope by @vue/runtime-core
Object.defineProperty(exports, '__esModule', { value: true })
exports.genHotReloadCode = void 0
function genHotReloadCode(id, templateRequest) {
return `
/* hot reload */
if (module.hot) {
function debounce(func, wait) {
let timeoutId
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
func.apply(this, args);
}, wait)
}
}
__exports__.__hmrId = "${id}"
const api = __VUE_HMR_RUNTIME__
const debounceReload = debounce(function(...args) {
api.reload(...args)
__exports__.__isReloading = false
}, 100)
module.hot.accept();
/* fix: vue-loader hmr时同一个vue在qiankun中热更新失效或者打开空白页面问题 */
if (!api.createRecord('${id}', __exports__)) {
if (window.__POWERED_BY_QIANKUN__) {
if (window.__VUE_HMR_RUNTIME_SIGN__) {
if (!__exports__.__isReloading) {
const href = window.location.href
if (!__exports__.__routePath || __exports__.__routePath == href) {
api.rerender('${id}', render)
}
__exports__.__routePath = href
}
}
} else {
api.reload('${id}', __exports__)
}
}
${templateRequest ? genTemplateHotReloadCode(id, templateRequest) : ''}
}
`
}
exports.genHotReloadCode = genHotReloadCode
function genTemplateHotReloadCode(id, request) {
return `
module.hot.accept(${request}, () => {
// console.log('rerender');
api.rerender('${id}', render)
})
`
}
关闭主应用热更新,子应用不用调整。主要是解决子应用可以热更新问题,记住子应用在开发环境的时候,一定css方面一定开启内联方式,不要通过 mini-css-extract-plugin方式提炼出单独的css文件,通过link加载进来 两种方案: 1、调整 node_modules/vue-loader/dist/index.js 如果是主应用启动的时候,要在96行
const needsHotReload = !isServer &&
!isProduction &&
!!(descriptor.script || descriptor.scriptSetup || descriptor.template) &&
options.hotReload !== false;
修改如下:
const needsHotReload = false && !isServer &&
!isProduction &&
!!(descriptor.script || descriptor.scriptSetup || descriptor.template) &&
options.hotReload !== false;
2、在webpack层面dev-server做限制。设置hot为false,禁止热更新(hmr)
现象:
vue3项目,webpackage启用externals,loadMicroApp加载子应用时主应用根节点的内容会被子应用的App.vue替换
https://user-images.githubusercontent.com/26342286/139656491-935ca4af-e902-4300-b2ab-d4f975257f37.mp4
createApp(App).mount('#mainApp')
module.exports = { configureWebpack: { externals: { vue: 'Vue' }, devServer: { port, // 跨域 headers: { 'Access-Control-Allow-Origin': '*', } }, output: { // 把子应用打包成 umd 库格式(必须) library:
${name}-[name]
, libraryTarget: 'umd', jsonpFunction:webpackJsonp_${name}
, } } }let instance: any = null // 根组件实例
async function render(props: any) { const { container } = props instance = createApp(App) instance.mount(container ? container.querySelector('#microApp') : '#microApp') }
// webpack打包公共文件路径 if (window.POWERED_BY_QIANKUN) { webpack_public_path = window.INJECTED_PUBLIC_PATH_BY_QIANKUN }
// 生命周期 export async function bootstrap() { console.log('[vue] vue app bootstraped') } export async function mount(props: any) { console.log('mounted') console.log('[vue] props from main framework', props) render(props) } export async function unmount() { console.log('unmounted') instance.unmount() }
项目依赖
vue: ^3.0.0 qiankun: 2.4.10