loader
什么是loader
Loader的作用是帮助webpack去打包,webpack不能识别的文件。 webpack只能识别js文件,那些webpack不能识别的文件,就需要loader去进行识别解析。
下面以打包图片为例,简单分析一下loader的工作过程。
首先下载一张图片
-
将图片存进
src/imgs
之下,目录结构如下:
- 在我们的入口文件引用,并将它插入进html之中
import img from './imgs/twice.jpg'
console.log('file is', img)
const ImgElement = new Image();
ImgElement.src = img;
document.getElementById('root').append(ImgElement)</pre>
-
这时候直接去使用webpack打包会报错,因为webpack不能识别以jpq为结尾的图片文件。这时候需要借助loader
-
具体使用什么loader,翻阅官方文档。图片可以使用
file-loader
- 安装:
npm install file-laoder -D
- 安装:
将loader配置进webpack的文件内
-
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
module: {
rules: [{
test: /\.jpg$/,//匹配jpg为结尾的文件
use: [{
loader: 'file-loader'
}]
}]
},
output: {
filename: "bundle.js",
path: path.resolve(__dirname, 'dist')
}
}
再运行命令,这次成功打包并且页面上也可以看到。
-
打开控制台,可以看到刚刚输出的内容,是文件的文件名
-
并且在dist目录之下,也同样生成了一份乱码后的图片,文件名与输出内容一致。
由此可以看出,loader会先将文件移动到dist这个文件夹下,然后再返回这个文件的地址,最终打包
-
总结:file-loader执行顺序
会先将文件移动到dist这个目录下面
然后将这个文件的地址返回给这个变量
打包静态资源
打包图片
在上面的loader介绍中,已经使用过file-loader
对文件进行过简单的打包。接下来会使用file-loader
以及url-loader
对图片资源进行打包
为loader配置option,对打包产生的文件增加更多的配置。
使用
placehodler
设置文件名,当前输出文件是以hash值作为文件名使用
outputPath
设置图片的存放路径test: /\.jpg$/, use: [{ loader: 'url-loader', options: { name: '[name].[ext]', outputPath: 'images' } }] }]
重新生成的就是想要的文件路径与文件名了。
使用url-loader
除了file-loader
以外,url-loader
也可以对文件资源进行打包。
安装:npm install url-loader --save-dev
将原有的file-loader
替换成url-loader
module: {
rules: [{
test: /\.jpg$/,
use: [{
loader: 'url-loader',
options: {
name: '[name].[ext]',
outputPath: 'images'
}
}]
}]
}
图片还是可以成功被打包出来。
那么url-loader
与file-loader
的区别在于哪里呢?我们可以点开F12去查看一下这个文件
可以发现,这个文件已经被url-loader
解析成了base 64的String。然后直接将这个字符串放进bundle.js之中。
所以对比file-loader
, url-loader
更适用与小的图片,并且可以少请求一次对图片的http请求。不然图片过大会增加页面的加载速度,降低性能。
但url-loader
可以配置一个limit属性,在超过限制大小时,会像file-loader一样解析图片。
options: {
name: '[name].[ext]',
outputPath: 'images',
limit:8192 //limit to 8kb
}
这里将大小限制到8kb(源文件大小在11kb左右),由于图片大于限制大小,所以并不会被打进bundle.js
打包样式
想要给图片增加一些样式,添加一个style.css的样式文件。里面添置一些文件的样式:
.twice_img {
width: 400px;
height: 400px;
margin: auto;
}
将这个样式文件引入到入口文件之中,并将这个class添加到img element之中。
import img from './imgs/twice.jpg'
import './style.css'
console.log('file is', img)
const ImgElement = new Image();
ImgElement.src = img;
ImgElement.classList.add('twice_img');
document.getElementById('root').append(ImgElement)
现在直接打包显然肯定是会失败的。还是哪一个原则:webpack只能识别js,不能识别其他文件。这里要引入两个loader去识别css文件:css-loader
, style-loader
。
- 安装
npm install style-loader css-loader -S
在安装完成之后,在webpack.config.js文件之中添加css的配置
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
重新打包之后,打开页面,可以看到图片变大,并且居中,样式也覆盖上去了。
这里说明一下,为什么需要两个loader。
- css-loader的作用是帮助webpack去识别样式文件
-
style-loader的作用是将样式挂载到html的style标签里。
打包scss文件
在项目中一啊不能都会使用sass
或者less
的预编译css文件。这里也打包一下sass文件。
- 安装loader
npm install sass-loader sass -S
改写一下样式文件style.css
--->style.scss
body {
#root {
width: 100%;
height: 100%;
}
.twice_img {
display: block;
width: 400px;
height: 400px;
margin: auto;
}
}
更改一下打包策略
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
}
再重新打包一下,打开页面
添加postcss
如果在样式中需要使用一些css新特性如grid
之类的,需要对样式做兼容性处理,前面拼上厂商前缀如,-webkit-
等
安装postcss-loader
以及autoprefixer
npm install postcss-loader autoprefixer -S
配置postcss.config.js
,放在和webpack.config.js同一目录之下。
module.exports = {
plugins: [
require('autoprefixer')
]
}
配置完之后重新打包,但是从页面上并没有看到拼的厂商前缀:
原因是在package.json文件之中需要添加浏览器支持配置,添加一下就可以看到了。
...
"devDependencies": {
"css-loader": "^3.5.3",
"style-loader": "^1.2.1"
},
"browserslist": [
"defaults",
"not ie <= 8",
"last 2 versions",
"> 1%",
"iOS >= 7",
"Android >= 4.0"
]
}
打包样式,loader常用的配置项
importLoaders
先描述一种场景,将scss的代码进行分割,放置在不同的文件之中。然后在style.scss
这个文件中引入其他的scss文件。
这种场景之下,scss文件中引入的其他scss文件可能会不依次走
['style-loader', 'css-loader', 'sass-loader', 'postcss-loader']
这个顺序,可能会直接走css-loader
以及style-loader
这两个loader,从而导致样式失效。
importLoaders
的作用就是,可以确保引入的scss文件也能将执行css-loaders之前的loaders执行完。
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2,
// 0 => no loaders (default);
// 1 => postcss-loader;
// 2 => postcss-loader, sass-loader
}
},
'sass-loader',
'postcss-loader'
]
modules
这loader使用的场景是:css模块化。
比如我现在将创造图片元素这一段逻辑抽离出来变成一个function。并且放在一个新的文件createImg.js
之中。然后在index.js之中去调用这一个方法。
import img from './imgs/twice.jpg'
import './style.scss'
import createImage from './createImg'
createImage()
const ImgElement = new Image();
ImgElement.src = img;
ImgElement.classList.add('twice_img');
document.getElementById('root').append(ImgElement)
这样从页面上就会得到两个一模一样的图片,并且样式也一样。因为在index.js
中都引用了样式文件,在一定程度上造成了样式污染。为了让两个图片拥有不一样的样式,可以将样式模块化。
添加module的配置
{
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2,
// 0 => no loaders (default);
// 1 => postcss-loader;
// 2 => postcss-loader, sass-loader,
modules: true
}
},
'sass-loader',
'postcss-loader'
]
}
同时对代码进行改写
import style from './style.scss'
import createImage from './createImg'
createImage()
const ImgElement = new Image();
ImgElement.src = img;
ImgElement.classList.add(style.twice_img); // twice_img是class的类名
document.getElementById('root').append(ImgElement)
分成不同模块之后,生成的图片样式就不相同了。
打包字体
在项目中最常见的字体应用场景就是由font生成的那些icon了。
从iconFont上将字体下载之后,放在src/fonts
的文件里。附带的字体申明样式放在font.scss
之中,项目的目录如下:
在生成的dom元素上加上相对应的iconfont的class
const iconHtml = `<span class="icon iconfont icon-Dyanjing"></span><span class="icon iconfont icon-caidan"></span>`
document.getElementById('root').innerHTML = iconHtml;
最后更改一下打包规则,添加对字体文件的打包:
{
test: /\.(eot|woff2|woff|ttf|svg)$/,
use: [{
//placeholder
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts',
}
}]
}
打包一下,打开页面,icon就成功出现啦: