![f2accc7af66bf83673dec9df98b693dc.png](https://i-blog.csdnimg.cn/blog_migrate/60655edcd77f3b0faa6e50a7bb7bd701.jpeg)
前言
在当今前端开发中,组件化研发模式已然是大行其道,各种基于组件化的搭建系统更是层出不穷,在提升业务研发效率的同时,组件化面临着一个痛点—组件样式隔离的问题。
一个组件可能会被多个业务页面所使用,如果不做任何处理,业务在使用该组件的过程中就极有可能会发生组件与组件或者组件与页面因为class命名撞衫而导致的样式覆盖问题,最终使页面展示异常。
针对这个问题目前业界也已经有了很多成熟的方案,包括 css module, css in js 以及BEM命名约定等等。但是这些方案在编码体验和最终构建产物上都或多或少的存在一些问题。
以最为典型和常用的 css module 方案为例,它需要在 jsx 中进行 className 的动态绑定,导致的问题是需要先编写样式而不是先编写元素结构和定义 className。另外一个问题是在 className 写法上由于需要使用获取对象属性的写法,会导致一些使用连字符的样式类名需要用中括号才行,比如如下代码:
.container-title {
color: red;
}
import React from 'react';
import style from './App.css';
export default () => {
return (
<h1 className={style["container-title"]}>
Hello World
</h1>
);
};
这种编码方式确实算不上优雅,毕竟对于前端开发者来说最爽最熟悉的肯定还是直接编写 className 字符串,然后在 css 文件中去编写对应 class 的样式。此外其编译产物中 className 的值会变成一个哈希字符串,如下所示:
<h1 class="_3zyde4l1yATCOkgn-DBWEL">
Hello World
</h1>
._3zyde4l1yATCOkgn-DBWEL {
color: red;
}
虽然类名确实变成独一无二了,但是可读性极差并且如果在作为其他组件的子组件使用时,如果父组件想要覆盖子组件样式,这种情况下就没法儿支持了。
其他的像 css in js 这种需要在 js 中编写样式,这本身就不太符合关注点分离的开发习惯,不仅会导致js文件的膨胀,并且其构建产物中样式大多是通过 style 内联的形式,这种方式对于样式复写也会造成较高的成本。
铺垫做了这么多,接下来会介绍我对于解决 jsx 组件样式隔离问题的最佳实践,它来源于我自己思考并开发的两个 webpack-loader。
最佳实践
示例展示
你需要在组件研发脚手架的 webpack 配置中添加 scope-jsx-loader 和 scope-css-loader。使用示例如下:
先完成 loader 安装
npm i scope-jsx-loader scope-css-loader --save-dev
然后可以在 webpack 中进行 loader 添加
module.exports = {
module: {
rules: [
{
test: /.(t|j)sx$/i,
exclude: /node_modules/,