接着上一块https://juejin.im/post/5be29710e51d457e90193cf3
模块:CSS文件打包
Webpack在生产环境中有一个重要的作用就是减少http的请求数,就是把多个文件打包到一个js里,这样请求数就可以减少好多。在学习CSS打包之前,需要先对webpack.config.js里的Loaders配置项进行了解。
Loaders(以下所有的配置都是基于3版本的 如果过程中有bug 会进行改进)
Loaders是Webpack最重要的功能之一,他也是Webpack如此盛行的原因。通过使用不同的Loader,Webpack可以的脚本和工具,从而对不同的文件格式进行特定处理。
简单的举几个Loaders使用例子:
可以把SASS文件的写法转换成CSS,而不在使用其他转换工具。 可以把ES6或者ES7的代码,转换成大多浏览器兼容的JS代码。 可以把React中的JSX转换成JavaScript代码。
注意:所有的Loaders都需要在npm中单独进行安装,并在webpack.config.js里进行配置。下面我们对Loaders的配置型简单梳理一下。
test:用于匹配处理文件的扩展名的表达式,这个选项是必须进行配置的; use:loader名称,就是你要使用模块的名称,这个选项也必须进行配置,否则报错; include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选); query:为loaders提供额外的设置选项(可选)。
打包CSS文件
建立index.css文件 ./src/css/index.css
要打包CSS你必须先要有个CSS文件,在/src目录下,我们建立一个css文件夹,在文件夹里建立index.css文件。代码内容如下
body{ background-color: red; 可以跟我不一样 完全为了测试 color: white; }复制代码
CSS文件建立好后,需要引入到入口文件中,才可以打包到,这里我们引入到entry.js中。
/src/entery.js中在首行加入代码: import css from './css/index.css';
也就是在entry.js中顶部导入
import css from './css/index.css'; document.getElementById('title').innerHTML='Hello Webpack';复制代码
CSS和引入做好后,我们就需要使用loader来解析CSS文件了,这里我们需要两个解析用的loader,分别是style-loader和css-loader
首先我们先使用npm 安装(有些脚手架生成的webpack 会自动安装这些简单的加载器)
npm install style-loader css-loader --save-dev
一步到位
安装好之后查看一下package.json
两个loader都下载安装好后,我们就可以配置我们loaders了。
loaders配置:
修改webpack.config.js中module属性中的配置代码如下:
webpack.config.js
const path = require('path') module.exports={ mode: 'development', //入口文件的配置项 entry:{ //里面的entery是可以随便写的 entry:'./src/entry.js', }, //出口文件的配置项 output:{ //打包的路径文职 path:path.resolve(__dirname,'dist'), //打包的文件名称 filename:'bundle.js' }, //模块:例如解读CSS,图片如何转换,压缩 module:{ rules: [ =>以前此处是loaders 现在是rules { test: /\.css$/, =>正则 这个好理解 use: [ 'style-loader', 'css-loader' ] =>使用css 与 style loader 来加载匹配到的css文件 } ] }, //插件,用于生产模版和各项功能 plugins:[], //配置webpack开发服务功能 devServer:{ host:'localhost', //服务器的ip地址 port:1573, //端口 } }复制代码
webpack一下,之前我们在js中引入了css 运行一下html ok 有样式了
友情提示:小伙伴们在测试的时候,可能会遇到找不到模块的 这种error 建议重新新建配置 重新npm插件 刚才我就莫名其妙找不到模块了 重新安装了一下就可以了
loader的三种写法:
有些小伙伴看到别人的CSS打包的写法和我的写法不太一样,是不是我写错了,loader还有几种写法,这里我们就看两种另外的写法。
使用use
module:{ rules:[ { test:/\.css$/, use:['style-loader','css-loader'] } ] },复制代码
把use换成loader。
module:{ rules:[ { test:/\.css$/, loader:['style-loader','css-loader'] } ] },复制代码
第三种写法:用use+loader的写法:
module:{ rules:[ { test:/\.css$/, use: [ { loader: "style-loader" }, { loader: "css-loader" } ] } ] },复制代码
没有全测 也不知道哪里需要修改 小伙伴可以自行测试一下
接下来我们来试着压缩一下js
在Webpack中可以很轻松的实现JS代码的压缩,它是通过插件的方式实现的,这里我们就先来引入一个uglifyjs-webpack-plugin(JS压缩插件,简称uglify)。
注意:虽然uglifyjs是插件,但是webpack版本里默认已经集成,不需要再次安装。
const path = require('path') const webpack =require('webpack') =>注意这里我们引入了webpack module.exports={ mode: 'development', //入口文件的配置项 entry:{ //里面的entery是可以随便写的 entry:'./src/entry.js', }, //出口文件的配置项 output:{ //打包的路径文职 path:path.resolve(__dirname,'dist'), //打包的文件名称 filename:'bundle.js' }, //模块:例如解读CSS,图片如何转换,压缩 module:{ rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] } ] }, //插件,用于生产模版和各项功能 plugins:[ new webpack.optimize.UglifyJsPlugin() =>因为是webpack集成的 所以要在上方引入webpack ] }复制代码
此时我们webpack一下 你会发现 报错(报错的内容就不截屏了)
在webpack4.0版本中已经废弃了之前 UglifyJsPlugin的用法,用的是optimization.minimize
重新配置一下webpack
const path = require('path') 删除了webpack模块引入 const UglifyJsPlugin=require('uglifyjs-webpack-plugin');=>需要 npm 手动安装 module.exports={ mode: 'development', //入口文件的配置项 entry:{ //里面的entery是可以随便写的 entry:'./src/entry.js', }, //出口文件的配置项 output:{ //打包的路径文职 path:path.resolve(__dirname,'dist'), //打包的文件名称 filename:'bundle.js' }, //模块:例如解读CSS,图片如何转换,压缩 module:{ rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] } ] }, //插件,用于生产模版和各项功能 plugins:[ ], optimization: { minimizer: [ new UglifyJsPlugin({ uglifyOptions: { compress: false } }) ] }, }复制代码
这里需要注意一下 webpack打包也是分模式的 默认是mode ‘production(生产环境)’
如果我们没在config.js中标明webpack 的mode 直接webpack是会有警告的
就是说我们打包的命令完整应该是 webpack --mode production/development
默认是production 此方法打包文件会小很多 注意一下即可
production 其实默认自带了uglifyjs-webpack-plugin 插件 已经不需要使用
也就是我们在production 状态下 其实可以不需要配置 直接 webpack --mode development 即可
接下来我还是设置默认 production 环境下测试 方便点
插件配置:HTML文件的发布
webpack 构建项目时, 通过指定的入口文件,会将所有的js css 等以依赖模块的形式打包成一个或多个的脚本文件,通常情况下,脚本文件会附属于html 文件运行,这时候需要将 打包好的脚本文件,注入到html 中, html-webpack-plugin 插件的目的是, 以一个html 为模板, 将打包好的脚本注入到模板中, 相关的配置如下
先安装 html-webpack-plugin npm i html-webpack-plugin -D
安装好之后 我们在plugins中配置
const path = require('path') const htmlPlugin = require('html-webpack-plugin'); =>引入模块 module.exports={ //入口文件的配置项 entry:{ //里面的entery是可以随便写的 entry:'./src/entry.js', }, //出口文件的配置项 output:{ //打包的路径文职 path:path.resolve(__dirname,'dist'), //打包的文件名称 filename:'bundle.js' }, //模块:例如解读CSS,图片如何转换,压缩 module:{ rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] } ] }, //插件,用于生产模版和各项功能 plugins:[ new htmlPlugin({ =>这是一般情况下的配置 打包html minify:{ removeAttributeQuotes:true }, hash:true, template:'./src/index.html' }) ], }复制代码
minify:是对html文件进行压缩 hash:为了开发中js有缓存效果,所以加入hash,这样可以有效避免缓存JS。 template:是要打包的html模版路径和文件名称。
此时我们webpack --mode production
此时dist下生成了 index.html js是上面的命令生成的 这就是我们常见的状态了 熟悉vue的小伙伴都知道 npm run build就会生成这俩文件 此时我们直接开index.html 也是有效果的 如果需要改名的话可以再配置一个参数 filename:'filename.html' 一定要加后缀
图片迈坑:CSS中的图片处理
在学习Webapck过程中你可能遇到的第一个坑就是CSS中的图片处理。很多webpack新手都在图片的坑中无法自拔(有的小伙伴在开发环境中是可以找到图片的,但是一打包后就找不到图片了,有的小伙伴是不知道如何正确引入html或者css中的图片,导致程序出错)
图片写入css 我们先找张图片先
注意一定要本地图片啊 刚才偷懒使用网络图片发现居然成功了 不能成功 一定要失败的
index.html
webpack 复制代码
index.css css还是在js中引入
#tupian{background-image: url('./../image/1.jpg');width:466px;height:453px; }复制代码
我们这时候 通过webpack --mode production 是会失败的 失败的原因就是缺少loader的解析
对于图片我们也需要安装两loader
安装file-loader和url-loade npm install --save-dev 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。
安装好之后我们来配置webpack 直接在module中配置loader
const path = require('path') const htmlPlugin = require('html-webpack-plugin'); module.exports={ //入口文件的配置项 entry:{ //里面的entery是可以随便写的 entry:'./src/entry.js', }, //出口文件的配置项 output:{ //打包的路径文职 path:path.resolve(__dirname,'dist'), //打包的文件名称 filename:'bundle.js' }, //模块:例如解读CSS,图片如何转换,压缩 module:{ rules: [ { test: /\.css$/, => css的loader use: [ 'style-loader', 'css-loader' ] =>这边顺带提一下 其实webpack的loader是从右往左看 =>也就是 先使用css loader 再使用style loader }, { test:/\.(png|jpg|gif)/ , =>图片的loader use:[{ loader:'url-loader', options:{ limit:500000 =>不认识limit的小伙伴可以自行百度一下 类似我们的流量 哈哈 好吧其实就是指500000B } }] } ] }, //插件,用于生产模版和各项功能 plugins:[ new htmlPlugin({ minify:{ removeAttributeQuotes:true }, hash:true, template:'./src/index.html' }) ], }复制代码
接下来我们webpack --mode production 即可 成功生成
为什么只使用了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。
###图片迈坑:CSS分离与图片路径处理
CSS分离:extract-text-webpack-plugin
有些简单的交互页面中,你的JavasScript页面代码会非常少,而大部分代码都在CSS中,这时候项目组长会要求把CSS单独提取出来,方便以后更改。遇到这个需求你不要惊慌,已经有大神为我们准备好了对象的插件(plugin)
这个插件就可以完美的解决我们提取CSS的需求,但是webpack官方其实并不建议这样作,他们认为CSS就应该打包到JavasScript当中以减少http的请求数。但现实中的需求往往不是我们前端能控制的,有些需求是我们不能控制的,分离CSS就是这样一个既合理由不合理的需求,说白了,还是得听老大的 ,如果小姐姐让你这样你做不做呢?
npm install --save-dev extract-text-webpack-plugin
安装好了自然要用 我们直接在webpack上方 引入 const extractTextPlugin = require("extract-text-webpack-plugin")
引入之后 我们只需在webpack中new 使用 并且还要配置关于css的加载器
const path = require('path') const htmlPlugin = require('html-webpack-plugin'); const extractTextPlugin = require("extract-text-webpack-plugin") module.exports={ //入口文件的配置项 entry:{ //里面的entery是可以随便写的 entry:'./src/entry.js', }, //出口文件的配置项 output:{ //打包的路径位置 path:path.resolve(__dirname,'dist'), //打包的文件名称 filename:'bundle.js' }, //模块:例如解读CSS,图片如何转换,压缩 module:{ rules: [ { // test: /\.css$/, // use: [ 'style-loader', 'css-loader' ] test: /\.css$/, use: extractTextPlugin.extract({ fallback: "style-loader", use: "css-loader" }) }, { test:/\.(png|jpg|gif)/ , use:[{ loader:'url-loader', options:{ limit:500000 } }] } ] }, //插件,用于生产模版和各项功能 plugins:[ new htmlPlugin({ minify:{ removeAttributeQuotes:true }, hash:true, template:'./src/index.html' }), new extractTextPlugin("/css/index.css") =>注意插件的使用 (此处是生成的文件位置 前面配置了path 默认都是dist文件下的) ], }复制代码
此时我们webpack一下 是有错误的 因为extract-text-webpack-plugin 不支持4版本以上的 我们既然学习4版本的webpack肯定不能降级 好 我们升级 npm install --save-dev extract-text-webpack-plugin@4.0.0-beta.0
安装好之后 其余不变 再次 webpack一下 因为此时生成打包了三个文件 我给截图一下
这样就成功分离了 本来是起初我们导入js中的 此时成功生成了index.css 并且里面的url是base64形式的,但是我们此时浏览dist下的html是没有东西的 因为我们路径有问题 这里是指图片路径 不是文件路径
图片路径问题
利用extract-text-webpack-plugin插件很轻松的就把CSS文件分离了出来,但是CSS路径并不正确,很多小伙伴就在这里搞个几天还是没有头绪,网上也给出了很多的解决方案,我觉的最好的解决方案是使用publicPath解决
publicPath:是在webpack.config.js文件的output选项中,主要作用就是处理静态文件路径的。
此处增加一个知识 webpack-dev-server 本来是不想配置后面给大家简单提一下,毕竟单独测试webpack的真的不多,很多时候都是看webpack或者脚手架生成直接修改
测试publicPath的时候 没设置服务器状态老报错 使用live-server也不好配置 所以简单提一下webpack-dev-server的配置
npm install webpack-dev-server –save-dev
先安装
在webpack.config.js 中配置
plugins:[ new htmlPlugin({ minify:{ removeAttributeQuotes:true }, hash:true, template:'./src/index.html' }), new extractTextPlugin("/css/index.css") ], devServer:{ =>注意 与plugins同级 //设置基本目录结构 contentBase:path.join(__dirname,'dist'), //服务器的IP地址,可以使用IP也可以使用localhost // 不知道自己IP的可以 打开cmd 输入ipconfig 查看 host:'localhost', //服务端压缩是否开启 compress:true, //配置服务端口号 port:1717 }复制代码
在packge.json的 scripts 中输入"dev": "webpack-dev-server --open"
我们启动webpack-dev-server的时候只需要npm run dev 即可
启动webpack-dev-server之后 会启动热更新 当我们改变内容保存的时候会自动进行webpack命令打包 实时更新内容
别忘了我们主要的目的 ,解决图片路径问题 使用publicPath
主要看output模块
const path = require('path') const htmlPlugin = require('html-webpack-plugin'); const extractTextPlugin = require("extract-text-webpack-plugin") module.exports={ // mode:'development', //入口文件的配置项 entry:{ //里面的entery是可以随便写的 entry:'./src/entry.js', }, //出口文件的配置项 output:{ //打包的路径文职 path:path.resolve(__dirname,'dist'), //打包的文件名称 filename:'bundle.js', publicPath:'localhost:1717' }, //模块:例如解读CSS,图片如何转换,压缩 module:{ rules: [ { // test: /\.css$/, // use: [ 'style-loader', 'css-loader' ] test: /\.css$/, use: extractTextPlugin.extract({ fallback: "style-loader", use: "css-loader" }) }, { test:/\.(png|jpg|gif)/ , use:[{ loader:'url-loader', options:{ limit:500000 } }] } ] }, //插件,用于生产模版和各项功能 plugins:[ new htmlPlugin({ minify:{ removeAttributeQuotes:true }, hash:true, template:'./src/index.html' }), new extractTextPlugin("/css/index.css") ], devServer:{ //设置基本目录结构 contentBase:path.resolve(__dirname,'dist'), //服务器的IP地址,可以使用IP也可以使用localhost host:'localhost', //服务端压缩是否开启 compress:true, //配置服务端口号 port:1717 } }复制代码