css module

来源:CSS Modules 用法教程

后面项目地址:https://github.com/947133297/lwj-webpack-demo

关键是打开这一行,表示开启loader的css module功能:

{ test: /.css$/, loader: 'style-loader!css-loader?modules' },

style-loader :用于创建style标签

css-loader:使css文件用起来像组件一样,允许require css进来,还可以启用css module功能

局部作用域测试

border.css

body {
   border: 10px solid darkmagenta;
}
.qwe{
    border: 10px solid black;
}
#eee{
    border: 10px solid green;
}
.outer .inner{
    border: 10px solid red;
}

app.css

body {
  background-color: blue;
}
:global(.qwe){
  font-size: 40px;
}
#eee{
  color: aqua;
}
.outer .inner{
  font-weight: 900;
}

入口js文件

require('./app.css');
var other1 = require('./border.css');

// Cannot read property 'inner' of undefined
// var html1 = '<div class="'+other1.outer.inner+'">other1</div>';
var html1 = '<div class="'+other1.outer+'"><div class="'+other1.inner+'">border test1</div></div>';
var html2 = '<div class="'+other1.qwe+'">border test2</div>';
var html3 = '<div id='+other1.eee+'>border test id</div>';

document.write(html1);
document.write(html2);
document.write(html3);

打包后的文件中有两段这样的代码(导出的标识符是base64生成的,转换前的字符串与路径和文件名相关):

exports.locals = {
    "eee": "_3omJ4gpO6T45EFo0ZOMzz3",
    "outer": "_2R2TiJtwoE2Ka6dR0UXOk1",
    "inner": "_2Zm3l9VFNoYdhD18zUhAsL"
};
//...
exports.locals = {
    "qwe": "qhJc-oYXMZ34_XRr59Qtz",
    "eee": "_2EWJ0p0M9i7zNLMpM4YhOW",
    "outer": "_1wB3wnxbesTSl4WbD-h9aP",
    "inner": "_136k_jaRt4SbXZzJIe6J6O"
};

运行效果:

<style type="text/css">
  body {
    background-color: blue;
  }
  .qwe{
    font-size: 40px;
  }
  #_3omJ4gpO6T45EFo0ZOMzz3{
    color: aqua;
  }
  ._2R2TiJtwoE2Ka6dR0UXOk1 ._2Zm3l9VFNoYdhD18zUhAsL{
    font-weight: 900;
  }
</style>
<style type="text/css">
  body {
    border: 10px solid darkmagenta;
  }
  .qhJc-oYXMZ34_XRr59Qtz{
    border: 10px solid black;
  }
  #_2EWJ0p0M9i7zNLMpM4YhOW{
    border: 10px solid green;
  }
  ._1wB3wnxbesTSl4WbD-h9aP ._136k_jaRt4SbXZzJIe6J6O{
    border: 10px solid red;
  }
</style>
<body>
  <div class="_1wB3wnxbesTSl4WbD-h9aP">
    <div class="_136k_jaRt4SbXZzJIe6J6O">border test1</div>
  </div><div class="qhJc-oYXMZ34_XRr59Qtz">border test2</div>
  <div id="_2EWJ0p0M9i7zNLMpM4YhOW">border test id</div>
  <h1>Hello World</h1>
  <span class="qwe">3333</span>
  <span id="eee">4444</span>
  <div class="outer">
    <div class="inner">
      bold
    </div>
  </div>
</body>

结论:

  • 只要require了一个css,这个css会被预处理成css module(前提是打开了css-loader的module参数),然后添加由style-loader把处理后的内容到html中
  • 预处理的过程会把css中所有自定义的标识符(除标签选择符、以及global修饰外),都进行编码处理成另一个一一对应的标识符(猜测编码的主体包括选择符和文件名),这样被添加进html之后,虽然都是全局作用的,但不同css module之间同名的选择符会被编码成不同的标识,也就互不影响,就达到了“作用域”的目的了
  • 在js中使用的时候,可以通过导入的模块来获取转换后的标识符,从而为dom动态使用不同css module中样式
  • 以组件的概念来理解这里的应用场景,一个组件依赖于css,对这个css进行module预处理后,然后在js中动态获取预处理后标识,应用组件中样式。这样一来,组件间的样式就不会互相影响了。可见,要达到这样的目的,必须要动态处理样式,因为html中的类、id等不会被进行预处理。

组合class

dep.css

.depclass{
    color: darkmagenta;
}

combine.css

.red{
    background-color: red;
}
.content{
    composes: red;
    composes: depclass from './dep.css';
    border: 2px solid #000;
}

入口文件添加如下代码:

var c = require('./combine.css');
var html4 = '<div class="'+c.content+'">compose test</div>';
document.write(html4);

bundle.js有如下两段代码:

exports.locals = {
    "depclass": "_3o2XDTxGMaBRvs2mRiV1es"
};
//...
exports.locals = {
    "red": "_1KvM5G6-rmsDcUM_AatNkH",
    "content": "_3oH95_iAzM0qUNDaF3GCxv _1KvM5G6-rmsDcUM_AatNkH " + __webpack_require__(2).locals["depclass"] + ""
};

运行结果

<style type="text/css">
  ._1KvM5G6-rmsDcUM_AatNkH{
    background-color: red;
  }
  ._3oH95_iAzM0qUNDaF3GCxv{
    border: 2px solid #000;
  }
</style>
<style type="text/css">
  ._3o2XDTxGMaBRvs2mRiV1es{
    color: darkmagenta;
  }
</style>
<div class="_3oH95_iAzM0qUNDaF3GCxv _1KvM5G6-rmsDcUM_AatNkH _3o2XDTxGMaBRvs2mRiV1es">compose test</div>

结论:

  • 这次测试依赖了2个css,但运行的时候,发现只请求了一个bundle.js,而没有请求这两个css,是因为这两个css中的全部内容都打包到bundle.js中了。这就是webpack一个非常大的优点,组件化,减少网络请求次数
  • 被间接依赖的css,虽然没有在入口文件中调用require,但它的内容也被处理进来了,可见被require的css,中依赖了其他的css,这一系列的css都会被处理进来
  • compose提供一种简便的多个类的书写方式,支持组合当前文件中以及外部文件中的类;不用compose的话,自己在js中引用,然后拼接类名,再写到dom上也是没问题,如果要用到外部其他文件的话,还要自己去require,麻烦了些而已
  • 被引用的不管是直接引用(require)或者间接引用(compose),都会把这个被引用的文件内容全部加载进来

scss

修改配置文件如下:

 loaders:[
      { test: /.s?css$/, loader: 'style-loader!css-loader?modules!sass-loader' },
    ]

1.scss:

$primaryColor: #333;
.s1{
  background: $primaryColor;
  composes: s1 from './2.scss';
}

2.scss:

$borderColor: red;
.s1{
  border: 1px solid $borderColor;
}

入口文件:

var s = require('./scss/1.scss');
var html5 = '<div class="'+s.s1+'">scss test</div>';
document.write(html5);

打包:

exports.locals = {
    "s1": "_2KqHQfE-Ms43DCsHA7wfbk"
};

exports.locals = {
    "s1": "EhwNnMc7oenHygrKydr1t " + __webpack_require__(3).locals["s1"] + ""
};

运行结果:

<style type="text/css">
  $borderColor: red;
  ._2KqHQfE-Ms43DCsHA7wfbk{
    border: 1px solid $borderColor;
  }
</style>
<style type="text/css">
  .EhwNnMc7oenHygrKydr1t {
    background: #333; 
  }
</style>
<div class="EhwNnMc7oenHygrKydr1t _2KqHQfE-Ms43DCsHA7wfbk">scss test</div>

结论:

  compose进来的scss,并没有被scss-loader所处理。所以如果要实现相关的引入功能,就只能用scss中的引入语法了。compse仅仅支持css

link和import的区别:

原文地址:https://www.cnblogs.com/hellohello/p/7625540.html