当前位置: 首页 > Web前端 > CSS

先说SassBreakingChange-SlashasDivision

时间:2023-03-31 01:47:26 CSS

最近在修改项目时,发现了一系列Sass警告——除号引起的warnings:What'sthewarningforthedirectory?告警如何解决?降级sass模块更新业务语法使用sass-migratorDartSass与节点SassDart-VM上的DartSass与NPM上的DartSass有什么注意事项?警告的内容很简单。在DartSass2.0.0中不推荐使用/作为分隔符。作为Sass的基本语法,这次deprecation是一个breakingchange,所以目前编译时只会抛出警告,不会抛出错误,否则大量项目无法正常运行。经过一番研究,我们可以看到Sass官方用了一整篇文章来解释为什么要这样修改。主要原因是/在Sass中同时起到了分割符和CSS分隔符的作用,例如:Sass代码//使用.test_division作为分割符{border-radius:ceil(28px/2);}//使用.test_operator作为CSS分隔符{font:12px/1.5-apple-system,"SFUIText","PingFangSC","LucidaGrande","MicrosoftYaHei",sans-serif;}实际编译的CSS代码.test_division{border-radius:14px;}.test_operator{font:8px-apple-system,"SFUIText","PingFangSC","LucidaGrande","MicrosoftYaHei",sans-serif;}/中有两个例子中,一个作为分隔符,一个作为font属性中font-size和line-height的分隔符,可以看出,作为分隔符时,/一般不会造成任何问题,但是当用作分隔符时,/作为除号很容易重载。其实要达到分隔符的效果,通常需要这样写:.test_operator{font:#{12px/1.5}-apple-system,"SFUIText","PingFangSC","LucidaGrande","MicrosoftYaHei",sans-serif;}使用插值(Interpolation)语法,包裹12px/1.5,插值的作用是只解析Sassscript,将Sass变量作为实际值输出,但不会进行计算。如果属性值比较复杂,写起来就不是很直观。Sass本身使用复杂启发式的技术来判断/是否应该用作除号或分隔符。复杂的启发式需要回顾当前上下文的内容才能做出判断,所以对Sass有一定的消耗。一般来说,原有的/语法会给开发者带来一些麻烦,尤其是随着越来越多的CSS属性使用分隔符(比如grid、hsl()等语法),Sass的维护和编译也会带来一些额外的消耗,所以Sass最终决定重新定义除法,新的语法相当清晰:@use"sass:math";.test_division{border-radius:math.div(28px,2);}new的语法是基于模块的Sass的语法。引入相关计算模块后,可以调用math.div代替原来的/,/只是作为分隔符。告警如何解决?解决该告警首先要知道项目中为什么会出现这个告警。使用这种语法的项目很多,但是目前只有这个项目有报警。首先,这个突破性的变化只在最新版本的DartSass中引入,NodeSass的版本还没有跟上。另外,项目使用"sass":"^1.30.0"来声明sass模块的版本(即DartSass的npm包)。重新执行npmi会导致安装新版本的DartSass时出现警告,所以解决方案也围绕DartSass版本来处理。降级sass模块删除package-lock.json和node_modules,将package.json中sass模块的版本改为"sass":"~1.32.12",即版本号会小于1.33。0。这个版本的DartSass没有引入斜线作为除法的重大变化。更新业务语法就是将相关告警内容替换成上面提到的新的math.div语法。如果涉及的业务量比较大,更新起来会比较费时间。使用sass-migratorSass-migrator是Sass官方推出的一款迁移工具,方便开发者将最新版本的Sass适配到原有的业务代码中。sass-migrator并没有直接用最新的语法替换相关的旧语法,而是使用更稳定的方式将代码安全地更新为符合最新要求的语法,比如上面的例子:Sasscode.test_division{border-radius:ceil(28px/2);}sass-migrator安装调用npmi-gsass-migratorsass-migratordivisiontest.scssprocessedSasscode.test_division{border-radius:ceil(28px*0.5);}可以看到原来sass-migrator并没有把原来的/修改成最新的math.div语法,而是用乘法代替了。事实上,正如sass基于复杂的启发式分析,重载分隔符作为除号一样,迁移工具无法准确判断每个/的作用,所以sass-migrator采用稳定的方式来适应最新的Sass规则。DartSassVsNodeSassNodeSass没有引入最新的Sass特性,所以不会出现这个警告,但是不推荐使用NodeSass来代替DartSass写的代码,主要是:DartSass已经是官方的首选,无论是新特性还是问题修复,DartSass都会有更强的时效性。如果担心新特性给业务带来问题,可以通过锁包进行控制。NodeSass实际上已经被正式定义为弃用。目前项目会维护一个大版本,但维护进度不确定,显然没有计划给NodeSass增加新特性,也不会适配新的CSS特性。NodeSass是基于LibSass开发的,LibSass依赖的模块安装起来比较麻烦,尤其是对于Windows用户。它要求用户在Windows中安装Python2和VisualStudio。因此,出于长期维护的考虑,选择DartSass也是一种趋势。Dart-VM上的DartSass和NPM上的DartSassDartSass目前有两种实现方式,分别是:DartSassbasedonDart-VMDartSassbasedonpureJavaScript根据官方介绍,单独运行的命令行版本是基于在Dart-VM运行上,得益于Dart-VM的高性能,这个版本的DartSass有非常好的性能,适合写脚本单独编译Sass文件。NPM中的DartSass是用纯JavaScript实现的,因此可以很方便的用于前端项目的构建。DartSass的JavaScript版本虽然性能比LibSass稍差,但就样式代码的编译量而言,差异并不大。上图分别展示了Dart-VM上的DartSass、NPM上的DartSass和NodeSass编译BootStrap4的耗时(来自StackOverflow)。可以看出NPM上的DartSass(也就是DartSassJS)比NodeSass慢很多(耗时3倍左右),但实际上即使对于Bootstrap的体量来说,它也只需要2秒。考虑到官方和社区已经逐步迁移到DartSass,建议新项目使用DartSass。