目标:
在webpack看来 一切皆模块,图片,样式文件,js文件… 。 但是webpack默认只能处理js, json模块,对于非js的内容它就需要一些帮手来处理了。这些帮手就是loader。
webpack 可以使用 loader 来预处理文件。这允许你打包除 JavaScript 之外的任何静态资源。
如果希望在.html文件中使用style.css样式,我们以前只学习过一种方式:直接在.html中通过link的方式来引入 ,这是传统的做法,在webpack语境下,我们将选择一条不同的道路:在js文件中引入了css。
下面来看一个典型的打包错误: 在入口文件中引用.css文件。
再次,打包代码,会报错。
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来处理。
webpack默认只能处理.js文件,它遇到其它类型的文件时,就需要下载相对应的包来帮着处理了。这些帮手就是loader。
我们来具体讨论如何处理.css文件。
基本学习步骤是:
在src目录下,再次创建一个css目录及两个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文件。
下面,我们修改src/js/main.js,在其中引入css。
import { updateDom } from './tool'
+ import '../css/style.css'
updateDom ('app','index.html')
上面的操作之后,打包会报错。
对于所有的loader的使用,其基本步骤是一致的,分成两步:
npm命令,以开发依赖的方式来安装。
npm i css-loader -D
--------------------
+ [email protected]
added 16 packages from 51 contributors in 14.718s
7 packages are looking for funding
修改webpack.config.js文件,添加module项。module的功能是:为webpack无法识别模块指定帮手
使用modules基本格式是:
module.exports = {
// 其它配置 ...
module: {
// rules: 规则
rules: [
{
test: 正则, // 用正则匹配后缀名
use: [loader] // 如果匹配成功,就用use中指定的帮手
}
]
}
}
下面是具体的配置
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
+ }
+ ]
+ }
}
它不会报错,但是,页面上也并没有出现样式的效果。
检查打包之后得到的目标代码.js文件,发现其包含css代码。但是,它为什么不会显示在页面上呢?
如果我们希望样式生效,最终在.html文件中有两种情况:
而css-loader只是允许你在.js中通过import来引入.css,如果你希望引入的css代码最终以style标签的方式插入到html页面中,则还需要安装一个loader:style-loader
npm开发依赖
npm i style-loader -D
---------------
+ [email protected]
added 4 packages from 6 contributors in 13.086s
8 packages are looking for funding
run `npm fund` for details
module: {
rules: [
// 每一个对象就是一条规则.
// test: 匹配
// use: 对匹配到的模块采用对应的loader
{
test: /\.css$/, // 正则匹配 .css文件
// 匹配成功后(从后向前;从右到左)
// 1. 先用css-loader去加载.css文件
// 2. 再用style-loader把样式以style标签的方式嵌入到html中
use: ['style-loader', 'css-loader']
}
]
}
注意:在有多个loader的情况下,use数组中的loader执行顺序是从右到左的过程。即:
index.html
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<div id="app">
div>
<script src="../build/main.js">script>
body>
html>
现在就能看到css的效果了 。
原理是:
你可以分析打包之后代码,来验证style-loader的工作原理。在main.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
这个方法,你就可以发现这个过程。
loader是webpack非常重要的概念
在webpack看来,一切皆模块: 每一个文件都是一个模块。
webpack默认只能处理json和js模块,对于其它的模块它需要对应的loader来处理
loader的基本使用是:
目标:在项目中支持使用less来写css代码。
在src目录的css目录下创建 index.less,则内容如下:
@import "style.css";
body{
div {
padding:50px;
}
}
在src/js/main.js文件中引入less
// nodejs中的模块化
const { updateDom } = require('./tool')
- import '../css/style.css'
+ import '../css/index.less'
updateDom ('app','index.html')
参考官网
npm i less-loader less -D
-------------------------
+ [email protected]
+ [email protected]
added 50 packages from 123 contributors in 23.883s
在rules中添加一个配置,专门针对less文件。
module: {
// 规则
rules: [
// ...
{
test: /\.less$/, // 如果这个模块以less结尾
// 如果在打包的过程遇到了.less,则:从右向左
// 1. 先用less-loader 读出内容,转成css
// 2. 用css-loader 读出内容
// 3. style-loader把读出的内容以style标签的格式
// 附加在.html文件上
use: ['style-loader','css-loader', 'less-loader'] // 设置要处理的loader
}
]
}
注意:如上配置中,对于less文件的处理涉及三个loader,其处理顺序是从右到左:less-loader --> css-loader–>style-loader。
大家是否遇到过浏览器兼容的问题?又是怎么处理的?更具体一点:display: flex有兼容性问题吗?
学习postcss-loader之后,就可以自动帮我们来处理这个问题。
tip: caniuse 这个网站可以查看兼容性问题,点击 这里查看flex的兼容性。
步骤
安装依赖
在modules中补充设置postcss-loader
单独设置postcss的autoprefixer插件
安装依赖
npm i postcss postcss-loader autoprefixer -D
补充设置postcss-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.config.js
const autoprefixer = require('autoprefixer')
module.exports = {
plugins:[
autoprefixer({
// last 2 versions : 浏览器最近的2版本
// >1% 全球市场占有率在1%以上的浏览器
overrideBrowserslist: ['last 2 versions', '> 1%']
})
]
}
默认是兼容所有最新版本。
通过npx browserslist
命令可以查看当前支持的浏览器的列表
下面是overrideBrowserslist中可以设置的结果
例子 | 说明 |
---|---|
> 1% | 全球超过1%人使用的浏览器 |
> 5% in US | 指定国家使用率覆盖 |
last 2 versions | 所有浏览器兼容到最后两个版本根据CanIUse.com追踪的版本 |
Firefox ESR | 火狐最新版本 |
Firefox > 20 | 指定浏览器的版本范围 |
not ie <=8 | 方向排除部分版本 |
Firefox 12.1 | 指定浏览器的兼容到指定版本 |
unreleased versions | 所有浏览器的beta测试版本 |
unreleased Chrome versions | 指定浏览器的测试版本 |
since 2013 | 2013年之后发布的所有版本 |
特别地:对于要支持的浏览器的设置,也可以写在package.json中独立设置browserslist项,同时删除overrideBrowserslist的设置。
{
// ......
"browserslist": "ie 10"
}
如果只支持ie 10 ,则flex只会加-ms-前缀
目标:支持在css中引入图片文件
思路:
在src下新增目录:img,并在其下放置两张图片:一张图片大一些,一张图片小一些(可以自己找图片)。
在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')
}
body {
+ background-image: url('../img/webpack.svg')
}
报错的原因是.svg, .png格式的文件webpack并不能直接处理。
安装包:npm i - D file-loader
添加rules
{
test: /\.(png|svg|jpg)$/, //
use: ['file-loader']
}
这样只是简单的拷贝功能。
补充设置路径
use: {
loader: 'file-loader',
options: {
outputPath: './img' // 它会在出口文件夹下创建一个img文件夹来保存图片
}
}
要注意:此时打包得到的图片的路径可能有问题,需要你把src下的index.html手动复制一份到目标文件夹,才能正确看到图片。(
后面会改成自动去复制
)
用作版本管理时,如果一个项目需要发布,只需要发布修改过的文件指纹;对于没有修改过的文件,用户在访问的时候,依旧可以使用浏览器缓存好的,无需二次加载,加速页面访问。
占位符名称 | 定义 |
---|---|
[ext] |
资源后缀名 |
[name] |
文件名称 |
[path] |
文件的相对路径 |
[folder] |
文件所在的文件夹 |
[contenthash] |
根据文件内容来定义hash ,文件内容不变,则contenthash 不变文,默认是md5生成 |
[hash] |
和整个项目的构建相关,只要项目文件有修改,整个项目构建的hash 值就会随之更改,默认是md5生成 |
[Chunkhash] |
和webpack 打包的chunk 有关,不同的entry 会生成不同的chunkhash 值 |
示例:
use: {
loader: 'file-loader',
options: {
name: '[name]_[hash:8].[ext]',
outputPath: './img' // 它会在出口文件夹下创建一个msg文件夹来保存图片
}
}
参考链接:npm官网
问题:如果在你的项目中,出现多次引入很小图片
的情况,会有什么后果?要如何解决?
答:会请求多次,加载速度会慢;
解决方案:
目标:在项目中支持对图片的处理:如果足够小就直接生成对应的base64编码值,否则就直接拷贝到指定位置。
下面,补充一个安装url-loader,并修改配置
npm i url-loader -D
修改后的配置如下:
{
test: /\.(png|svg|jpg)$/, // jpg
use: {
loader: 'url-loader',
// url-loader是增强版的file-loader
// 如果图片小于指定的大小,则会转成base64,否则就调用file-loader进行拷贝
options: {
limit: 3*1024, // 如果图片小于3k就转成base64,否则就直接拷贝
name: '[name].[ext]',
outputPath: './img' // 它会在出口文件夹下创建一个msg文件夹来保存图片
}
}
}
打包成功后,观察webpack对两张图片的不同处理。
在写js代码时,如果用到了一些比较高级的特性(箭头函数,函数默认参数等)时,可能会存在兼容性问题 ----- 低版本的浏览器(或者是ie系列)不支持,所以需要做降级处理。
能够把es6高级内容变为es5的loader名称为 babel-loader
es6/es7/es8等等高级标准有很多(let、箭头函数、对象解构赋值、…展开运算符、字符串模板等等),每个标准都需要一个独立的plugin进行降级处理,如果使用许多高级标准内容,那么势必要为此安装许多plugin,这样工作比较繁琐,系统已经考虑到这点了,其通过preset把许多常用的plugin给做了集合,因此一般性的使用只需要安装preset即可搞定(如果项目应用到了一个生僻的高级标准内容,preset处理不来,就还需要再安装对应的plugin处理)
npm官网: babel-loader
babel官网:https://www.babeljs.cn/setup#installation
步骤:
安装依赖包
npm i babel-loader @babel/core @babel/preset-env -D
在tool.js中修改一下函数,使用箭头函数和默认参数值
const updateDom = (id, content="函数的默认值") =>{
document.getElementById(id).innerHTML = content
}
在webpack.config.js中做如下配置:
{
test: /\.js$/,
exclude: /node_modules/, // 排除目录,通知webpack不要管这个目录下的js
use: [
{
loader:'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
]
// es6转es5
}
说明: @babel/preset-env用来指定按什么样的预设来进行降级处理
打包测试
打包之后,去打包后的文件中检查是否已经把const和箭头函数这种es6的代码转成了es5的代码。
如有不足,请多指教,
未完待续,持续更新!
大家一起进步!