Webpack的核心概念-loader与plugin

    科技2022-07-12  137

    文章目录

    1. Webpack的loader1.1 问题引入1.2 loader是什么1.3 配置文件修改以引入loader1.4 loader打包静态资源-图片保持图片原名打包其他类型图片希望图片资源打包后存放在一个单独目录url-loader与file-loader区别最佳实践 1.5 loader打包静态资源-样式使用style-loader与css-loader样式中前缀的补足scss的处理less的处理 1.6 css-loader的进阶配置importLoadersCSS模块化 1.7 loader打包静态资源-字体1.8 loader的顺序 2.Webpack的plugin2.1 HtmlWebpackPlugin介绍配置plugin 2.2 CleanWebpackPlugin介绍

    1. Webpack的loader

    1.1 问题引入

    之前的项目中我们打包的对象都是JS文件,那假设我们需要import一个图片应该怎么做呢,如果仍然使用之前的方式进行打包就会报错:

    Module parse failed:Unpexpected character ...

    很明显webpack不能识别图片文件,这里就需要借助loader来告诉webpack如何打包图片文件了

    1.2 loader是什么

    Loader就是一种打包方案,对于某一种类型文件他知道如何打包,帮助webpack完成打包工作。

    如果你写过vue,肯定写过类似的语句

    import Header from './header.vue'

    1.3 配置文件修改以引入loader

    我们需要给之前的webpack配置文件中加入一个module字段,并新增一个rules数组来增加规则:

    const path = required('path') module.exports = { mode:'development', entry:{ main:'./src/index.js' }, module:{ rules:[{ test:/\.jpg$/, use:{ loader:'file-loader } }] }, output:{...} }

    上述其实就是制定了一个规则,告诉webpack遇到以.jpg结尾的文件时候使用file-loader去处理。

    这里别忘了先把file-loader安装到项目中:

    npm install file-loader -D

    这样重新npm run bundle就可以看到dist目录下面多出了一个图片文件。

    file-loader底层做了这些:当他发现你这边图片文件要打包,首先会把图片移动到dist目录下面去 并改一个名字(名字可以自己定义),然后会得到图片相对于dist目录的一个名称,然后返回给引入模块的变量之中。

    file-loader理论上可以处理任何静态资源,例如excel,jpg,png,他实际上就是移动位置然后把新地址返回给变量,只要你的test字段写好就可以。 借助这一点我们尝试把静态资源放到网页上:

    import avatar from './avatar.jpg' const img = new Image(); img.src = avatar; .... root.append(img)

    1.4 loader打包静态资源-图片

    这里我们继续扩展之前的内容,了解如何对loader进行一些自定义配置和使用。

    保持图片原名

    默认使用file-loader会更改图片文件名称,但是我们希望保持原名该怎么做呢?

    这里可以通过对该loader进行配置解决:

    ... module:{ rules:[{ test:/\.jpg$/, use:{ loader:'file-loader', options:{ name:'[name].[ext]' // 记得包单引号 } } }] } ...

    这里的[name],[ext]是loader提供的占位符,具体value可以参考对应loader的文档,上述name和ext分别表示处理文件的名称和后缀

    打包其他类型图片

    大家应该联想到解决方法了,直接修改test字段匹配到更多的图片类型即可:

    test:/\.(jpg|png|gif)$/

    希望图片资源打包后存放在一个单独目录

    这里可以再添加一个outputPath配置项:

    use:{ loader:'file-loader', options:{ name:... outputPath:'images/' } }

    url-loader与file-loader区别

    这里你可能会在其他webpack资料里面看到使用url-loader来对图片进行打包。

    这里目前来说url-loader是可以代替file-loader来打包图片文件。

    区别在于url-loader是将图片转换为base64存放在bundle.js文件中,而非放到dist目录下。

    file-loader的特点:

    可以指定要复制和放置资源文件的位置,以及如何使用版本哈希命名以获得更好的缓存。你可以就近管理图片文件,可以使用相对路径而不用担心部署时 URL 的问题。使用正确的配置,webpack 将会在打包输出中自动重写文件路径为正确的 URL。

    url-loader的特点:

    允许你有条件地将文件转换为内联的 base-64 URL (当文件小于给定的阈值),这会减少小文件的 HTTP 请求数。如果文件大于该阈值,会自动的交给 file-loader 处理。

    最佳实践

    目前的最佳时间就是使用url-loader将一些几KB的小图片打包到JS文件中,而大图片移动到dist目录下,保证bundle.js尽快加载完成。

    这里你需要配置的就是一个阈值,保证不同区间使用不同策略:

    use:{ loader:'url-loader', options:{ ... limit:2048 } }

    上述表示小于2KB的会打包到bundle,否则就利用file-loader移动到dist目录

    1.5 loader打包静态资源-样式

    项目中通常都会有css文件负责管理样式,直接webpack打包同样无法解析,需要利用loader来处理。

    使用style-loader与css-loader

    这里我们针对css文件新增一个rule并使用对应loader来解析

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

    然后npm安装一下之后浏览器就可以正常显示了。

    接着我们说明一下这两个loader的作用。

    css-loader会帮助我们分析多个css文件之间的关系,然后把多个css文件合并成一个css。

    style-loader会将上述合并后的css文件挂载在文件的header上面:

    <head> ... <style>.avatar{ width:150px; } </style> ... </head>

    所以在使用css-loader时候需要配合style-loader来使用才行

    样式中前缀的补足

    我们可以使用postcss-loader来补足样式中诸如webkit这种前缀,默认打包是没有的:

    transform: webkit-translate(100px,100px)

    这个loader还要求我们在目录下创建一个postcss.config.js文件,这里对其进行一些配置:

    //postcss.config.js module.exports = { plugins:[ require('autoprefixer') ] //使用了一些插件 }

    需要执行npm install autoprefixer -D来安装插件。然后重新进行一次打包

    scss的处理

    这里我们可以先写一个有scss特殊语法的文件:

    body{ .avatar{ ... } }

    这里直接修改test匹配规则也是没用的,最终会发现页面挂在的还是scss语法的style,没有进行解析:

    <style> body{ .avatar{ ... } } </style>

    这里还需要借助sass-loader来处理,这里还需要安装node-sass模块来进行解析(这部分官网文档有说明):

    npm install sass-loader node-sass -D

    less的处理

    less需要使用less-loader,具体使用方式和上述类似

    1.6 css-loader的进阶配置

    这里继续扩展讲一下css-loader

    importLoaders

    该配置参数用于css中的一些间接引用的情况:

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

    我们在一个index.scss文件里面引入一个新的scss文件:

    // index.scss @import './avatar.scss' ...

    这个时候其实是index.js引用了index.scss,间接引用了avatar.scss,这个时候你引入的scss就有可能不会使用下面的postcss-loader和sass-loader了,如果你希望间接引用的也适用这些loaders,就需要这个配置项,importLoaders:2意味着无论直接引用还是间接引用都会从下到上再使用2个loader!

    CSS模块化

    上述配置的CSS其实是全局共享的,这样很容易导致样式冲突,我们可以配置来保证CSS只在import引入的JS文件中起作用:

    { test:/\.scss$/, use:[ 'style-loader', { loader:'css-loader', options:{ importLoaders:2, modules:true } }, 'sass-loader', 'postcss-loader' ] }

    1.7 loader打包静态资源-字体

    这里有时候我们希望项目能展示一些第三方字体,就需要引入字体文件,基于上述打包图片和样式的思路,我们其实直接借助file-loader就行了:

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

    1.8 loader的顺序

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

    注意webpack里面use的loader是有先后顺序的,从下倒上,从右到左,例如上面的例子当中我们是先执行sass-loader,把scss转成css,然后css-loader打包为一个css,最后style-loader进行挂载

    2.Webpack的plugin

    loader主要是解析不同类型的文件,而plugin则是提供一些额外的功能。

    其实plugin可以在webpack运行到某个时刻的时候帮你自动做一些事情,有些类似React或vue生命周期函数的概念~

    官网推荐的webpack插件有几十个,还有很多第三方插件也有很多功能,没必要一个个学,当我们想实现一些功能可以先搜索,找找有没有方便的插件或者配置

    2.1 HtmlWebpackPlugin介绍

    这里我们希望解决一个实际问题,之前我们的dist目录下的HTML文件其实都是手动拷贝过去的,有没有工具能自动完成这个。

    这里就可以借助html-webpack-plugin,首先npm install一下:

    npm install html-webpack-plugin -D

    接着我们在配置文件中引入plugin:

    module.exports = { mode:'development', entry:{...}, module:{ rules:[...] }, plugins:[new HtmlWebpackPlugin()], output:{...} }

    接着我们重新打包,该插件会在打包结束之后自动生成一个html文件,并自动包含对应的JS文件。

    但是我们会发现界面上面啥也没有,这是因为我们之前的代码逻辑是找到id为root的DOM节点,然后插入一个div节点,但是打包生成的没有这个root。

    配置plugin

    这里我们可以通过编写一个template文件,来用作插件自动生成的HTML文件的模板:

    ... <body> <div id='root'></div> </body>

    然后我们配置:

    plugins:[new HtmlWebpackPlugin({ template:'src/index.html' })]

    接着重新打包就会生成包含root节点的的index.html

    2.2 CleanWebpackPlugin介绍

    有时候我们修改了一下output的文件名,但是打包之后我们发现有新的dist.js文件了,但是bundle.js文件还在,没有删除,我们希望能够把dist目录删除然后再执行打包工作,这时候就可以用这个插件。

    注意这个插件不是官方推荐插件,官网搜不到,这里直接安装:

    npm install --save-dev clean-webpack-plugin

    然后添加到plugins数组:

    plugins:[ new HtmlWebpackPlugin({...}), new CleanWebpackPlugin(['dist']) ]

    参数是要删除的目录名

    Processed: 0.015, SQL: 8