--- nav: title: FAQ toc: menu --- # FAQ ## `Application died in status LOADING_SOURCE_CODE: You need to export the functional lifecycles in xxx entry` This error thrown as qiankun could not find the exported lifecycle method from your entry js. To solve the exception, try the following steps: 1. check you have exported the specified lifecycles, see the [doc](/guide/getting-started#1-exports-lifecycles-from-sub-app-entry) 2. check you have set the specified configuration with your bundler, see the [doc](/guide/getting-started#2-config-sub-app-bundler) 3. Check the webpack of micro app whether it configured with `output.globalObject` or not, be sure its value was `window` if it had, or remove it to use default value. 4. Check your `package.json` name field is unique between sub apps. 5. 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, such as: ```html {2} ``` 6. If the development environment is OK but the production environment is not, check whether the `index.html` and `entry js` of the micro app are returned normally, for example, `404.html` is returned. 7. If you're using webpack5 and not using module federation, please see [here](https://github.com/umijs/qiankun/issues/1092#issuecomment-1109673224) 8. If you are using webpack5 and using module federation, you need to expose the life cycle function in the index file, and then expose the life cycle function externally in the bootstrap file. ```js const promise = import('index'); export const bootstrap = () => promise.then((m) => m.bootstrap()); export const mount = () => promise.then((m) => m.mount()); export const unmount = () => promise.then((m) => m.unmount()); ``` 9. Check whether the main app and micro-app use AMD or CommonJS. Check method: run the main app and the micro-app independently, and enter the following code in the console: `(typeof exports === 'object' && typeof module === 'object') || (typeof define === 'function' && define.amd) || typeof exports === 'object'`,If it returns `true`,that it is caused by this reason, and there are mainly the following two solutions: - Solution 1: Modify the `libraryTarget` of the micro-app `webpack` to `'window'`. ```diff const packageName = require('./package.json').name; module.exports = { output: { library: `${packageName}-[name]`, - libraryTarget: 'umd', + libraryTarget: 'window', jsonpFunction: `webpackJsonp_${packageName}`, }, }; ``` - Solution 2: The micro-app is not bundle with `umd`, directly mount the life cycle function to the `window` in the entry file, refer to[Micro app built without webpack](/guide/tutorial#micro-app-built-without-webpack). 10. If it still not works after the steps above, this is usually due to browser compatibility issues. Try to **set the webpack `output.library` of the broken sub app the same with your main app registration for your app**, such as: Such as here is the main configuration: ```ts {4} // main app registerMicroApps([ { name: 'brokenSubApp', entry: '//localhost:7100', container: '#yourContainer', activeRule: '/react', }, ]); ``` Set the `output.library` the same with main app registration: ```js {4} module.exports = { output: { // Keep the same with the registration in main app library: 'brokenSubApp', libraryTarget: 'umd', jsonpFunction: `webpackJsonp_${packageName}`, }, }; ``` ## `Application died in status NOT_MOUNTED: Target container with #container not existed after xxx mounted!` This error thrown as the container DOM does not exist after the micro app is loaded. The possible reasons are: 1. The root id of the micro app conflicts with other DOM, and the solution is to modify the search range of the root id. `vue` micro app: ```js function render(props = {}) { const { container } = props; instance = new Vue({ router, store, render: (h) => h(App), }).$mount(container ? container.querySelector('#app') : '#app'); } export async function mount(props) { render(props); } ``` `react` micro app: ```js function render(props) { const { container } = props; ReactDOM.render(, container ? container.querySelector('#root') : document.querySelector('#root')); } export async function mount(props) { render(props); } export async function unmount(props) { const { container } = props; ReactDOM.unmountComponentAtNode(container ? container.querySelector('#root') : document.querySelector('#root')); } ``` 2. Some js of micro app use `document.write`, such as AMAP 1.x version, Tencent Map 2.x version. If it is caused by the map js, see if the upgrade can be resolved, for example, upgrade the AMAP map to version 2.x. If the upgrade cannot be resolved, it is recommended to put the map on the main app to load. The micro app also introduces this map js (used in run independently), but add the `ignore` attribute to the ` ``` In other cases, please do not use `document.write`. ## `Application died in status NOT_MOUNTED: Target container with #container not existed while xxx mounting!` This error usually occurs when the main app is Vue, and the container is written on a routing page and uses the routing transition effect. Some special transition effect caused the container not to exist in the mounting process of the micro app. The solution is to use other transition effects, or remove the routing transition. ## `Application died in status NOT_MOUNTED: Target container with #container not existed while xxx loading!` Similar to the above error, This error thrown as the container DOM does not exist when the micro app is loaded. Generally, it is caused by incorrect calling timing of the `start` function, just adjust the calling timing of the `start` function. How to determine the completion of the container DOM loading? The vue app can be called during the `mounted` life cycle, and the react app can be called during the `componentDidMount` life cycle. If it still reports an error, check whether the container DOM is placed on a routing page of the main app, please refer to [How to load micro apps on a routing page of the main app](#How to load micro apps on a routing page of the main app) ## `[import-html-entry]: error occurs while excuting xxx script http://xxx.xxx.xxx/x.js` ![](https://user-images.githubusercontent.com/22413530/109919189-41563d00-7cf3-11eb-8328-711228389d63.png) The first line is just a helper info printed by qiankun via `console.error` to help users identify which js file threw the error faster. It is not an exception thrown by qiankun itself. **The actual exception info is in the second line.** For example in the error above, it means the child app itself threw an exception when executing http://localhost:9100/index.bundle.js. **And the actual exception message is `Uncaught TypeError: Cannot read property 'call' of undefined` in the second line.** Exceptions from the child app itself can be debugged and fixed with the following steps: 1. Based on the specific exception message, check if the js file that errors has syntax errors, like missing semicolons, depending on uninitialized variables etc. 2. Whether it depends on global variables provided by the main app, but the main app did not initialize them. 3. Compatibility issues. The child app js itself has syntax compatibility issues in the current runtime environment. ## How to load micro apps on a routing page of the main app It must be ensured that the routing page of the main app is also loaded when the micro app is loaded. `vue` + `vue-router` main app: 1. When the main app registers this route, add a `*` to `path`, **Note: If this route has other sub-routes, you need to register another route, just use this component**. ```js const routes = [ { path: '/portal/*', name: 'portal', component: () => import('../views/Portal.vue'), }, ]; ``` 2. The `activeRule` of the micro app needs to include the route `path` of the main app. ```js registerMicroApps([ { name: 'app1', entry: 'http://localhost:8080', container: '#container', activeRule: '/portal/app1', }, ]); ``` 3. Call the `start` function in the `mounted` cycle of the `Portal.vue` component, **be careful not to call it repeatedly**. ```js import { start } from 'qiankun'; export default { mounted() { if (!window.qiankunStarted) { window.qiankunStarted = true; start(); } }, }; ``` `react` + `react-router` main app:only need to make the activeRule of the sub app include the route of the main app. `angular` + `angular-router` main app,similar to the Vue app: 1. The main app registers a wildcard sub route for this route, and the content is empty. ```ts const routes: Routes = [ { path: 'portal', component: PortalComponent, children: [{ path: '**', component: EmptyComponent }], }, ]; ``` 2. The `activeRule` of the micro app needs to include the route `path` of the main app. ```js registerMicroApps([ { name: 'app1', entry: 'http://localhost:8080', container: '#container', activeRule: '/portal/app1', }, ]); ``` 3. Call the `start` function in the `ngAfterViewInit` cycle of this routing component, **be careful not to call it repeatedly**. ```ts import { start } from 'qiankun'; export class PortalComponent implements AfterViewInit { ngAfterViewInit(): void { if (!window.qiankunStarted) { window.qiankunStarted = true; start(); } } } ``` ## Vue Router Error - `Uncaught TypeError: Cannot redefine property: $router` If you pass `{ sandbox: true }` to `start()` function, `qiankun` will use `Proxy` to isolate global `window` object for sub applications. When you access `window.Vue` in sub application's code,it will check whether the `Vue` property in the proxyed `window` object. If the property does not exist, it will look it up in the global `window` object and return it. There are three lines code in the `vue-router` as followed, and it will access `window.Vue` once the `vue-router` module is loaded. And the `window.Vue` in following code is your master application's `Vue`. ```javascript if (inBrowser && window.Vue) { window.Vue.use(VueRouter); } ``` To solve the error, choose one of the options listed below: 1. Use bundler to pack `Vue` library, instead of CDN or external module 2. Rename `Vue` to other name in master application, eg: `window.Vue2 = window.Vue; delete window.Vue` ## Why dynamic imported assets missing? The reason is that webpack does not use the correct `publicPath` when loading the resource. Two way to solve that: ### 1. With webpack live public path config qiankun will inject a live public path variable before your sub app bootstrap, what you need is to add this code at the top of your sub app entry js: ```js __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__; ``` For more details, check the [webpack doc](https://webpack.js.org/guides/public-path/#on-the-fly). Runtime publicPath addresses the problem of incorrect scripts, styles, images, and other addresses for dynamically loaded in sub application. ### 2. With webpack static public path config You need to set your publicPath configuration to an absolute url, and in development with webpack it might be: ```js { output: { publicPath: `//localhost:${port}`; } } ``` ### After the micro-app is bundled, the font files and images in the css load 404 The reason is that `qiankun` changed the external link style to the inline style, but the loading path of the font file and background image is a relative path. Once the `css` file is packaged, you cannot modify the path of the font file and background image by dynamically modifying the `publicPath`. There are mainly the following solutions: 1. Upload all static resources such as pictures to `cdn`, and directly reference the address of `cdn` in `css` (**recommended**) 2. Use the `url-loader` of `webpack` to package font files and images as `base64` (suitable for projects with small font files and images)(**recommended**) ```js module.exports = { module: { rules: [ { test: /\.(png|jpe?g|gif|webp|woff2?|eot|ttf|otf)$/i, use: [ { loader: 'url-loader', options: {}, }, ], }, ], }, }; ``` `vue-cli3` project: ```js module.exports = { chainWebpack: (config) => { config.module.rule('fonts').use('url-loader').loader('url-loader').options({}).end(); config.module.rule('images').use('url-loader').loader('url-loader').options({}).end(); }, }; ``` `vue-cli5` project, use the `asset/inline` of `webpack` replace `url-loader`: ```js module.exports = { chainWebpack: (config) => { config.module.rule('fonts').type('asset/inline').set('generator', {}); config.module.rule('images').type('asset/inline').set('generator', {}); }, }; ``` 3. Use the `file-loader` of `webpack` to inject the full path when packaging it (suitable for projects with large font files and images) ```js const publicPath = process.env.NODE_ENV === 'production' ? 'https://qiankun.umijs.org/' : `http://localhost:${port}`; module.exports = { module: { rules: [ { test: /\.(png|jpe?g|gif|webp)$/i, use: [ { loader: 'file-loader', options: { name: 'img/[name].[hash:8].[ext]', publicPath, }, }, ], }, { test: /\.(woff2?|eot|ttf|otf)$/i, use: [ { loader: 'file-loader', options: { name: 'fonts/[name].[hash:8].[ext]', publicPath, }, }, ], }, ], }, }; ``` `vue-cli3` project: ```js const publicPath = process.env.NODE_ENV === 'production' ? 'https://qiankun.umijs.org/' : `http://localhost:${port}`; module.exports = { chainWebpack: (config) => { const fontRule = config.module.rule('fonts'); fontRule.uses.clear(); fontRule .use('file-loader') .loader('file-loader') .options({ name: 'fonts/[name].[hash:8].[ext]', publicPath, }) .end(); const imgRule = config.module.rule('images'); imgRule.uses.clear(); imgRule .use('file-loader') .loader('file-loader') .options({ name: 'img/[name].[hash:8].[ext]', publicPath, }) .end(); }, }; ``` 4. Combine the two schemes, convert small files to `base64`, and inject path prefixes for large files ```js const publicPath = process.env.NODE_ENV === 'production' ? 'https://qiankun.umijs.org/' : `http://localhost:${port}`; module.exports = { module: { rules: [ { test: /\.(png|jpe?g|gif|webp)$/i, use: [ { loader: 'url-loader', options: {}, fallback: { loader: 'file-loader', options: { name: 'img/[name].[hash:8].[ext]', publicPath, }, }, }, ], }, { test: /\.(woff2?|eot|ttf|otf)$/i, use: [ { loader: 'url-loader', options: {}, fallback: { loader: 'file-loader', options: { name: 'fonts/[name].[hash:8].[ext]', publicPath, }, }, }, ], }, ], }, }; ``` `vue-cli3` project: ```js const publicPath = process.env.NODE_ENV === 'production' ? 'https://qiankun.umijs.org/' : `http://localhost:${port}`; module.exports = { chainWebpack: (config) => { config.module .rule('fonts') .use('url-loader') .loader('url-loader') .options({ limit: 4096, // Less than 4kb will be packaged as base64 fallback: { loader: 'file-loader', options: { name: 'fonts/[name].[hash:8].[ext]', publicPath, }, }, }) .end(); config.module .rule('images') .use('url-loader') .loader('url-loader') .options({ limit: 4096, // Less than 4kb will be packaged as base64 fallback: { loader: 'file-loader', options: { name: 'img/[name].[hash:8].[ext]', publicPath, }, }, }); }, }; ``` 5. The `vue-cli3` project can package `css` into `js` without generating files separately (not recommended, only suitable for projects with less `css`) Configuration reference [vue-cli3 official website](https://cli.vuejs.org/zh/config/#css-extract): ```js module.exports = { css: { extract: false, }, }; ``` ## Must a sub app asset support cors? Yes it is. Since qiankun get assets which imported by sub app via fetch, these static resources must be required to support [cors](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS). If it is your own script, you can support it by developing server-side cross-domain. If it is a 3-legged script and cannot add cross-domain headers to it, you can drag the script to the local and have your own server serve support cross-domain. See [Enable Nginx Cors](https://enable-cors.org/server_nginx.html). ## How to solve that micro apps loaded failed due to abnormal scripts inserted dynamically by carriers Scripts inserted by carriers are usually marked with `async` to avoid loading of block micro apps. This is usually no problem, such as: ```html ``` However, if some inserted scripts are not marked as `async`, once such scripts fail to run, the entire application will be blocked and subsequent scripts will no longer be executed. We can solve this problem in the following ways: ### Use a custom `getTemplate` method Filter abnormal scripts in the HTML template of the micro app through the `getTemplate` method implemented by yourself. ```js import { start } from 'qiankun'; start({ getTemplate(tpl) { return tpl.replace('