在webpack看来 一切皆模块,图片,样式文件,js文件… 。 但是webpack默认只能处理js模块,对于非js的内容它就需要一些帮手来处理了。这些帮手就是loader。
webpack 可以使用 loader 来预处理文件。这允许你打包除 JavaScript 之外的任何静态资源。你可以使用 Node.js 来很简单地编写自己的 loader。
处理css文件
下面,我们来讨论如何处理.css文件。
创建.css文件
在src目录下,再次创建一个css目录
|-src
|-src/css
|--------public.css
|--------style.css
src/css/public.css的内容如下
body,html{
padding:0;
font-size:14px;
}
src/css/style.css的内容如下
@import "public.css";
div {
border:4px solid #ccc;
width: 50%;
height: 200px;
margin:30px auto;
box-shadow: 3px 3px 3px #ccc;
background-color: #fff;
text-align: center;
}
说明:
- @import语句用来导入另一个css文件。
如果希望在.html文件中使用style.css样式,我们以前只学习过一种方式:直接在.html中通过link的方式来引入 。
那如果在js中引入了css会怎么样呢?
在.js中导入css
在js文件中引入css,就像vue项目中引入第三方ui样式一样,如element-ui的使用说明中提到的:
import Vue from 'vue';
import ElementUI from 'element-ui';
// 引入 css
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';
Vue.use(ElementUI);
new Vue({
el: '#app',
render: h => h(App)
});
很明显,上面的.js代码中引入了.css。
下面,我们修改自已的main.js,在 src/js/main.js中,引入css。
// nodejs中的模块化
const { updateDom } = require('./tool')
// es6中的模块化
import {log} from './tooles6'
+ import '../css/style.css'
updateDom ('app','index.html')
log('test')
再次,打包代码,会报错。
ERROR in ./src/css/style.css 1:0
Module parse failed: Unexpected character '@' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> @import "public.css";
| div {
| padding:20px;
@ ./src/js/main.js 4:0-26
上面报错的原因是:webpack把.css文件内容当作了js代码来运行,那当然会报错了。所以,解决方法是安装相应的loader来处理。
安装并使用css-loader
对于loader的使用,其基本步骤是一致的,分成两步:
-
- 安装loader包
-
- 配置webpack.config.js中的module
安装
npm i css-loader -D
--------------------
+ css-loader@4.1.1
added 16 packages from 51 contributors in 14.718s
7 packages are looking for funding
它也是开发依赖。
在配置文件中使用
修改webpack.config.js文件,添加modules
const path = require('path')
module.exports = {
mode: 'development',
entry:'./src/js/main.js',
output:{
path:path.resolve(__dirname, './build'),
filename:'bundle.js'
},
+ module:{ // 处理非js模块
+ rules:[ // 规则
+ {
+ test: /\.css$/, // 正则测试
+ use: ['css-loader'] // loader
+ }
+ ]
+ }
}
再次打包
它不会报错。但是,页面上也并没有出现样式的效果。打包之后的文件中并没有包含css代码。
安装并使用style-loader
如果我们希望样式生效,最终在.html文件中有两种情况:
- 有style标签
- 有link标签
而css-loader只是能让你在.js中通过import来引入.css,如果你希望引入的css代码最终以style标签的方式插入到html页面中,则还需要安装一个loader:style-loader
安装
npm i style-loader -D
---------------
+ style-loader@1.2.1
added 4 packages from 6 contributors in 13.086s
8 packages are looking for funding
run `npm fund` for details
配置
// nodejs模块,对整个打包过程做设置
const path = require('path')
// __dirname : 当前文件夹的绝对路径
// path.join(): 路径拼接
const pathValue = path.join(__dirname, 'dist123')
// console.log(pathValue)
module.exports = {
// 设置打包的方式
mode: "development",
// 设置入口文件
entry: "./src/js/main.js",
// 设置出口文件
output: {
path: pathValue,
filename: 'abc.js'
},
// 用写loader的配置。用来处理那些 非js模块
module: {
rules:[ //规则: 什么文件,用什么loader来处理
{
test: /\.css$/, // 用正则匹配
use:['style-loader','css-loader'] // 如果匹配成功,就使用Loader
// 如果它是一个数组,则表示当匹配成功之后从右向左依次去使用loader。
// css-loader: 允许你通过Import的方法引入css
// style-loader: 可以把css以style标签的格式插入到html中
}
]
}
}
Tip: 在有多个loader的情况下,use数组中的loader执行顺序是从右到左的过程。即:
- 先用css-loader来处理css
- 再用style-loader把css代码插入到html中的style标签中。
打包查看效果
index.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<div id="app">
</div>
<!-- 引入两个js文件 -->
<!-- <script src="./tool.js"></script> -->
<!-- <script src="./index.js"></script> -->
<script src="./dist123/abc.js"></script>
</body>
</html>
现在就能看到css的效果了 。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0b8qP0Xh-1596243713654)(asset/image-20200731143422794.png)]
原理是:
- bundle.js中有一些js代码,它在运行时,会自动在.html文件中追加style标签,并输出样式。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vtLZWkts-1596243713657)(asset/image-20200603143508746.png)]
拓展
你可以分析打包之后代码,来验证style-loader的工作原理。在bundler.js中,可以找到类似如下的代码:
eval("var api = __webpack_require__(/*! ../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ \"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js
再去node_modules\style-loader\dist\runtime\injectStylesIntoStyleTag.js
找下insertStyleElement
这个方法,你就可以发现这个过程。
处理less文件
如果希望处理less文件,则还需要去安装额外的包。
创建less文件
在src目录的css目录下创建 index.less,则内容如下:
@import "style.css";
body{
div {
padding:50px;
}
}
在.js中引用.less
在src/js/main.js文件中引入less
// nodejs中的模块化
const { updateDom } = require('./tool')
// es6中的模块化
import {log} from './tooles6'
- import '../css/style.css'
+ import '../css/index.less'
updateDom ('app','index.html')
log('test')
安装包
参考官网
npm i less-loader less -D
-------------------------
+ less@3.11.2
+ less-loader@6.1.0
added 50 packages from 123 contributors in 23.883s
- less 用来把less–>css
- less-loader用来加载less文件。
配置模块
在rules中添加一个配置,专门针对less文件。
module.exports = {
// 非js模块,在这里处理
module: {
rules:[ //规则: 什么文件,用什么loader来处理
{
test: /\.css$/, // 用正则匹配
use:['style-loader','css-loader'] // 如果匹配成功,就使用Loader
// 如果它是一个数组,则表示当匹配成功之后从右向左依次去使用loader。
// css-loader: 允许你通过Import的方法引入css
// style-loader: 可以把css以style标签的格式插入到html中
},
+ {
test: /\.less$/, // 用正则匹配
use:['style-loader','css-loader','less-loader'] // 如果匹配成功,就使用Loader
// 如果它是一个数组,则表示当匹配成功之后从右向左依次去使用loader。
// (1) less-loader: 把less加载,转成css
// (2) css-loader: 允许你通过Import的方法引入css
// (3) style-loader: 可以把css以style标签的格式插入到html中
+ }
]
}
}
注意:如上配置中,对于less文件的处理涉及三个loader,其处理顺序是less-loader --> css-loader–>style-loader。
- less-loader:用来加载less文件,并处理成css
- css-loader:用来加载css文件
- style-loader:用来将css代码以style标签的格式插入到html文件中
自动添加css样式前缀
目标:通过postcss及相关工具来处理兼容性问题
步骤
安装依赖
补充loader
单独设置postcss
安装依赖 npm i postcss postcss-loader autoprefixer -D
补充loader
{
test: /\.less$/,
// 匹配成功后(从后向前;从右到左)
// 1. 先用less-loader去加载.less文件,转成css
// 2. 用postcss-loader配合autoprofixer加浏览器前缀
// 3. 先用css-loader去加载css文件
// 4. 再用style-loader把样式以style标签的方式嵌入到html中
use:['style-loader', 'css-loader', 'postcss-loader', 'less-loader']
}
单独设置postcss
const autoprefixer = require('autoprefixer')
module.exports = {
plugins:[
autoprefixer({
// last 10 versions : 浏览器最近的10版本
// >10% 全球市场占有率在10%以上的浏览器
// overrideBrowserslist: ['last 2 versions', '> 1%']
})
]
}
特别地:对于要支持的浏览器的设置,也可以写在package.json中
{
// ......
"browserslist": "ie 10"
}
查看当前支持的浏览器的列表npx browserslist
url-loader-处理图片文件
参考链接:npm官网
如果在css(或者less)中通过url()
引用了图片,则还需要使用特殊的url-loader。
在css中引入图片
-
在src下新增目录:img,并在其下放置两张图片:一张图片大一些,一张图片小一些(可以自行决定)。
- webpack.png: 49.4kb
- webpack.svg: 3kb
-
在style.css中引入图片,作为div标签的background。
@import "public.css";
div {
border:4px solid #ccc;
width: 50%;
height: 200px;
margin:30px auto;
box-shadow: 3px 3px 3px #ccc;
background-color:pink;
text-align: center;
+ background-image: url('../img/webpack.png')
}
现在,直接打包,会报错。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a4eoRdWX-1596243713660)(asset/image-20200603145626515.png)]
原因:webpack它自已只能处理.js。
安装url-loader
npm i url-loader -D
------
+ url-loader@4.1.0
added 4 packages from 6 contributors in 6.171s
配置
module:{ //
rules:[
// ...
{
test:/\.(png|svg)$/,// 正则匹配,以.png结尾的文件, 以.svg结尾的文件
use:['url-loader'] // 匹配成功,使用指定的loader
}
]
}
注意:
- 正则表达式中的写法
/\.(png|svg)$/
表示可以匹配.png和.svg文件。
再次打包
检查它的效果:把图片文件转成base64编码。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kMOnROa5-1596243713662)(asset/image-20200603150213249.png)]
好处:减少一次网络请求
坏处:增加了文件的大小
在实操的过程,会把一个较小的图片文件转base64,这样虽然会增加打包文件的大小,但可以减少一次网络请求,划算!
但是,如是一个文件特别大,就不适合去转base64:它会急剧增长打包文件的大小 。
下面来精细设置它能直接处理的文件阈值。
设置文件阈值
在modules中补充配置:
{
test:/\.(png|svg)$/,
use:[
{
loader:'url-loader',
+ options:{
+ limit: 3 * 1024 // 限制大小为3k
+ }
}
]
}
由于webpack.png的大小超过了上面的阈值,所以url-loader并不会处理这个图片文件,会报一个类似于如下的错误:
ERROR in ./src/img/webpack.png
Module build failed (from ./node_modules/url-loader/dist/cjs.js):
Error: Cannot find module 'file-loader'
报错的原因如下:当引入的文件大小大于或者等于指定的limit时,会交给file-loader来处理,同时把所有的参数也传给file-loader(参见这里的说明),而由于file-loader是另一个加载器,当前我们并没有安装它,所以报错了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TKfcxiuW-1596243713665)(asset/image-20200603152729013.png)]
安装并使用file-loader
安装
npm i file-loader -D
-----------------------
+ file-loader@6.0.0
added 4 packages from 6 contributors and removed 26 packages in 13.844s
11 packages are looking for funding
run `npm fund` for details
配置
不需要额外配置。如果url-loader处理不了,它会自动介入,file-loader会自动工作:它的处理结果是:
- 找到这个文件
- 复制一份,以hash值命名
- 放在output设置的出口文件夹下。
打包测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I4tAZ2yY-1596243713668)(asset/image-20200603153053111.png)]
页面上还是不会正确地显示出图片来,因为这个file-loader只是负责把较大的图片移到打包出口文件夹,而不会把这个文件的地址信息更新到.css,或者是.html文件,这个工作需要我们去使用一个plugin来解决。
练习:babel-loader
能够把es6高级内容变为es5的loader名称为 babel-loader
es6/es7/es8等等高级标准有很多(let、箭头函数、对象解构赋值、…展开运算符、反勾号字符串等等),每个标准都需要一个独立的plugin进行降级处理,如果使用许多高级标准内容,那么势必要为此安装许多plugin,这样工作比较繁琐,系统已经考虑到这点了,其通过preset把许多常用的plugin给做了集合,因此一般性的使用只需要安装preset即可搞定(如果项目应用到了一个生僻的高级标准内容,preset处理不来,就还需要再安装对应的plugin处理)
let----降级---->plugin
箭头函数----降级—>plugin
npm官网: babel-loader
babel官网:https://www.babeljs.cn/setup#installation
步骤:
-
安装依赖包
npm i babel-loader @babel/core @babel/preset-env -D
-
在webpack.config.js中做如下配置:
{ test: /\.js$/, exclude: /node_modules/, // 排除目录 use: [ { loader:'babel-loader', options: { presets: ['@babel/preset-env'] } } ] // es6转es5 }
说明: @babel/preset-env用来指定按什么样的预设来进行降级处理
-
打包测试
打包之后,去打包后的文件中检查是否已经把const和箭头函数这种es6的代码转成了es5的代码。
小结
- 一切皆模块,模块有loader
- loader
- 第一步:安装包
- 第二步:配置rules