Webpack 提倡一切皆模块,所有类型的文件(css、图片等)都可以经过 loader 处理变成我们可加载的模块。
1. loader 安装和配置
安装 loader 统一方式是 npm insatll xxx-loader --save-dev
-dev
表示开发时依赖。
webpack.config.js
基本配置方式:
module.exports = {
entry: ...,
output:{...},
module:{
rules:[
{
test: ...,
use:['xxx-loader','xxx-loader',...]
},
{...},
{...},
]
}
}
2. 样式处理
2.1 css-loader 和 style-loader
css-loader 通过 npm 安装,但是要把样式真正挂载到 dom 上,还需要安装 style-loader
通过 webpack.conifg.js
配置 css-loader 和 style-loader。注意 webpack 是从右向左读取的,书写顺序有要求。
module:{
rules:[
{
test: /\.css$/,
use:['style-loader','css-loader']
}
]
}
2.1 less-loader
同样的,还可以使用 less-loader:
module:{
rules:[
{
test: /\.css$/,
use:['style-loader','css-loader']
},
{
test:/\.less$/,
use:[{
loader:"style-loader"
},{
loader:"css-loader"
},{
loader:"less-loader"
}]
}
]
}
从 npm 3.x 开始,less 不会再随着 less-loader 的安装而自动给你安装,所以我们需要手动安装 less,也就是完整命令:npm install less less-loader --save-dev
,否则后续打包会报错。
3. 图片打包
和图片打包相关的两个 loader ,一个是 url-loader,一个是 file-loader。
如果图片较多,会发送很多 http 请求,降低页面性能。因此,url-loader 会将引入的图片编码,生成 base64 的 dataURL —— 相当于把图片数据翻译成一串字符,再把这串字符打包到文件中,最终只需要引入这个文件就能访问图片了。
当然,如果图片较大,编码会消耗性能,打包文件体积也会变大,因此 url-loader 提供了一个 limit
参数(一般是8kb),小于 limit
的图片依然被转为 DataURL;大于 limit
的图片则调用 file-loader 进行copy,并输出到 dist 文件夹中。 虽说 url-loader 封装了 file-loader,但实测如果不额外安装 file-loader 的话,在图片体积较大时打包还是会报错的,因此两个都要安装。
下面通过例子说明在 CSS 或者 JS 中使用图片时,loader 是如何处理的。
2.1 css 引用
这里我们在 src 下新建 img 文件夹,里面放 test1.jpg 和 tets2.jpg,一张大于8kb,一张小于8kb。在前面的 index.css
文件中,我们像往常一样使用图片作为背景:
div{
width:100px;
height:200px;
background:url("../img/test1.jpg");
}
之后打包发现报错,所以我们安装 url-loader,再次打包。浏览器查看:
会发现图片可以正常引用了,而且是以 dataURL 的形式引用的。
接着测试大于8kb的图片(修改上面代码为 test2.jpg )。这时,如果直接打包会报错提示缺少 file-loader,所以我们这里安装一下 file-loader。
再次打包,虽说这次不报错了,但是我们发现浏览器里图片没有显示出来。看一下控制台:
可以看到,路径是直接引用的图片名字,同时会看到 dist 文件夹下输出了原始图片的副本。也就是说,其实这时候 webpack 认为我们的 index.html
文件在 dist 文件夹中,所以选择了这样的路径引用,但其实我们的 index.html
文件在外层。同时,我们也不希望直接输出在 dist 文件夹下,最好是里面还有一个 img 文件夹,所以我们先来 webpack.config.js
配置一下:
{
test: /\.(png|jpg|gif|jpeg)$/,
use:[{
loader:"url-loader",
options:{
limit:8192,
outputPath:'img'
}
}]
}
这里就设置了图片的输出路径,另外,图片默认以 32 位 hash 命名,这样太长了,而且也不知道具体是哪张图片,所以我们顺便配置一下图片命名规则:
{
test: /\.(png|jpg|gif|jpeg)$/,
use:[{
loader:"url-loader",
options:{
limit:8192,
outputPath:'img',
name:'[name].[hash:8].[ext]'
}
}]
}
再次打包,打开控制台:
可以看到,命名正确了,文件输出方式也正确了(dist 下多出一个 img 文件夹),但是图片路径还是错的,所以不显示图片。我们接着来配置一下图片路径。
我们前面说过,webpack 认为 index.html
在 dist 文件夹中,所以才会直接通过图片名字引用图片。那么 index.html
实际上是在 dist 文件夹外面的,对于 index.html
来说,它就要通过 ./dist/img
才能顺利找到图片,也就是说,我们可以在原本路径(图片名)的基础上加一个固定前缀(./dist/img),使之正确指向图片位置(./dist/img/图片名)。
而 publicPath
正是可以用来做这件事的:
{
test: /\.(png|jpg|gif|jpeg)$/,
use:[{
loader:"url-loader",
options:{
limit:8192,
outputPath:'img',
publicPath:'./dist/img',
name:'[name].[hash:8].[ext]'
}
}]
}
publicPath
会给使用了相对路径引用的图片加上统一前缀。比如我们的图片路径一开始是 img/test2.95a05a82.jpg
,那么使用了 publicPath
后,图片路径就变成 ./dist/img/test2.95a05a82.jpg
。通常可以给 publicPath
配置一个 cdn 地址前缀,比如 https://xxx.cdn.com
,上线的时候图片就都统一使用 cdn 地址了。
那么配置好后再次打包,浏览器查看:
路径正常,而且图片也正常显示了。
另外,我们也可以选择给 output.publicPath
配置 ./dist/
,这样的话不止是图片,所有使用相对路径引用的静态资源都会加上这个前缀了。不过要注意,这个前缀需要加一个 /
,而图片的 publicPath
是不需要的。
2.2 js 引用
js 中引用图片需要使用 require,举个例子:
// module2.js
// require 拿到图片路径字符串
var img = require('../img/test2.jpg');
// 模板字符串构建 img 标签
export var demo = `<img src="${img}"/>`
// main.js
import demo from './js/module2.js';
document.body.innerHTML = demo;
只管根据图片和 module2.js
的路径关系正常引入图片即可,后面路径会被正确替换。
如果我们之前没有配置 publicPath
的话,会发现打包后的路径是 img/test2.95a05a82.jpg
,也即 index.html
依然被当作是位于 dist 文件夹下的。因为我们前面配置了,所以这里路径是正确的,最后可以正常显示图片:
4. Babel 转译
命令行安装:
npm install --save -dev babel-loader@7 babel-core babel-preset-es2015
配置 webpack.config.js
:
module:{
rules:[
{...},
{...},
{
test:/\.js$/,
exclude:/(node_modules|bower_components)/,
use:{
loader:'babel-loader',
options:{
presets:['es2015']
}
}
}
]
}
exclude:/(node_modules|bower_components)/
表示不转译 node_modules
文件夹中的 js 。
babel-loader 的预设:
babel-preset-es2015
,babel-preset-es2016
等:支持不同版本的ECMAScript规范;babel-preset-latest
: 支持现有所有 ECMAScript 版本的新特性,包括处于stage 4里的特性(已经确定的规范,将被添加到下个年度的)。babel-preset-env
:但很多时候我们需要更灵活的 preset —— 比如大部分浏览器已经支持了 ES6 的某个特性,那么对于这个特性我们其实是不必去转译的,但前面所说的那些 preset 会一概转译。所以这里还提供了babel-preset-env
,它可以根据我们指定的目标环境(比如某个版本的浏览器)来选择它不支持的特性进行转译。
5. 集成 Vue
注意这不是一个开发时依赖:
npm install vue@2.5.21 --save
如果遇到这个报错:
You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
这是因为 Vue 有两个版本:
- runtime-only
- runtime-compiler
其中,runtime-only 版本无法编译模板,要么用 render 函数,要么修改 webpack.config.js
配置改用其它版本。这里我们先选择后者:
module.exports = {
entry: ...,
output: {...},
module: {...},
resolve:{
alias:{
'vue$':'vue/dist/vue.esm.js' // 指定版本
}
}
}
另外,webpack 还需要分别借助 vue-loader 和 vue-template-compiler 去加载和解析 .vue 文件:
npm install vue-loader@13.0.0 vue-template-compiler@2.5.21 --save -dev
之后我们就可以编写单文件组件了( 使用 vscode 的话强烈建议安装 vetur 插件)。
Note:
因为我们安装的 vue 版本是 vue@2.5.21,所以这里的 vue-loader 和 vue-template-compiler 要注意版本对应问题,总之报错信息也写得很清楚了。
(要说为什么用这么低版本的 vue,因为视频里的项目也是用低版本 Vue 构建的,所以暂时先跟着讲师的步伐吧 =。=)