这是我学习webpack的过程,后面会持续更新,大家可以跟着来学习,下面正文开始。
什么是Webpack
WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。
ps:本文都是用淘宝镜像来安装插件,这样安装速度快很多,还没安装的小伙伴可以用下面的指令进行安装。
//安装淘宝镜像,命名为cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
安装webpack
新建一个空的练习文件夹,我这里叫webpack-demo,然后在cmd或git打开,用cnpm初始化然后安装webpack。
package.json文件已经就绪,然后安装webpack和webpack-cli。
cnpm init // 初始化,终端会问你一系列诸如项目名称,项目描述,作者等信息,不过不用担心,如果你不准备 在cnpm中发布你的模块,这些问题的答案都不重要,回车默认即可,随即自动生成package.json文件
cnpm i webpack webpack-cli -D // i指install,-D相当于--save-dev(webpack4.0以上需要安装webpack-cli)
在根目录新建一个文件叫webpack.config.js,作为webpack的配置文件。
配置文件里有几个参数,分别为entry、output、module、plugins、devServer,他们分别对应:
entry:配置入口文件(需要打包压缩的文件)的地址,可以是单一入口,也可以是多入口。
output:配置出口文件的地址。
module:配置模块,主要是解析js/css和图片转换压缩等功能。
plugins:配置插件,根据你的需要配置不同功能的插件。
devServer:配置开发本地服务功能
新建src文件夹,作为我们的开发目录,新建index.html作为模板文件
dist是打包目录,运行打包命令后自动生成(可在webpack配置打包路径)
我们在app.js写个函数fun1,让他一秒后给id为welcome的元素赋值文本内容。
(ps.用些es6语法,let声明变量或箭头函数,后面通过配置处理成es5)
开始配置webpack
entry里设置入口文件,这里想压缩app.js,key为模块名,这里命名为'app',值为app.js的路径。
output的path属性必须是绝对路径,这里用path.resolve(__dirname,’dist’)获取了打包目录的绝对路径;filename属性是输入打包之后的文件名,其中[name] 指的是根据入口文件设置的模块名,打包成相同的名称,有几个入口文件,就可以打包出几个文件。
开始打包
打包之前,我们先在package.json的script属性设置打包的指令,webpack4.x要求设置mode
设置完之后我们打包只要在终端运行 cnpm run build 就行了。
运行cnpm run build进行打包,打包成功,发现他在dist/js目录自动生成一个app.bundle.js,这个就是打包后的压缩文件。
打开app.bundle.js文件,打包之后能找到之前在app.js书写的代码,虽然有一点不一样,运行起来效果是一样的。
我们把app.bundle.js引入根目录的index.html,然后打开在浏览器运行看看。
运行效果:1秒后页面显示“欢迎使用webpack”。
这样就是一个简单的打包过程,但在一般的项目中,我们还需要打包其他的文件,如css文件和图片文件,下面就介绍下如何打包这类文件。
使用html-webpack-plugin
看到plugin就知道这是个插件,它会在打包的时候,根据我们配置的模板html去生成一个入口html文件,然后自动帮我们引用打包的资源文件,比如js、css。这样的话,即使我们需要打包很多js文件和css文件,也不必自己手动去添加了,方便了很多。
安装html-webpack-plugin
cnpm i html-webpack-plugin -D
先引用html-webpack-plugin,然后在plugins进行初始化
**filename:打包生成的html名称;
**template:模板html文件;
**inject:引入打包资源文件的位置
把根目录引用的app.bundle.js删掉,然后运行打包命令cnpm run build,然后在dist目录自动生成一个index.html文件,他也自动引入了打包的js文件,浏览器运行打包的index.html也正常,成功!
这里先提前说下loader的处理顺序
=============================================================
loader的工作方式是先处理后面的loader,然后一步步往前执行,比如 {loaders: 'style-loader!css-loader!postcss-loader!less-loader'},它就是先处理less-loader,接着处理postcss-loader,然后执行css-loader,最后处理style-loader。
=============================================================
使用babel-loader处理js
现在前端开发基本都在使用ES6的语法了,但是ES6,ES7这些标准目前并未被当前的浏览器完全支持,所以我们可以利用babel-preset-env,它可以根据配置的目标浏览器或者运行环境来自动将ES2015+的代码转换为es5。
安装babel-loader、@babel/core和@babel/preset-env,@babel/core是babel核心包,@babel/preset-env是ES语法分析包。
cnpm i babel-loader @babel/core @babel/preset-env -D
在根目录创建.babelrc文件,作为babel-loader的配置文件,当babel-loader运行的时候,会检查这个配置文件,并读取相关的语法和插件配置
**test:用正则匹配需要使用loader的文件
**use:设置需要用到的loader
**include:设置需要转换的文件目录,这里设置开发目录src,这样他就只会检测src目录下的js文件;
**exclude:设置不需要转换的文件目录,这里设置插件依赖包目录node_modules,这样打包会快点。
运行cnpm run build进行打包,然后打开打包生成的app.bundle.js文件,可以看到经过处理,已经把箭头函数转译成功。
使用css-loader和style-loader处理css
webpack无法自己打包css文件,他需要css-loader和style-loader:
css-loader帮助webpack打包处理css文件
经过css-loader的处理,style-loader主要是新建一个style标签,然后插入到html的head标签里。
在src/css目录下新建一个公共的css文件,命名为common.js,然后先随便写点样式。
我们把他引入app.js,在打包的时候顺便处理一下css文件。
安装css-loader和style-loader
cnpm i css-loader style-loader -D
安装好,开始配置css的打包规则
**test:用正则匹配以css结尾的文件
**use:设置需要使用的loader
运行cnpm run build进行打包,运行成功后浏览器打开dist/index.hmtl,看到body的背景色变了,样式生效。
打开开发者工具看到在head标签里新增了一个style标签,里面的样式就是刚才定义的commo.css的样式。
使用postcss-loader自动处理CSS3属性前缀
为了浏览器的兼容性,有时候我们必须加入-webkit,-ms,-o,-moz这些前缀。目的就是让我们写的页面在每个浏览器中都可以顺利运行,我们这里使用postcss-loader来帮我们自动补充前缀。
安装postcss-loader和autoprefixer(自动添加前缀的插件)。
cnpm i postcss-loader autoprefixer -D
安装好这两个模块后,在项目根目录下新建 postcss.config.js 和 .browserslistrc 文件,分别作为postcss-loader和browserslist的配置文件。
Replace Autoprefixer browsers option to Browserslist config. Use browserslist key in package.json or .browserslistrc file. Using browsers option can cause errors. Browserslist config can be used for Babel, Autoprefixer, postcss-normalize and other tools.
browserslist key属性建议在packge.json或者新建一个.browserslistrc文件进行配置 (ps.browserslist配置说明)
这里选择后者新建.browserslistrc文件的方式
对postcss.config.js配置完成后,我们还需要编写我们的loader配置,在use里添加postcss-loader。
注意:如果我们要打包的css文件里面引用了其他css文件,他会帮我打包,但是不会帮我们处理前缀,那么该如何处理@import引入的css文件,如何让他自动加上前缀呢?
这时候我们需要借助css-loader的 importLoaders 参数
importLoaders 默认值:0 描述:在 css-loader 前应用的 loader 的数
配置css-loader
这里的importLoaders: 1 是在css-loader 之后指定1个数量的loader(即 postcss-loader)来处理import进来的资源。
在src/css目录新建一个tem.css,并设置样式。
在common.css文件头引入刚创建的tem.css
在根目录index.html引用样式f-rotate45
OK,common.css里面引入了其他css文件,我们的css-loader也配置好了,开始打包,运行cnpm run build,浏览器打开dist/index.html预览。
打开开发者工具可以看到head标签里又多了一个style标签,展开一看就是刚才创建的tem.css,并且他帮我们补上前缀了,完成!
使用extract-text-webpack-plugin分离css
有些简单的交互页面中,你的JavasScript页面代码会非常少,而大部分代码都在CSS中,这个插件就可以完美地帮我们提取CSS。
安装 extract-text-webpack-plugin
cnpm i extract-text-webpack-plugin -D
开始配置
首先require引用插件,然后修改css配置,最后在plugins里面初始化实例。
extract-text-webpack-plugin的参数说明:
**use:用于将资源转换为CSS导出模块的加载程序(必需);
**fallback:未提取CSS时应使用的加载程序(例如“style-loader”),即编译后用什么loader来提取css文件。
配置完成,运行cnpm run build打包,终端出现报错信息。
原因:webpack4不再支持extract-text-webpack-plugin这个插件,需要使用最新版或者替代插件。
解决办法:卸载之前版本插件,并安装最新测试版。
cnpm i extract-text-webpack-plugin@next -D
再次运行cnpm run build打包,看到dist目录生成一个css文件夹,里面有个index.css文件,我们写过的样式都在index.css里,看来分离成功了。
打包生成的index.html也自动引入了index.css,浏览器运行也正常。
使用purifycss-webpack、purify-css去除冗余的 css
有时候我们声明了很多样式,但部分样式并没有用到,这样就会造成冗余,刚好有插件能帮忙解决。
注意:如果想使用purify-css 的话,必须结合extract-text-webpack-plugin 这个插件,否则没效果!!!
安装 purifycss-webpack、purify-css。
cnpm i purifycss-webpack purify-css -D
开始配置
在webpack.config.js文件头部引入glob和purifycss-webpack,因为我们需要同步检查html模板,所以我们需要引入node的glob对象来使用。
然后在plugins初始化实例,这里配置了一个paths,主要是寻找html模板,purifycss根据这个配置会遍历你的文件,查找哪些css被使用了。
开始使用
在tem.css里写一个没用的样式
运行cnpm run build打包命令,查看生成的index.css文件,发现他只展示了我们用到的样式,刚才声明的.nonesense没打包进去,而且以前在common.css声明的.f-flex-box也没对其进行打包。
使用less-loader处理less
新建一个组件文件夹components和一个layer组件,并创建layer的html、less和js文件。
在layer.less文件写点样式,然后layer.js引入layer.less文件,并且在app.js引入组件layer。
注意:千万不能在css文件引入less和scss文件,css 引入less和scss 语法是不起作用的,必须同文件引用才能正确解析!!也就是说css文件只能引入css文件,less文件只能引入less文件。
不能把我们新建的layer.less在common.css或者tem.css里面引入,我这里是在组件layer的js文件里面引入less,然后app.js再引入layer组件,然后打包的时候对app里面引入的common.css、layer.js还有自身的js进行打包。
配置less
在module添加less的规则
在根目录的模板index.html添加个div,写上刚才在layer.less定义的 #m-new-wrap,因为没用到的样式会被purifycss-webpack给过滤掉。
打包运行cnpm run build,运行成功后浏览器打开dist/index.hmtl,发现页面有点变化了,是新增加的样式生效了。打开开发者工具查看,刚才的样式被style标签包住然后加在head标签里。
我们发现他并没有分离css,这里我们用 extract-text-webpack-plugin 修改下配置,让less解析完写入index.css。
打包运行cnpm run build,打包完成后,查看index.css文件,可以看到分离成功。
思考:我们前面讲到一个css文件@import了其他css文件,我们想其他css文件也自动补全前缀的话,我们必须配置css-loader的importLoaders属性,那么问题来了,如果一个less文件@import了其他less文件的话,那这里也需要配置importLoaders属性吗?
·
·
·
·
答案是:不需要配置importLoaders,因为less文件他先处理了@import进来的less文件,然后再交给postcss-laoder去添加前缀。小伙伴们可以自己试试看。
使用sass-loader处理sass
安装node-sass和sass-loader
cnpm i node-sass sass-loader -D
配置sass
sass的配置和less差不多
新建一个layer.scss文件,修改layer.js引入layer.scss。
打包运行cnpm run build,打包成功,查看生成的index.css文件。
思考:我们前面讲到一个css文件@import了其他css文件,我们想其他css文件也自动补全前缀的话,我们必须配置css-loader的importLoaders属性,但一个less文件@import了其他less文件,就不需要配置importLoaders属性,那么问题来了,如果一个scss文件@import了其他scss文件的话,那这里需要配置importLoaders属性吗?
·
·
·
我们来试一下,我们先把purifycss给注释掉,别让他把没用的代码过滤了。然后新建一个new_layer.scss文件,并写下需要自动补全的样式,并且在layer.scss引入new_layer.scss。
打包运行cnpm run build,打包成功,查看生成的index.css文件,可以看到new_layer经过处理了,并且自动加上了前缀。
说明sass-loader和less-loader一样,先处理引入的文件,然后再交给postcss-loader去处理。
(ps:sass-loader很奇怪,我在网上看别人都是得配置importLoaders的,但是我自己测试却不用加,后期再研究研究。)
使用file-loader、url-loader处理图片
我们先创建一个images的文件夹,里面存放几张图片待会用,然后找个css文件设置个背景为图片资源,这里我在layer.scss里改写之前的样式。
然后运行打包命令cnpm run build,发现报错了,他解析不了图片,提示我们需要适当的处理器去处理这种图片类型。
这里我们用 file-loader 和 url-loader 来解析图片:
**file-loader:解决引用路径的问题,拿background样式用url引入背景图来说,我们都知道,webpack最终会将各个模块打包成一个文件,因此我们样式中的url路径是相对入口html页面的,而不是相对于原始css文件所在的路径的。这就会导致图片引入失败。这个问题是用file-loader解决的,file-loader可以解析项目中的url引入(不仅限于css),根据我们的配置,将图片拷贝到相应的路径,再根据我们的配置,修改打包后文件引用路径,使之指向正确的文件。
**url-loader:如果图片较多,会发很多http请求,会降低页面性能。这个问题可以通过url-loader解决。url-loader会将引入的图片编码,生成dataURl。相当于把图片数据翻译成一串字符。再把这串字符打包到文件中,最终只需要引入这个文件就能访问图片了。当然,如果图片较大,编码会消耗性能。因此url-loader提供了一个limit参数,小于limit字节的文件会被转为DataURl,大于limit的还会使用file-loader进行copy。
安装 file-loader 和 url-loader
cnpm i file-loader url-loader -D
配置url-loader
**use:指定使用的loader和loader的配置参数;
**limit:把小于500000B的文件打成Base64的格式。
运行打包命令,编译成功,在index.css可以看到有个background的图片链接是base64,打开浏览器运行也能看到背景图样式生效了。
这里说明一下为什么只使用了url-loader
有的小伙伴会发现我们并没有在webpack.config.js中使用file-loader,但是依然打包成功了。我们需要了解file-loader和url-loader的关系。url-loader和file-loader是什么关系呢?简答地说,url-loader封装了file-loader。url-loader不依赖于file-loader,即使用url-loader时,只需要安装url-loader即可,不需要安装file-loader,因为url-loader内置了file-loader。通过上面的介绍,我们可以看到,url-loader工作分两种情况:
1.文件大小小于limit参数,url-loader将会把文件转为DataURL(Base64格式);
2.文件大小大于limit,url-loader会调用file-loader进行处理,参数也会直接传给file-loader。
也就是说,其实我们只安装一个url-loader就可以了。但是为了以后的操作方便,我们这里就顺便安装上file-loader。
我们上面limit限制了500000B大小的图片,也就是说超过488kb就交给file-loader去处理,我们这里试一下把背景图换成大于488kb的图片,然后打包,再看看index.css文件,看看发生什么变化,我们发现路径不对,而且在浏览器运行也没效果。
为什么会这样呢?其实不分离css就能显示图片,因为我们之前把所有的css给分离了,背景图片设置了相对路径,所以分离之后的图片路径就不对了,也就不会正常显示了。