关于编译sass的问题优化 - childlabor/blog GitHub Wiki
问题: 项目构建后css文件体积整体偏大,代码重复,解析效率不高等等。
目标:
- 优化整体css文件体积,减小app.css,合理分割chunks;
- 避免样式全局污染、重复载入等问题,提升样式解析效率;
- 提升书写开发效率,提高代码可维护性。
方法方式:
- 提取到common,全局引用
优点:模块复用简单,不需额外处理
缺点:构建后app.css体积增大,如果app.css过大会增加首次加载的白屏时间
- %...定义,scoped内 @extend继承
优点:分散css到chunk模块中,按需引用,减小app.css;编译成DRY风格代码,减小文件体积
缺点:每次需要手动引入,容易重复定义
- @mixin,@include
同@extend,mixin可使用变量参数,但是编译成的代码非DRY式。
因此,无需变量时应该优先使用@extend。
- @use(Dart Sass)/@import (Node Sass)文件模块引入
通常用于业务模块管理,整体引入覆盖。需要注意样式全局污染问题,必要是使用namespace限制。
.namespace {
@import '~@/Foo.scss';
}
- 其他
其他方式如@function @at-root根据实际需要使用。
根据上述方法方式做约定规范:
-
整体(复合)模块样式,在多数页面使用到的,比如布局box,主副标题等,提取到common;
-
业务模块有复用性但区别于1的,独立文件,使用@import引入,便于维护;
-
功能性样式,比如文本省略,元素定位,loading等,使用@extend/mixin,无需变量时应该优先使用@extend;
-
活用属性继承性,在层级关系中提升属性,减少重复定义的代码量;
-
icon小图标转成base64,可减少http请求,但是增加了css文件体积; 因此,图标转base64的size界限需根据项目,具体情况分析而定。
首先,分析webpack splitChunks
拆包机制:
- 必要组件
即那些项目里必须加载它们才能正常运行的组件或者函数,它们都会默认打包到app.js中。如果启用css分离,与这些模块相关的样式被打包进app.css。通常是指入口文件main.js、app.vue 及router里全局引入的组件的样式都将编译到app.css。
例如项目app.vue,引入了,而登录组件只在首页有调用, 因此将组件转移到内局部引入,重新构建后,app.css体积将明显减小。
app.css体积减小,可以缩短页面的资源请求时间,也就缩短了白屏loading时间。
- 共用chunk-commons
与上面1不同的非必要组件,但是会被大部分页面使用的模块, 如果你有十个页面引用了它,就会包重复打包十次。 为了避免这种情况发生,webpack会将那些被大量共用的组件单独打包成chunk-commons。
可以通过配置最小共用次数(minChunks)等策略,优化这部分内容。减少其他chunks体积,利用浏览器缓存机制,能加快各页面的加载速度。
- chunk-libs
第三方基础类库,它们的升级频率都不高,但每个页面都需要它们。 因此被打包到chunk-libs。
UI 组件库(elementUI等)通常比较大, 建议将 UI 组件库单独拆成一个包,或者通过CDN引入(externals)。
- 业务组件
一般都是按照页面的划分来打包,
比如在 vue 中,使用路由懒加载的方式加载页面component: () => import('./Foo.vue')
,webpack默认会将它打包成一个独立的bundle。
有一点需要特别注意:同一模块的细分组件(子组件)里通用的样式,无论是在vue文件内单独定义还是提取在common.scss并通过import引入,如果style标签带上scoped属性,编译时都会重复载入(每个scoped一次)并带上[data-v-*]标记区别(并不能保证绝对唯一),重复的样式导致单chunk文件体积增大,并且
[data-v-*]
属性选择器的效率性能也很低。
因此要慎重使用scoped。
vue-loader提供了与css modules的集成,可作为scope CSS的替代方案。
以下是部分配置参数:
splitChunks: {
chunks: "all",
cacheGroups: {
libs: {
name: "chunk-libs",
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: "initial" // 只打包初始时依赖的第三方
},
elementUI: {
name: "chunk-elementUI", // 单独将 elementUI 拆包
priority: 20, // 权重要大于 libs 和 app 不然会被打包进 libs 或者 app
test: /[\\/]node_modules[\\/]element-ui[\\/]/
},
commons: {
name: "chunk-commons",
test: resolve("src/components"), // 可自定义拓展你的规则
minChunks: 2, // 最小共用次数
priority: 5,
reuseExistingChunk: true
}
}
};