webpack核心,Loader打包样式资源

2.jpg

写在前面

之前的文章给大家介绍了Loader,并带大家使用了file-loaderurl-loader这样的loader来处理图片,当我们查阅官网就会发现,loader的种类有很多很多,各自承担的功能也不尽相同,今天我带大家了解一下专门编译样式资源的loader,首先我们对之前的代码做如下改动

import Banner from './banner.jpg'
import './index.css'
var img = new Image()
img.src=Banner
img.classList.add('banner')
var root = document.getElementById('root')
root.append(img)
.banner {
    width: 150px;
    height: 150px;
}

这个时候打包我们会发现报错了,自然,我们就想到了用loader去编译这样的webpack不认识的模块。

style loader 和 css loader

通常我们要编译css样式文件,需要用到两个loader,即style-loadercss-loader,我们先安装,并做如下配置,打包先看一下,完事再给大家讲解

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

我们发现,打包成功了,页面中的样式也生效了,下面我们让我将样式文件分离出去,让它再复杂一点

|--src
|--|--banner.css
@import './banner.css'

我们再来打包试一下,会发现一样的效果,那么在这些打包的过程中css-loader为我们干了什么样的事情呢

首先css-loader会分析出项目中的css文件之间的关系,然后将多个css模块的文件合并打包,style-loader在检测到css-loader为我们生成的css文件后,会把生成的css挂载到页面的head部分。为了证实这一点,大家可以检查元素,看一下

head.PNG

所以,我们在处理样式文件的时候一定要配合style-loader使用!

针对高级css语法的loader

我们在通常的开发中,一般会用到注入less,sass,scss等这样的高级的样式语言,那么我们是如何编译这些语言的呢?
首先我们对我们的项目文件做如下修改,然后对应引入

// index.scss
body {
    .banner {
        width: 150px;
        height: 150px;
    }   
}

当然,编译结果肯定也是报错,这个时候,又该我们修改webpack配置了。
这时候就需要我们借助其他loader把scss语法翻译成css语法了,然后就和之前的一样了。这个loader就是sass-loader,我们可以到webpack官网查看文档介绍,安装,并做相应的配置。

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

这时候再编译,会发现编译成功,且head中的样式文件如下


1.PNG

这里我们要特别注意一下loader的执行是按照配置的从下到上,从右到左执行的
对于样式文件,我们有时候还会遇到一些css3的特性,我们知道,在使用css3特性的时候,一般都需要我们在属性前面加上注入-wbekit-之类的“厂商前缀”,我们现在修改一下代理,打包一下

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

我们发现生成的样式文件中,并没有假如厂商前缀,其实我们也是有对应的laoder帮我们加上的,也就是postcss-loader,我们看一下文档,做相应配置试一下效果。

use: [
  'style-loader',
  'css-loader',
  'sass-loader',
  'postcss-loader'
]

但我们发现并没有生效,我们还需要按照postcss-loader的配置方法,在postcss.config.js中配置autoprefixer插件,安装后配置如下

module.exports = {
    plugins: [
        require('autoprefixer')
    ]
  }

这个尝试完,发现并不能生效,但我们的配置也是没问题的,这时候,需要我们在package.json中配置一手(配置项目支持的浏览器版本)

  "browserslist": [
    "defaults",
    "not ie <= 8",
    "last 2 versions",
    "> 1%",
    "iOS >= 7",
    "Android >= 4.0"
  ]

这样就OK了,试试吧~

扩展

上面我们介绍了过于样式打包的相关loader,接下来我们将针对样式打包再进行较深入的配置讲解

扩展css-loader配置

如果要扩展配置,那么loader配置就不是个字符串了,会变成下面这样

use: [
    'style-loader',
    {
        loader: 'css-loader',
        options: {
            importLoaders: 2,
        }
    },
    'sass-loader',
    'postcss-loader'
]

其中loader项为我们使用的loader名称,options项为我们的配置项,大家看我配置了importLoaders项,下面我简单说一下他的作用,考虑下面这种情况

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

我们在scss文件中又引入了另外的scss文件,我们在打包时,对于index.scss文件,他的loader执行顺序为从下到上一次执行一遍,但是对于其中引入的‘banner.scss’文件就会就可能会跳过postcss-loadersass-loader直接进入css-loader,这样必然会报错的,我们在css-loader中配置importLoaders就会保证每一个scss文件都会重新走前面两个loader。

样式打包模块化(css module)

考虑下面一种情况,假如我们不同的页面或者是使用vue/react开发的不同的组件,如果我们有相同的类名,那么当他们处于同一个样式文件作用下时就会发生覆盖,就像下面的代码一样

import Banner from './banner.jpg'
function createBanner () {
    var img = new Image()
    img.src=Banner
    img.classList.add('banner')
    var root = document.getElementById('root')
    root.append(img)
}
export default createBanner
import Banner from './banner.jpg'
import './index.scss'
import createBanner from './createBanner'
createBanner()
var img = new Image()
img.src=Banner
img.classList.add('banner')
var root = document.getElementById('root')
root.append(img)

上面的代码中,我们创建了一个函数,这个函数生成一张图片,并且同样拥有'banner'的类名,我们将它引用到index.js中,这时我们打包后运行会发现,index.js中引入的index.scss样式会加在两张图片中,这是我们不想看到的,于是就有了CSS Module的概念,我们在css-loader中加入这样的配置项目

{
    loader: 'css-loader',
    options: {
        importLoaders: 2,
        modules: true,
    }
},

然后再引用的时候下面这种方式引用

import style from './index.scss'
import Banner from './banner.jpg'
import style from './index.scss'
import createBanner from './createBanner'
createBanner()
var img = new Image()
img.src=Banner
img.classList.add(style.banner)
var root = document.getElementById('root')
root.append(img)

这时候再打包试试,你会发现样式之间不再相互影响了。假如有复用的需求,以同样的方式引用即可。

打包字体文件

我们改造我们的项目哈,当然也可以自己搭建一个,下面的内容和之前的没有太大关系了,我这边就直接改原来的项目成下面这样

var root = document.getElementById('root')
root.innerHTML = '<div class="test">abc</div>'

打包后运行是啥样子这里就不赘述了,大家应该能想象到,现在有这样一个需求,我们希望再页面中使用字体文件来替换我们的文本字体。

  • 我们首先从iconfont官网下载几个字体图标到我们本地(下载方法自行解决)
  • 然后再src目录下新建'font'文件夹,将字体文件拷如,大概文件如下


    font.PNG
  • 我们将下载下载下来的字体文件中的‘iconfont.css’文件中的内容替换至index.scss中。并且将引用的路径写对,大概如下
@font-face {font-family: "iconfont";
    src: url('./font/iconfont.eot?t=1596637328641'); /* IE9 */
    src: url('./font/iconfont.eot?t=1596637328641#iefix') format('embedded-opentype'), /* IE6-IE8 */
    url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'),
    url('./font/iconfont.woff?t=1596637328641') format('woff'),
    url('./font/iconfont.ttf?t=1596637328641') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
    url('./font/iconfont.svg?t=1596637328641#iconfont') format('svg'); /* iOS 4.1- */
  }
  • 我们在自己的元素中使用字体图标类
import './index.scss'
var root = document.getElementById('root')

root.innerHTML = '<div class="iconfont iconduosesvggeshiyimeitubiao-01"></div>'

按理说,我们字体图标的样式文件,样式都配好了,打包应该会比较顺利,其实这个时候打包时报错的,因为我们的index.scss中,引用了后缀是‘.eot’‘.woff’‘.ttf’‘.svg’的文件,这时候还需要我用用file-loader转一下,我们在配置中假如这样的配置。

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

这个时候再打包,发现页面就出现了我们需要的图标。

写在最后

这篇讲的东西比较多,主要是为大家介绍了,webpack针对于样式文件的打包,看过本节文章,相信你对这一块的知识有了一定的了解也。接下来,我们将深入更深的内容,关注我,不迷路...

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