这是一个关于Webpack4的文章系列,其中包含以下文章:
本系列文章源代码:
git clone https://github.com/davenkin/webpack-learning.git
在上一篇文章中,我们讲到了多入口文件的代码分割,本文我们将讲到CSS的处理。
欢迎访问本文github地址。
Webpack最基本的css处理:css-loader + style-loader。其中css-loader用于处理css文件中的@import
和url(...)
,而style-loader用于将css-loader的输出生成js中的函数调用将css动态添加到html文件中。
安装css-loader和style-loader:
cnpm install --save-dev css-loader style-loader
首先创建index.html:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Webpack4-CSS处理-index</title>
</head>
<body>
</body>
</html>
然后创建main.css:
body {
background-color: red;
}
这里我们将body设置成红色。
然后在index.js文件中直接importmain.css
:
import './main.css'
然后配置webpack.config.js,使webpack可以将css文件当做module对待(即可以进行import操作)以及使用css-loader和style-loader对css文件进行处理。
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
]
}
plugins:[
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
})
]
}
运行cnpm start
,可以看到红色页面出现。
style-loader将css动态添加到html文件中,有时(特别是在生产环境下)我们希望将所有的css抽离为独立的css文件,此时可以借助mini-css-extract-plugin
,安装mini-css-extract-plugin
:
cnpm install --save-dev mini-css-extract-plugin
将style-loader改为mini-css-extract-plugin的loader:
...
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
...
{
test: /\.css$/,
use: [ MiniCssExtractPlugin.loader, 'css-loader' ]
}
...
另外,还需要引入MiniCssExtractPlugin插件本身:
...
plugins: [
new CleanWebpackPlugin(['distribution']),
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
}),
new MiniCssExtractPlugin({
filename: "[name].[contenthash].css",
chunkFilename: "[name].[contenthash].css"
})
]
...
运行cnpm run build
,可以看到生成了独立的index._.css文件,另外所生成的index._.html文件中自动的引用了该css文件。
根据CSS Module的官网,CSS Module只对类名和动画的名字起作用。
css-loader支持CSS Module,CSS Module为每个独立的css文件处理为一个module。此时需要修改webpack.config.js文件中css-loader的配置:
...
{
loader: 'css-loader',
options: {
sourceMap: true,
modules: true,
localIdentName: '[name]---[local]---[hash:base64:5]'
}
},
...
其中,modules: true,
表示启用CSS Module,localIdentName
设置css类名的命名方式。
在main.css中加入更多的css:
body {
background-color: red;
}
div {
box-sizing: border-box;
}
.red {
background-color:red;
}
:global(.gold){
background-color:gold;
}
:local(.aqua){
background-color: aqua;
}
请注意这里的:global(.gold)
和:local(.aqua)
,前者表示脱离模块化约束而使用全局的声明(即效果跟普通css相同),后者表示使用模块化化处理,这里的:local
有点多余,因为当启用了CSS Module之后,css文件中的类名默认便是:local
的。
运行cnpm run build
,输出对应的css文件为:
body {
background-color: red;
}
div {
box-sizing: border-box;
}
.main---red---1GVbX {
background-color:red;
}
.gold{
background-color:gold;
}
.main---aqua---34_W6{
background-color: aqua;
}
可以看到,.main---red---1GVbX
对应原文件中的.red
,命名规则有localIdentName: '[name]---[local]---[hash:base64:5]'
配置完成。.gold
由于标记有:global
,所以生成的全局的类名。
SASS的基本使用请参考笔者这篇文章。
安装sass-loader:
npm install sass-loader node-sass webpack --save-dev
请注意,要使用sass-loader,同时需要安装node-sass。
修改webpack.config.js文件,首先让原来处理的css的loader也能处理scss文件:
...
test: /\.(s*)css$/,
...
然后加入sass-loader:
...
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
...
注意,sass-loader需要是处理scss/css文件的第一个loader,也即需要配置在最后面。
为了演示sass的使用,创建partial的_global.scss:
$base-color:red;
然后将公共的css内容移动到base.scss:
body {
background-color: red;
}
div {
box-sizing: border-box;
}
修改main.css文件为main.scss,内容如下:
@import './global';
:global(.gold){
background-color:gold;
}
:local(.aqua){
background-color: aqua;
}
.localRed {
background-color: $base-color;
}
可以看到,在main.scss文件中我们通过@import
引入了_global.scss
,然后对.localRed
应用了_global.scss
中的变量$base_color
。
作为演示,另外再创建main2.scss,情况与main.scss相似:
@import './global';
.red {
background-color: red;
}
.localRed {
background-color: $base-color;
}
最后,在index.js文件中引用base.scss,main.scss和main2.scss:
import './base.scss'
import './main.scss'
import './main2.scss'
运行cnpm run build
,输出css文件如下:
body {
background-color: red; }
div {
box-sizing: border-box; }
.gold {
background-color: gold; }
.main---aqua---Faovj {
background-color: aqua; }
.main---localRed---2p9T9 {
background-color: red; }
.main2---red---2xwE1 {
background-color: red; }
.main2---localRed---3yuRF {
background-color: red; }
可以看到,生成的css文件中有公共的base.scss中的内容,main.scss和main2.scss中的内容。
请注意,如果让main.scss和main2.scss也引用base.scss,那么body和div将出现3次,也即index.js、main.scss和main2.scss对base.scss的引用会重复出现;base.css中如果有类名声明,那么这些类名声明会同时出现在这3个引用它的module中,因为SASS分别以这三个文件为编译单位进行处理,最后将他们的内容合并到一起。因此,对于SASS来说,有个原则是如果有文件作为公共css文件,那么建议它最多只引用1次,通常是在入口文件中进行引用,比如VueJS的App.vue文件。
另外,除了@import partial文件(下划线作为前缀,比如_global.scss
,SASS不会单独进行编译)之外,一个scss文件中也可以@import其他常规scss文件,此时与partial一样,相当于将常规scss文件内容拷贝到了目的文件。
安装postcss-loader:
cnpm install --save-dev postcss-loader
添加postcss-loader:
{
loader: 'postcss-loader',
options: {
plugins: [require("autoprefixer")],
sourceMap: true
}
}
请注意,该loader的作用顺序应该在sass-loader和css-loader之间。
这里我们仅演示autoprefixer的使用,安装autoprefixer:
cnpm install --save-dev autoprefixer
然后在package.json中添加:
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
此时的输出文件中,请注意base.scss中的div配置:
div {
-webkit-box-sizing: border-box;
box-sizing: border-box; }
其中的-webkit-box-sizing
为autoprefixer自动加上的前缀。
当项目中有多个入口文件时,webpack会为每个入口文件生成对应的css bundle文件。
为了演示真实场景,创建模块createElement.js,让两个入口文件都依赖于该模块:
import style from "./createElement.scss";
export function createElement(className) {
let element = document.createElement('div');
element.style.height = "50px";
element.classList.add(style[className]);
element.style.marginBottom = "10px";
element.innerHTML = "Hello World.";
document.body.appendChild(element);
}
以及对应的scss文件createElement.scss:
.blue {
background-color: blue;
}
.yellow {
background-color: yellow;
}
.green {
background-color: green;
}
.gray {
background-color:gray;
}
:global(.deepskyblue){
background-color:deepskyblue;
}
:local(.fuchsia){
background-color: fuchsia;
}
修改index.js文件,使其依赖于createElement.js:
import _ from 'lodash'
import './base.scss'
import './main.scss'
import './main2.scss'
import {createElement} from './createElement'
createElement('yellow');
createElement('blue');
createElement('green');
增加index2.html文件:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Webpack4-CSS处理-index2</title>
</head>
<body>
</body>
</html>
相应地增加index2.js文件:
import _ from 'lodash'
import './main.scss'
import {createElement} from './createElement'
createElement('fuchsia');
createElement('gray');
再次运行cnpm run build
,可以看到webpack为两个入口文件分别生成了css bundle文件。
有时我们需要将真个项目中所有生成的css合并为一个文件,此时可以使用splitChunks:
splitChunks: {
cacheGroups: {
default: false,
vendors: false,
styles: {
name: 'styles',
test: /\.(s*)css$/,
chunks: 'all',
enforce: true
}
}
}
修改HtmlWebpackPlugin配置,使每个入口文件引用自己的bundle以及公共的styles chunk文件:
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
chunks: ['index', 'manifest', 'vendors', 'styles']
}),
new HtmlWebpackPlugin({
template: './src/index2.html',
filename: 'index2.html',
chunks: ['index2', 'manifest', 'vendors', 'styles']
}),
此时运行cnpm run build
,可以看到只有一个styles.*.css文件生成。
在下一篇文章中,我们将讲到开发环境与chan
Original url: Access
Created at: 2019-05-05 16:58:54
Category: default
Tags: none
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论