umijs / qiankun

📦 🚀 Blazing fast, simple and complete solution for micro frontends.
https://qiankun.umijs.org
MIT License
15.83k stars 2.02k forks source link

webpack5子应用加载失败 #1092

Closed zc-eason closed 3 years ago

zc-eason commented 3 years ago

What happens?

项目由webpack4升级到webpack5之后, 加载子应用就一直报 You need to export lifecycle functions, 子应用的入口执行了, 推测是webpack打包机制改版导致export出去的mount没有拿到, 请问一下该怎么解决

最小可复现仓库

https://github.com/zc-eason/qiankun-webpack5-demo

复现步骤,错误日志以及相关配置

主应用就直接用qiankun的examples, 改一个子应用的入口到可复现仓库 image

image

相关环境信息

lili21 commented 3 years ago

devServer配一个injectClient: false

zc-eason commented 3 years ago

devServer配一个injectClient: false

配过了也不行..

geweidong commented 3 years ago

devServer配一个injectClient: false

配过了也不行..

我配上了就好使

happy-little-one commented 3 years ago

是 webpack5的问题,有一些break change

Mustang-Galaxy commented 3 years ago

devServer配一个injectClient: false

配上之后 live reload 会失效啊,有解决办法吗?

meiminjun commented 3 years ago

devServer配一个injectClient: false

没用,这个问题还没有解决

webMasterMrBin commented 3 years ago

@zc-eason 请问这个问题解决了么

webMasterMrBin commented 3 years ago

问题解决 webpack5 与 项目里的webpack-dev-server 不兼容 导致 export的entry为空 即子应用的library为{} https://github.com/webpack/webpack-dev-server/issues/2484 升级 webpack-dev-server@4.0.0-beta.0 可解决

Measy commented 3 years ago

@gongshun 你好 这个issue有解决办法了吗?

Measy commented 3 years ago

@zc-eason 你好 请问你解决了吗?

gongshun commented 3 years ago

@gongshun 你好 这个issue有解决办法了吗?

你的楼上已经给出了解决办法啊,升级 webpack-dev-server4.0.0-beta.0 就行了1

Measy commented 3 years ago

@gongshun 你好 这个issue有解决办法了吗?

你的楼上已经给出了解决办法啊,升级 webpack-dev-server4.0.0-beta.0 就行了1

我升级了不行,僵硬 @gongshun

gongshun commented 3 years ago

我升级了不行,僵硬 @gongshun

你确定你升级到了这个版本?就这个issue的demo,我试了,可以,人家官方的issue都说了升级可以解决

gongshun commented 3 years ago

更新依赖包真的可以啊,为啥你们不信呢?

image

更新依赖包很难吗 ?npm install webpack-dev-server@4.0.0-beta.0 -D

https://user-images.githubusercontent.com/29347231/112089210-26793900-8bcc-11eb-9cd8-10653c256df9.mp4

省略安装依赖时间

https://user-images.githubusercontent.com/29347231/112089223-2da04700-8bcc-11eb-9c54-1ea831c15bb6.mp4

视频为证,可以自己试下,@Measy @postbird @dbkillerf6

cloydlau commented 3 years ago

injectClient: false webpack-dev-server@4.0.0-beta.0 webpack-dev-server@4.0.0-beta.1

三种都试了不行 至少我自己这个项目不行 vuecli的版本是 5.0.0-alpha.8 qiankun的版本是 2.3

估计vuecli 5.x还是用的老版本webpack-dev-server吧 毕竟还在beta 要等vuecli升级依赖不知道什么时候去了

DevilZh commented 3 years ago

升级webpack-dev-server@4.0.0-beta.0 后, HRM失效了

linxiaodi commented 3 years ago

更新依赖包真的可以啊,为啥你们不信呢?

image

更新依赖包很难吗 ?npm install webpack-dev-server@4.0.0-beta.0 -D

20210323_104040_Trim.mp4 省略安装依赖时间

20210323_104739.mp4 视频为证,可以自己试下,@Measy @postbird @dbkillerf6

webpack-dev-server 更新到4.0.0-beta.0 也不行

gongshun commented 3 years ago

webpack-dev-server 更新到4.0.0-beta.0 也不行

@linxiaodi demo 发出来看看?

Thyiad commented 3 years ago

我更新到webpack-dev-server@4.0.0-beta.1可以了,gongshun大佬辛苦了,我也不明白上面3个踩人的原因是什么,莫名其妙。 真的是更新一下就好了呀!!

linxiaodi commented 3 years ago

抱歉应该是可以实现的。可能我本身项目的配置上出了些问题 @gongshun

jemmy-tang commented 3 years ago

本地开发环境没问题了,但是生产还是有这个问题,怎么解~

q774221810 commented 3 years ago

升级webpack-dev-server@4.0.0-beta.0 后, HRM失效了

这个怎么解决呢

Wangoutsmart commented 3 years ago

如果我没用webpack-dev-server呢,用webpack-dev-middleware

lovefishs commented 3 years ago

@q774221810 @jemmy-tang @DevilZh @cloydlau @Measy 楼上的几位朋友,经过我不断的踩坑尝试,发现问题不仅仅在于升级 webpack-dev-server@4.0.0-beta.0,而是要把 webpack-dev-server 升级到 v4 最新版,这只是第一步,同时还要升级的有 @pmmmwh/react-refresh-webpack-plugin 这个依赖,并且版本升级到 0.5.x,否则在启动 HMR 模式的情况下,会报 js 错误,页面无法正常展示。

我把相关依赖的及版本信息写下,给各位朋友做个参考:

{
  // ...
  "@pmmmwh/react-refresh-webpack-plugin": "0.5.0-rc.3",
  "react-refresh": "0.10.0",
  "webpack-cli": "4.8.0",
  "webpack-dev-server": "4.0.0-rc.1"
}

这里还有一个地方需要注意的就是,当我们把 webpack-dev-server 升级到 v4 之后,webpack.config.js 配置中的 devServer 配置项会有一些变化,可以根据启动的报错指示进行修改(如果没有报错那是最好的),或者直接参考 webpack-dev-server/lib/options.json 进行修改。

经过这些配置,我本地启动服务之后,可以解决 webpack export 入口为 {} 空对象的问题,主应用能够正确载入微应用,希望这些信息能对其他人有所帮助。

q774221810 commented 3 years ago

@lovefishs 我上上周也是这么试过,按这样下来可以,但是我这里有一个情况就是关闭dev-server然后再run dev-server会出现浏览器疯狂请求hot-update-json,不知道你有没有这样的情况

linxiaodi commented 3 years ago

@q774221810 @jemmy-tang @DevilZh @cloydlau @Measy 楼上的几位朋友,经过我不断的踩坑尝试,发现问题不仅仅在于升级 webpack-dev-server@4.0.0-beta.0,而是要把 webpack-dev-server 升级到 v4 最新版,这只是第一步,同时还要升级的有 @pmmmwh/react-refresh-webpack-plugin 这个依赖,并且版本升级到 0.5.x,否则在启动 HMR 模式的情况下,会报 js 错误,页面无法正常展示。

我把相关依赖的及版本信息写下,给各位朋友做个参考:

{
  // ...
  "@pmmmwh/react-refresh-webpack-plugin": "0.5.0-rc.3",
  "react-refresh": "0.10.0",
  "webpack-cli": "4.8.0",
  "webpack-dev-server": "4.0.0-rc.1"
}

这里还有一个地方需要注意的就是,当我们把 webpack-dev-server 升级到 v4 之后,webpack.config.js 配置中的 devServer 配置项会有一些变化,可以根据启动的报错指示进行修改(如果没有报错那是最好的),或者直接参考 webpack-dev-server/lib/options.json 进行修改。

经过这些配置,我本地启动服务之后,可以解决 webpack export 入口为 {} 空对象的问题,主应用能够正确载入微应用,希望这些信息能对其他人有所帮助。

能否贴一个详细的repo

lovefishs commented 3 years ago

@lovefishs 我上上周也是这么试过,按这样下来可以,但是我这里有一个情况就是关闭dev-server然后再run dev-server会出现浏览器疯狂请求hot-update-json,不知道你有没有这样的情况

经过我本地的测试不会出现这样的情况。 当我在后台关闭 dev-server 页面端 console 是会打印错误日志,并且 network 会尝试新建 websocket 连接,并且这个尝试连接的时间段会越来越长,不出出现过多的请求连接存在。

或者你可以试试当重启 dev-server 时手动刷新一下页面,或者给 client.logging 参数配置为 none,看看会不会解决您的这个问题。

lovefishs commented 3 years ago

@q774221810 @jemmy-tang @DevilZh @cloydlau @Measy 楼上的几位朋友,经过我不断的踩坑尝试,发现问题不仅仅在于升级 webpack-dev-server@4.0.0-beta.0,而是要把 webpack-dev-server 升级到 v4 最新版,这只是第一步,同时还要升级的有 @pmmmwh/react-refresh-webpack-plugin 这个依赖,并且版本升级到 0.5.x,否则在启动 HMR 模式的情况下,会报 js 错误,页面无法正常展示。 我把相关依赖的及版本信息写下,给各位朋友做个参考:

{
  // ...
  "@pmmmwh/react-refresh-webpack-plugin": "0.5.0-rc.3",
  "react-refresh": "0.10.0",
  "webpack-cli": "4.8.0",
  "webpack-dev-server": "4.0.0-rc.1"
}

这里还有一个地方需要注意的就是,当我们把 webpack-dev-server 升级到 v4 之后,webpack.config.js 配置中的 devServer 配置项会有一些变化,可以根据启动的报错指示进行修改(如果没有报错那是最好的),或者直接参考 webpack-dev-server/lib/options.json 进行修改。 经过这些配置,我本地启动服务之后,可以解决 webpack export 入口为 {} 空对象的问题,主应用能够正确载入微应用,希望这些信息能对其他人有所帮助。

能否贴一个详细的repo

今天较忙,晚点我搞个小的 demo 发上来,到时候再回复您。

lovefishs commented 3 years ago

@linxiaodi 看这里 https://github.com/webpack/webpack/releases/tag/v5.51.0

q774221810 commented 3 years ago

@lovefishs 我现在也好了,今天把devServer和webpack都更到最新,之前我用的是devServer4.0Rc和webpack5.48,现在用4.0和5.51.1,都是最新的,没问题,感谢

lovefishs commented 3 years ago

@lovefishs 我现在也好了,今天把devServer和webpack都更到最新,之前我用的是devServer4.0Rc和webpack5.48,现在用4.0和5.51.1,都是最新的,没问题,感谢

客气了,本来想补充一个 demo repo,但是业务有点赶没空,后面我再补充一个最小可运行的 demo repo。

enyobao commented 3 years ago

升级完webpack-dev-server@4.0.0-beta.0之后有报错,可能因为是node版本太低。我从v10升级v12就没有报错了。

JinJieTan commented 3 years ago

webpack5在配置sideEffects时候,要记得public-path文件,今天有同事在升级版本时,public-path文件被webpack5打包时给tree sharking了

JohnYu588 commented 2 years ago

@gongshun @lovefishs 升级到最新版本还是有这个问题 "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", "webpack-dev-server": "^4.6.0",

library: ${packageName}-[name], libraryTarget: 'umd', chunkLoadingGlobal: webpackJsonp_${packageName},

gongshun commented 2 years ago

@gongshun @lovefishs 升级到最新版本还是有这个问题 "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", "webpack-dev-server": "^4.6.0",

能给个复现demo吗

JohnYu588 commented 2 years ago

@gongshun @lovefishs 升级到最新版本还是有这个问题 "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", "webpack-dev-server": "^4.6.0",

能给个复现demo吗

@gongshun 已解决"html-webpack-plugin": "^5.5.0" 默认注入 chunk.js 到 header,需要在 HtmlWebPlugin 中添加 inject: 'body' 配置将其注入到body,不然app.js不会放置到最后

zjjjjjjjjjjd commented 2 years ago

哥哥们,我试过全部升级最新也没用,最后我在提供一个解决思路 我的版本如下:

    "webpack": "5.65.0",
    "webpack-cli": "4.9.1",
    "webpack-dev-server": "4.7.1"

目前最新了,还是这个错误 于是我加了这个就好了,不妨试试

  output: {
    library: packageName,
    libraryTarget: 'umd',
  },

packageName 为你项目的名字和package里的一致

geekftz commented 2 years ago

问题千奇百怪 答案只有一个

libraryTarget: 'umd',
ywj87132749 commented 2 years ago

我解决半天,试了一下你这个chunkLoadingGlobal属性,终于运行成功了。之前按照官网的jsonFunction配置,一直报错

enhezzz commented 2 years ago

@gongshun @lovefishs 升级到最新版本还是有这个问题 "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", "webpack-dev-server": "^4.6.0",

能给个复现demo吗

@gongshun 已解决"html-webpack-plugin": "^5.5.0" 默认注入 chunk.js 到 header,需要在 HtmlWebPlugin 中添加 inject: 'body' 配置将其注入到body,不然app.js不会放置到最后

背景:create-react-app生成的项目,webpack5,html-webpack-plugin导致的注入顺序问题,在faq里可以找到答案,但是原因比较隐蔽,感谢启发: Check if the entry js in the sub-app's entry HTML is the last script to load. If not, move the order to make it be the last, or manually mark the entry js as entry in the HTML

geekftz commented 2 years ago

更新依赖包真的可以啊,为啥你们不信呢?

image

更新依赖包很难吗 ?npm install webpack-dev-server@4.0.0-beta.0 -D

20210323_104040_Trim.mp4 省略安装依赖时间

20210323_104739.mp4 视频为证,可以自己试下,@Measy @postbird @dbkillerf6

“视频为证”,太狠了

bigcui commented 2 years ago

umdNamedDefine 属性不能忘了 output: { path: resolve('dist'), library: { name:webpack5-vue3-[name], type: 'umd', auxiliaryComment: { root: 'Root Comment', commonjs: 'CommonJS Comment', commonjs2: 'CommonJS2 Comment', amd: 'AMD Comment', }, }, umdNamedDefine: true, }, demohttps://github.com/bigcui/webpack5-vue3

masongzhi commented 2 years ago

@gongshun @lovefishs 升级到最新版本还是有这个问题 "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", "webpack-dev-server": "^4.6.0",

能给个复现demo吗

@gongshun 已解决"html-webpack-plugin": "^5.5.0" 默认注入 chunk.js 到 header,需要在 HtmlWebPlugin 中添加 inject: 'body' 配置将其注入到body,不然app.js不会放置到最后

背景:create-react-app生成的项目,webpack5,html-webpack-plugin导致的注入顺序问题,在faq里可以找到答案,但是原因比较隐蔽,感谢启发: Check if the entry js in the sub-app's entry HTML is the last script to load. If not, move the order to make it be the last, or manually mark the entry js as entry in the HTML

这是有用的回答,某些项目可能把依赖放在body中引入,vue-cli打包在head中并加入defer属性,所以单独运行没问题,在乾坤中运行会忽略defer属性,导致执行时依赖未引入导致该错误产生

另外提供俩种修改chainWebpack方式:

c.plugin(‘html’)
  .tap(args => {
      args[0].inject = 'body'
      return args;
  });

上面的方式可用,但会与vue-cli的modern模式冲突,可改为:

c.plugin(‘html’)
  .tap(args => {
      args[0].scriptLoading = 'blocking'
      return args;
  });
eleven-net-cn commented 2 years ago

这个问题,如果 library、libraryTarget 等基础配置都正确,问题主要在 webpack-dev-server 版本问题,升级版本可以解决掉。

对于一些不太能升级 webpack-dev-server 的项目,可以采用下面的办法,算是万金油方案。

  1. 在项目入口文件中添加如下代码,先将生命周期函数挂到 window

    export async function bootstrap() {
      console.log('bootstrap');
    }
    
    export async function mount(props) {
      console.log('mount');
    }
    
    export async function unmount(props) {
      console.log('unmount');
    }
    
    /**
     * 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效
     */
    export async function update() {
      console.log('update');
    }
    
    /**
     *  最理想的方法是升级 webpack-dev-server 到 v4,可以解决问题,
     *  但是,升级到 v4,会产生连锁反应:
     *    1.dev-server 有破坏性更新,原有配置参数需要替换掉
     *    2.升级 dev-server,连带会有其它依赖需要更新,比较难解决
     *
     *  解决办法:
     *    1.先将 qiankun 需要的生命周期函数挂到 window(供别处使用)
     *    2.在 index.html 底部注入 js,将生命周期函数挂到 window['purehtml'] 上
     *      灵感来自:
     *        - https://github.com/umijs/qiankun/issues/1846
     *        - https://qiankun.umijs.org/zh/guide/tutorial#%E9%9D%9E-webpack-%E6%9E%84%E5%BB%BA%E7%9A%84%E5%BE%AE%E5%BA%94%E7%94%A8
     * 
     *  区分运行环境,仅本地调试才需要。
     */
    + if (process.env.NODE_ENV === 'development') {
    +   window.qiankunLifecycle = {
    +     bootstrap,
    +     mount,
    +     unmount,
    +     update,
    +   };
    + }
  2. index.html 底部添加 script,挂载 qiankun 生命周期函数

    借助模板语法 <% %> 控制仅本地调试环境才添加这段 script 代码

    window.purehtml 是 qiankun 提供的另一种子应用生命周期挂载方式(传送门

    <html>
      <head>
      </head>
      <body>
      </body>
    
      + <% if(process.env.NODE_ENV==='development' ) { %>
      +   <script entry>
      +     if (window.__POWERED_BY_QIANKUN__) {
      +       window.purehtml = window.qiankunLifecycle;
      +     }
      +   </script>
      + <% } %>
    </html>

    注意事项:

    • script 标签上必须有 entry 属性(重要)
    • script 标签位置必须在 </body> 结束标签后面(重要),否则将出现加载问题
  3. 新版本的 html-webpack-plugin 默认会将编译的 js 产物放到 head 标签尾部,并添加 defer 属性,这会导致 qiankun 在应用加载方面产生问题(qiankun 的生命周期 js entry 需要放在页面 js 资源的末尾,即顺序排在最后),尤其当 html 文件底部自己有额外引入 js 文件的情况,一定会出问题。

    html-webpack-plugin 配置中添加参数 inject: 'body' 搞定。

    如果你的编译产物已经是在 </body> 结束标签前,那么无需处理。

以上方式可以完美解决低版本 webpack-dev-server 产生的问题,同时也不影响生产编译。

顺便列举一些需要正确设置的内容(易错项,都有可能影响到子应用加载):

  1. 正确设置 __webpack_public_path__

    入口文件头部位置(或靠前位置)添加,确保 runtime publicPath 正确。

    通常来说,公司的静态资源都会部署到 CDN,在 test/production 大家基本都会配置好 webpack publicPath(或 React 项目的 PUBLIC_URL)。因此,这主要是 development 环境需要(一般来讲是空)。

    if (window.__POWERED_BY_QIANKUN__) {
      // __webpack_public_path__ 前不能加 window
      // eslint-disable-next-line camelcase
      __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
    }
  2. webpack 5 相关

    1. jsonpFunction 属性需要替换为 chunkLoadingGlobal

    2. libraryTarget 将来可能会被废弃,可以替换为:

      library: {
        name: `${name}-[name]`,
        type: 'umd',
      }
  3. dev-server 开启 CORS

    headers: {
      'Access-Control-Allow-Origin': '*',
    },
  4. 注意 babel polyfill 仅能引入一次,父子应用重复引入会导致应用加载出错

  5. 注意某些类库,仅能初始化一次(例如:vconsole),重复初始化也会导致应用加载出错

unforesndprson commented 2 years ago

升级webpack 5 后,之前在入口js绑定的entry属性是用script-ext-html-webpack-plugin插件。但是这个插件不支持webpack 5,作者也不维护了,导致入口js不再最后加载也没有entry属性,qiankun解析不到。希望能帮到一部分人。

sunnynudt commented 2 years ago

@unforesndprson 那解决方案是什么呢?

unforesndprson commented 2 years ago

@unforesndprson 那解决方案是什么呢? @zhang-maxwell 对入口js的script增加entry属性。 实现上依赖html-webpack-plugin提供的钩子


/**
* 通过html-webpack-plugin暴露的钩子处理数据
*/
class HtmlWebpackCustomPlugin {
constructor(htmlWebpackPlugin, options) {
this.htmlWebpackPlugin = htmlWebpackPlugin;
// 外部传入配置
this.options = options || {};
}

apply(compiler) { // 插件名 const pluginName = 'HtmlWebpackCustomPlugin'; if (compiler.hooks) { compiler.hooks.compilation.tap(pluginName, compilation => { const hook = this.htmlWebpackPlugin.getHooks(compilation); hook.alterAssetTags.tapAsync(pluginName, (htmlPluginData, callback) => { const cloneHtmlPluginData = { ...htmlPluginData }; const entryScript = cloneHtmlPluginData.assetTags.scripts.find(item => // 匹配自己的入口js ); if (entryScript) { entryScript.attributes.entry = true; } callback(null, cloneHtmlPluginData); }); }); } } }

module.exports = HtmlWebpackCustomPlugin;

libertassss commented 2 years ago

我也是 请问你解决了嘛

jiujiantang commented 2 years ago

@unforesndprson 有没有demo

jiujiantang commented 2 years ago

在试过官方给出的方法还不生效,往往是index.html出问题了,看看构建以后,入口js后面还有没有script脚本,将index.html的脚本都去掉,看看能不能正常