使用 qiankun 微前端的子应用中 element-ui 的 icon 图标不显示的问题(单独打开应用 icon 显示没问题,在 qiankun 中打开不显

3,187 阅读2分钟

【问题】

使用 qiankun 微前端框架加载的子应用中使用了 element-ui 框架,icon 图标不显示的问题(单独打开应用 icon 显示没问题,在 qiankun 中打开不显示)

【复现步骤】

使用乾坤框架加载使用了 element-ui 框架的子应用,icon 图标不显示(效果是个识别失败的矩形)

错误效果: 错误效果

正确效果: image.png

【原因】

经过搜索资料,element-ui 图标 icon 使用的 是 .woff .ttf 格式的字体图标,浏览器加载后以 <style> 标签的方式引入的,且 .woff 的引入方式为相对路径引入,因为 qiankun 框架的主应用地址和子应用地址不一样,导致加载 .woff 文件地址错误,所以图标不显示

image.png

为什么本地开发的时候没问题:因为本地启动的时候url被处理成了全路径

image.png

【解决】

方案一:配置 url-loader 的 limit 参数大一些,从而使 .woff 和 .fft 等文件直接转成 base64,绕过路径问题。

module.exports = {
    chainWebpack: config => {
        config.module
            .rule('fonts')
            .test(/\.(ttf|woff)(\?.*)?$/)
            .use('url-loader')
            .loader('url-loader')
            .tap(options => {
                 options = {
                    ...options,
                    limit: 99999999,
                    name: '[name].[hash:7].[ext]',
                }
                return options
            })
            .end()
    },
}

方案二: 配置打包时 .woff 等文件的引入路径为 http/https 开头的完整路径。

注意:如果使用 nginx 部署的应用需要配置支持 .woff 和 .ttf 等文件的静态地址访问


const publicPath = process.env.NODE_ENV === 'production' ? 'https://production.com/activeRule/' : `http://localhost:8888/`;
module.exports = {
    chainWebpack: config => {
        const fontRule = config.module.rule('fonts')
        fontRule.uses.clear() // 先清除 vue 默认的配置,不然会有问题
        fontRule
            .use('file-loader')
            .loader('file-loader')
            .options({
                name: 'static/fonts/[name].[hash:7].[ext]',
                publicPath,
            })
            .end()
    },
}

借助 webpack 的 file-loader ,在打包时给其注入完整路径(适用于字体文件和图片体积比较大的项目)

解决完后无意间去查看 qiankun 的官方文档,也给出了类似的解决方案 image.png

ps:因为我们的项目子应用地址是动态配置的,环境比较多,所以采用了方案一。

【复盘】:

首先根据错误提示,确定是 .woff 文件的路径错误导致的 image.png 然后定位显示错误的 icon 发现 使用的相对路径(../../)引入的,在 style使用相对路径它会根据当前浏览器地址栏域名去拼全路径,因为子应用的域名和主应用的不一样,所以路径错误。 image.png

找到了是路径问题,然后就从路径下手去解决,首先的想法是把 相对路径换成绝对路径,解决方式是去配置 url-loader,在 vue.config.js 添加如下配置

const packageName = require('./package.json').name
const getPath = () => {
    return   process.env.NODE_ENV === 'production' ? `../../${packageName}/` : '/'
}
module.exports = {
    chainWebpack: config => {
        config.module
            .rule('fonts')
            .test(/\.(ttf|woff)(\?.*)?$/)
            .use('url-loader')
            .loader('url-loader')
            .tap(options => {
                options = {
                    ...options,
                    // limit: 10000, 
                    publicPath: getPath() ,
                    name: '[name].[hash:7].[ext]',
                }
                return options
            })
            .end()
    },
}

意思是把路径加上子应用的前缀,发版,测试,发现这样不行,虽然我加了子应用的前缀,但是子应用和主应用的域名不同,它还是会使用浏览器地址了的域名。 然后再改

options = {
    ...options,
    // limit: 10000, 
    publicPath: `/`,
    // publicPath: getPath() ,
    name: '[name].[hash:7].[ext]',
}

把相对路径改为绝对路径,发版,测试,发现这样不行,虽然改了它的路径,但是本质上它还是使用的主应用域名,此方法行不通。

然后就想用其他方法,发现配置了 limit 参数之后,打包出来的url不是文件路径,而是base64,结合以往的知识,小图片打包的时候可以通过配置 limit 配置最大值,小于该值的会被转成 base64,而不是路径,然后修改配置如下:

module.exports = {
    chainWebpack: config => {
        config.module
            .rule('fonts')
            .test(/\.(ttf|woff)(\?.*)?$/)
            .use('url-loader')
            .loader('url-loader')
            .tap(options => {
                 options = {
                    ...options,
                    limit: 999999,
                    name: '[name].[hash:7].[ext]',
                }
                return options
            })
            .end()
    },
}

把 limit 配置的大一些,使 .woff 与 .ttf 等文件直接编译成 base64,从而绕过路径问题,虽然感觉不是很正经,但是因为环境很多,配置配置全路径比较麻烦,算是比较简单省事的方法。如果 .woff 文件过大,转成 base64 较大,可能会存在性能问题(影响首次页面速度),建议使用方案二。

【注意 】:

<style> 标签的方式引入文件的相对路径是取的浏览器地址栏域名,导致的该问题的根本原因、 【总结】:

【整理】:

后来查看 qiankun 官方文档,找到了类似的解决方案 image.png