webpack的核心概念loader之打包静态资源-样式篇

1.style-loader和css-loadder

我的页面中现在有一张猫咪得图片,如下:

cat.png

但是我觉得图片有点太大了,于是我给图片加了一个avatar的类名,并在src目录下新建了一个demo.css的样式文件,对图片的大小进行了限制:

.avatar{
    width: 150px;
    height: 150px;
}

写好之后,在src目录下的入口文件index.js中引入样式文件:

import './demo.css'

然后运行npm run bundle进行打包,这时候控制台就会报一个错误,如下所示:

error.png

翻译过来就是webpack需要一个合适的loader来处理css文件,这个时候我们就需要能够处理样式的loader:style-loader,css-loader来帮我们处理样式文件了,修改webpack配置文件如下:

rules: [{
                test: /\.(jpe?g|png|gif|svg)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                        name: '[name]_[hash:6]. [ext]',
                        outputPath: 'images',
                        limit: 204800 //表示当图片的大小超过200kb时,将其打包生成图片
                    }
                }
            },
            {//新增的代码
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            },
        ]

修改完之后还需要安装一下这两个依赖,

npm install css-loader style-loader -D

安装完成之后,运行npm run bundle再次打包,打包完成之后,打开页面,就可以看到我们的图片确实变小了:

css.png

css-loader的作用:css-loader会帮我们分析出几个css文件之间的依赖关系,最终把这些css文件合并成一个css文件;
style-loader的作用:在得到css-loader生成的内容之后,style-loader会把这段内容挂到页面的<head>中,如下所示:
style.png

这个<style>标签就是style-loader帮我们挂载到页面上的,所以在处理css文件的时候,我们需要css-loader和style-loader结合一起使用,才可以让我们的样式起作用

2.sass-loader

假如我的css文件是.scss文件,那又该如何处理呢?

//demo.scss
.avatar{
    width: 150px;
    height: 150px;
}

在index.js中导入:

//index.js
import  './demo.scss'

我们运行npm run bundle重新打包,这个时候命令行中会报一个错:

error.png

翻译过来就是webpack需要一个合适的loader去处理.scss的文件,这个时候sass-loader就出场了,安装一下这个loader:

npm install sass-loader node-sass  -D//官网有说使用sass-loader的时候,必须安装node-sass

修改配置文件如下:在rules数组中新增这个配置对象

{
                test: /\.scss$/,
                use: ['style-loader', 'css-loader', 'sass-loader']
            },

修改完成后,我们再次打包代码,这个时候就可以看到代码可以正常打包了,回到页面,可以看到我们的样式也是生效的.

注意:loader的执行顺序是从右到左,从下到上,所以当我们去打包一个scss文件的时候,实际上首先sass-loader将scss文件翻译转换成css文件,再由css-loader处理各个文件之间的依赖关系,将css文件合并成一个css文件,再由style-loader将处理好的文件添加到页面的<head>部分的<style>中。

3.postcss-loader实现自动添加浏览器厂商前缀

demo.scss文件修改如下:

.avatar{
    width: 150px;
    height: 150px;
    transform: translate(100px,100px);
    
}

安装postcss-loader:

npm install  postcss-loader   -D

要实现自动添加浏览器厂商前缀,我们还需要一个插件:autoprefixer

npm install autoprefixer  -D

postcss配置文件:

//postcss.config
module.exports = {
    plugins: [
        require('autoprefixer')
    ],
};

再次打包代码,就可以看到transform前面被添加了浏览器前缀。

4.loader的配置项

代码修改如下:

//index.js入口文件
import './demo.scss'

//demo.scss
@import './avatar.scss';
.avatar{
    width: 150px;
    height: 150px;
    transform: translate(100px,100px);  
}

//avatar.scss
body{
    height: calc(100vh - 20px);
}

也就是在之前的基础上,我在demo.scss文件中又引入了另一个scss文件,也就是在import引入的文件中,又通过@import引入了别的scss文件,那么这个时候打包对于在index.js中引入的demo.scss文件它会依次调用postcss-loader,sass-loader,css-loader,style-loader,但是打包demo.scss这个文件的时候,它里面又通过@import引入了另一个scss,那这个时候可能会出现对于avatar.scss文件没有经过postcss-loader和sass-loader的处理,就直接用css-loader和style-loader来处理了,这样显然是不对的,我想让在demo.scss文件中通过@import导入的scss文件也通过postcss-loader,sass-loader,css-loader,style-loader这几个loader的处理,这个时候,就需要修改一下配置文件了:

{
                test: /\.scss$/,
                use: ['style-loader', {
                    loader: 'css-loader',
                    options: {//新增加的
                        importLoaders: 2
                    }
                }, 'sass-loader', 'postcss-loader']
            },

importLoaders: 2意思是通过@import导入的文件也需要postcss-loader,sass-loader这两个loader的处理,这样配置了以后就可以保证通过@import引入的scss文件也能够经过所有loader的处理,就不会有任何问题了。

5.css打包的模块化

模块化css:指某个文件内的样式只在该文件内有效,不会对其他地方的文件造成影响
首先一起看一个案例:

//src/avatar.js
    import avatar from './assets/bottom.png'
    function createAvatar() { //创建一张图片,并把图片放到页面上
        var img = new Image()
        img.className = 'avatar'
        img.src = avatar;
        document.body.appendChild(img)
    }
    export default createAvatar

下面是入口文件:

//index.js
import './demo.scss' //这样引入的样式相当于是全局样式,这样很容易造成样式的全局污染
import createAvatar from './avatar.js'//引入创建图片的js文件
import avatar from './assets/bottom.png'

createAvatar()
// 这里创建了另一张图片
var img1 = new Image()
img1.className = 'avatar'
img1.src = avatar;
document.body.appendChild(img1)

重新打包代码,你就会发现,页面中的两张图片其实都有.avatar这个类对应的样式,那如果我想让这个样式只作用于某个文件,该怎么做呢?这个时候css模块化就显得格外重要了,我们需要修改一下配置文件,给options多添加一个属性就可以了:

{
                test: /\.scss$/,
                use: ['style-loader', {
                    loader: 'css-loader',
                    options: {
                        importLoaders: 2,
                        modules: true//新增加的
                    }
                }, 'sass-loader', 'postcss-loader']
            },

这句话的意思是开启css的模块化打包,还需要修改一下index.js文件:

import style from './demo.scss'
import createAvatar from './avatar.js' //引入创建图片的js文件
import avatar from './assets/bottom.png'

createAvatar()
// 这里创建了另一张图片
var img1 = new Image()
img1.classList.add(style.avatar)
img1.src = avatar;
document.body.appendChild(img1)

重新打包代码,完成后再回到页面,就会发现只有一个图片添加了.avatar的样式,另一张完全没有被影响,如果我们想让另一张图片也有对应的样式,只需要在对应的文件中再引入一下样式即可:

//avatar.js
    import avatar from './assets/bottom.png'
    import style from './demo.scss' //引入对应的样式

    function createAvatar() { //创建一张图片,并把图片放到页面上
        var img = new Image()
        img.classList.add(style.avatar)
        img.src = avatar;
        document.body.appendChild(img)
    }
    export default createAvatar

这样两张图片就都有.avatar的样式了,这就是css module的概念,这样做带来的好处就是一个模块里面的样式和其他模块里面的样式不会有任何的冲突,这样我们写样式就不怕会被其他地方的样式覆盖的问题.

6.webpack打包字体文件

首先我们在阿里巴巴矢量图标库下载项目需要的图标,然后将图标保存到项目中,我放在了如下目录:

font.png

样式文件iconfont.css放在了src下,入口文件中的代码如下所示:

import './iconfont.css' //导入iconfont的样式文件
var root = document.getElementById('demo');
root.innerHTML = "<i class = 'iconfont icon-icon-star '/>"//在页面添加一个i元素

修改完之后,直接打包代码,完成后回到页面就会看到小图标已经显示出来了,但是在之前的webpack中,是需要配置loader的,如下所示:

{
            test: /\.(eot|ttf|svg)$/,
            use: {
                loader: 'file-loader'
            } 
        }

但是现在已经不需要了,如果你没有将字体下载下来而是使用的线上的,做法也是一样的,都比较简单,这里就不赘述了.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容