vue-cli3.0+webpack4中关于svg-sprite-loader踩坑,让svg组件徜徉我的web项目

1,434 阅读3分钟

第一次写文章,今天踩坑过后希望能够记录这样'生动有趣'的踩坑之旅,还是那样,在技术的海洋中,我和大佬就像鱼和水,我没了大佬就凉了,大佬没了我还清净,感谢一路栽培。公司之前的项目都是用vue-cli2.x的脚手架集成的webpack3,但是最近的项目用到@vue/cli3,也就是vue-cli3,最新的脚手架契合webpack4,目前文档也更新到了这个版本,一开始看目录结构,纳尼!!webpack常规的配置文件build和config文件怎么没了,这尼玛是不是没有用到自动化构建!!诸如此类的疑问我相信当你第一眼看到这样简洁清爽的目录结构时也会产生,然后我就去看文档,这里cli.vuejs.org/zh/guide/,原来脚手架自动帮我们把webpack的配置集成到了node_modules中

,这样的目录结构还是有些熟悉的。好,那么疑问又产生了,我如何根据项目需要配置baseUrl,outputDir,assetsDir ,loader等等呢,官方是这样写的 调整 webpack 配置最简单的方式就是在 vue.config.js 中的 configureWebpack 选项提供一个对象 , 总结两个, configureWebpack, chainWebpack,这也是我们后面需要用到的两个属性,是更改webpack配置的关键, configureWebpack属性值可以是一个对象或者是一个函数,当为对象时该对象将会被 webpack-merge 合并入最终的 webpack 配置,这应该是集成第三方插件的用法,另外当属性值是一个函数的时候,函数的第一个参数是已经解析好的配置,我们可以看一下console.log

结果 是
是不是看到了许多熟悉的属性,是的,这个config就是webpack的基础配置了,
这里也返回了vue-cli3给我内置配好的不同lodaer,图中对应每一个[object],这也是后来修改和暴力重设loader发现的,仿佛发现新大陆一般的我开始继续项目了,毕竟大佬给的时间有点紧迫,嘤嘤嘤....,因为种种原因ui小姐姐没法将有过渡渐变效果的svg图片放在iconfont上,所以只能自己在项目本地使用svg,参考vue-element-admin中提供一个svg组件的方式,我也这样做
这是svg图片的组件目录结构,接下来是js文件和vue-component

原本的es6箭头函数看上去比较社会(涩会),所以用es5的方式展示,这里非常重要的webpack内置api,require.context函数,它接受三个参数,第一个是文件夹,第二个是是否使用子文件,第三个是文件匹配的正则。对于我们的项目来说,我们需要动态引入的就是

const req = require.context('./svg', false, /\.svg$/)

require.context会返回一个函数,对应上面的console我们看一下控制台

那么311这里对应的这个函数到底代表什么呢,我们知道js中函数也是一个对象,那么这个函数有神马不同,点开看一下:
,哇,看到这个我心态都蹦了,还很激动,这个方法会把我们刚刚联系的上下文中的svg全部写入一个map对象,而这个方法也自己定义了keys方法,用来遍历map,遍历后的key可以作为 webpackContext(key)的参数,从而导出每一个svg,我们看一下导出的requireAll(req)(对应图中,也就是前面说到的webpackContext(key))
果然如所说的,导出了每一个map中对应的svg图,但是可能会有所疑问为什么不是键值形式对应的值,如下:
这里就要说到遇到的第一个坑了,常规按照脚手架的设置,对svg图片的处理会经过file-loader进行文件转化,我们知道这种工程化项目在跑起来时内部会生产一个隐式的dist包,所有的静态资源都会被打包进dist/assets/下,这里也不例外,所以我console.log出来后全是诸如此类的"assets/img/daily-mission83544646.svg "如此的经过其他loader转化的svg图片,但是这样写的话我们的svg组件是没法通过use标签拿到对应svg图片的,这里参考一下张鑫旭大神的关于svg的讲解 未来必热 ,所以我们只能更改脚手架的默认配置,通过svg-sprite-loader生成对应的svg精灵图供我们组件使用,思路回到前文提到的两种配置更改webpack的思路,因为没有用过,所以此坑必填。使用configWebpack:config=>{}这种方式去合并或者添加svg-sprite-loader的方法虽然在rules中增加了该lodaer,但是不知道是因为已经有了其他loader解析svg或者脚手架的基础poader配置权限最高问题,svg图片始终得不到正确的处理,此方法(失败)代码:

configWebpack:config =>{
   config.module.rules.push(
           {
               test: /\.svg$/,
               loader: 'svg-sprite-loader',
               include: [resolve('src/icons')],
               options: {
                   symbolId: 'icon-[name]'
               }
           }
       )
}

结果无功而返,参考了文档后发现了重设loader的配置方法,那就是通过chainWebpack,通过链式操作来修改配置,官方给出的结论 是可以允许我们更细粒度的控制其内部配置,提供了一个 webpack 原始配置的上层抽象,使其可以定义具名的 loader 规则和具名插件,并有机会在后期进入这些规则并对它们的选项进行修改。对于这句话我目前还不是很理解,真是只在此山中,云深不知处!如果合并不行,那就替换!

    chainWebpack: config => {
        const svgRule = config.module.rule('svg');
         svgRule.uses.clear();
         svgRule
            .test( /\.svg$/)
            .use('svg-sprite-loader')
           .loader('svg-sprite-loader')
           .options({
              symbolId: 'icon-[name]'
          });
      }

如此~svg成功通过此loader解析,我们也得到了需要的svg图片模块,但是既然知道合并不行,替换可以,如果不希望用链式操作的话这里也列出一种暴力的方法去修改,同样通过configWebpack

 configureWebpack: config => {
       console.log(config)
       let rules=config.module.rules;
       for(let i in rules){
           console.log(rules[i]);
           if(rules[i].use && rules[i].use[0].loader=='file-loader'){
               rules.splice(i,1)
           }
       }

       config.module.rules.push(
           {
               test: /\.svg$/,
               loader: 'svg-sprite-loader',
               include: [resolve('src/icons')],
               options: {
                   symbolId: 'icon-[name]'
               }
           }
       )
   }

现在这样的话,删除了file-loader,其实和替换一样,但是看上去暴力一些,效果确是相同的。至此,大佬和我的加班时间也到了末尾,感觉很累,但是感觉收获颇丰,走出公司,风呼啸着略过我的双肩背包,我耸了下眼镜,走向昏黄的公交车站。感谢!