Webpack的作用
- 打包:可以把多个Javascript文件打包成一个文件,减少服务器压力和下载带宽。
- 转换:把拓展语言转换成为普通的JavaScript,让浏览器顺利运行。
- 优化:前端变的越来越复杂后,性能也会遇到问题,而WebPack也开始肩负起了优化和提升性能的责任。
图例:
安装
前提是你已经安装node
//全局安装webpack
npm install -g webpack
//初始化
npm init
//项目目录安装webpack
npm install webpack --save-dev
全局安装并不推荐,因为在使用不同的webpack项目中,可能会导致构建失败
什么是开发环境和生产环境?
- 开发环境:开发时需要的环境,这里指在开发时需要依赖的包
- 生产环境:程序开发完成,开始运行后的环境,这里指要使项目运行,所需要的依赖包
一个DEMO
webpack {entry file} {destination for bundled file}
webpack src/entry.js dist/bundle.js
配置文件 : 入口和出口
module.exports={
//入口文件的配置项
entry:{},
//出口文件的配置项
output:{},
//模块:例如解读CSS,图片如何转换,压缩
module:{},
//插件,用于生产模版和各项功能
plugins:[],
//配置webpack开发服务功能
devServer:{}
}
- entry:配置入口文件的地址,可以是单一入口,也可以是多入口。
- output:配置出口文件的地址,在webpack2.X版本后,支持多出口配置。
- module:配置模块,主要是解析CSS和图片转换压缩等功能。
- plugins:配置插件,根据你的需要配置不同功能的插件。
- devServer:配置开发服务功能
//入口文件的配置项
entry:{
//里面的entry是可以随便写的
entry:'./src/entry.js'
},
//出口文件的配置项
output:{
//打包的路径
path:path.resolve(__dirname,'dist'), //获取绝对路径
//打包的文件名称
filename:'bundle.js'
}
需要引入path
const path = require('path');
现在的webpack.config.js代码
const path = require('path');
module.exports={
//入口文件的配置项
entry:{
entry:'./src/entry.js'
},
//出口文件的配置项
output:{
//输出的路径,用了Node语法
path:path.resolve(__dirname,'dist'),
//输出的文件名称
filename:'bundle.js'
},
//模块:例如解读CSS,图片如何转换,压缩
module:{},
//插件,用于生产模版和各项功能
plugins:[],
//配置webpack开发服务功能
devServer:{}
}
多入口,多出口
const path = require('path');
module.exports={
//入口文件的配置项
entry:{
entry:'./src/entry.js',
//这里我们又引入了一个入口文件
entry2:'./src/entry2.js'
},
//出口文件的配置项
output:{
//输出的路径,用了Node语法
path:path.resolve(__dirname,'dist'),
//输出的文件名称
filename:'[name].js'
},
//模块:例如解读CSS,图片如何转换,压缩
module:{},
//插件,用于生产模版和各项功能
plugins:[],
//配置webpack开发服务功能
devServer:{}
}
[name]的意思是根据入口文件的名称,打包成相同的名称,有几个入口文件,就可以打包出几个文件。
配置文件 : 服务和热更新
设置webpack-dev-server
先安装webpack-dev-server
devServer:{
//设置基本目录结构
contentBase:path.resolve(__dirname,'dist'),
//服务器的IP地址,可以使用IP也可以使用localhost
host:'localhost',
//服务端压缩是否开启
compress:true,
//配置服务端口号
port:9898
}
- contentBase:配置服务器基本运行路径,用于找到程序打包地址。
- host:服务运行地址,建议使用本机IP
- compress:服务器端压缩选型,一般设置为开启
- port:服务运行端口
支持热更新
在npm run server 启动后,它是有一种监控机制的(也叫watch)。它可以监控到我们修改源码,并立即在浏览器里给我们更新。
//package.json
"scripts": {
"server":"webpack-dev-server"
},
打包CSS文件
Loaders
- 可以把SASS文件的写法转换成CSS,而不在使用其他转换工具。
- 可以把ES6或者ES7的代码,转换成大多浏览器兼容的JS代码。
- 可以把React中的JSX转换成JavaScript代码。
所有的Loaders都需要在npm中单独进行安装,并在webpack.config.js里进行配置。
- test:用于匹配处理文件的扩展名的表达式,这个选项是必须进行配置的;
- use:loader名称,就是你要使用模块的名称,这个选项也必须进行配置,否则报错;
- include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选);
- query:为loaders提供额外的设置选项(可选)。
CSS文件建立好后,需要引入到入口文件中,才可以打包到
/src/entry.js
import css from './css/index.css';
安装loader
npm install style-loader css-loader --save-dev
loaders配置
//webpack.config.js
module:{
rules:[
{
test:/\.css$/,
use:['style-loader','css-loader']
}
]
},
loader的三种写法
//use
module:{
rules:[
{
test:/\.css$/,
use:['style-loader','css-loader']
}
]
},
//loader
module:{
rules:[
{
test:/\.css$/,
loader:['style-loader','css-loader']
}
]
},
//use+loader
module:{
rules:[
{
test:/\.css$/,
use: [
{
loader: "style-loader"
}, {
loader: "css-loader"
}
]
}
]
},
压缩JS代码
虽然uglifyjs是插件,但是webpack版本里默认已经集成,不需要再次安装。
//webpack.config.js
//引入
const uglify = require('uglifyjs-webpack-plugin');
//配置插件
plugins:[
new uglify()
],
现在的webpack.config.js
const path=require('path');
const uglify = require('uglifyjs-webpack-plugin');
module.exports={
entry:{
entry:'./src/entry.js',
entry2:'./src/entry2.js'
},
output:{
path:path.resolve(__dirname,'dist'),
filename:'[name].js'
},
module:{
rules:[
{
test:/\.css$/,
use: ["style-loader", "css-loader"]
}
]
},
plugins:[
new uglify()
],
devServer:{
contentBase:path.resolve(__dirname,'dist'),
host:'192.168.0.104',
compress:true,
port:1717
}
}
HTML文件的发布
在之前,html文件应该是在src目录下的.
- 先把html文件放入到src目录下
- 配置webpack.config.js文件,先引入html-webpack-plugin插件。
const htmlPlugin= require('html-webpack-plugin');
- npm安装
npm install --save-dev html-webpack-plugin
- webpack.config.js配置
plugins:[
new htmlPlugin({
minify:{
removeAttributeQuotes:true
},
hash:true,
template:'./src/index.html'
})
],
- minify:是对html文件进行压缩,removeAttrubuteQuotes是却掉属性的双引号。
- hash:为了开发中js有缓存效果,所以加入hash,这样可以有效避免缓存JS。
- template:是要打包的html模版路径和文件名称。
html文件的打包可以有效的区分开发目录和生产目录
图片处理
CSS中的图片处理
- css中写入一些图片的样式
#tupian{
background-image: url(../images/manhua.png);
width:466px;
height:453px;
}
- 安装file-loader和url-loader
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。
- 配置url-loader
//webpack.config.js文件
module:{
rules:[
{
test:/\.css$/,
use:['style-loader','css-loader']
},
{
test:/\.(png|jpg|gif)$/,
use:[{
loader:'url-loader',
options:{
limit:5000,
outputPath:'images/'
}
}]
}
]
},
- test:/.(png|jpg|gif)/是匹配图片文件后缀名称。
- use:是指定使用的loader和loader的配置参数。
- limit:是把小于5000B的文件打成Base64的格式,写入JS。
- outputPath : 将图片放入指定的路径下
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。
CSS分离与图片路径处理
CSS分离:extract-text-webpack-plugin
- 安装
npm install --save-dev extract-text-webpack-plugin
- 引入
const extractTextPlugin = require("extract-text-webpack-plugin");
- 设置plugins,只需要new一下这个对象就可以了
new extractTextPlugin("css/index.css")
- 修改原来的style-loader和css-loader。
module:{
rules:[
{
test:/\.css$/,
use: extractTextPlugin.extract({
fallback:"style-loader",
use:"css-loader"
})
},
{
test:/\.(png|jpg|gif)$/,
use:[{
loader:'url-loader',
options:{
limit:5000,
outputPath:'images/'
}
}]
}
]
},
图片路径问题
利用extract-text-webpack-plugin插件很轻松的就把CSS文件分离了出来,但是CSS路径并不正确,使用publicPath解决
publicPath:是在webpack.config.js文件的output选项中,主要作用就是处理静态文件路径的。
//webpack.config.js
//声明一个对象
var website ={
publicPath:"http://192.168.1.108:1717/"
}
//引用这个对象的属性
output : {
path:path.resolve(__dirname,'dist'),
filename: '[name].js',
publicPath:website.publicPath
},
处理HTML中的图片
html-withimg-loader
- 安装
npm install html-withimg-loader --save-dev
- 配置loader
//webpack.config.js
{
test: /\.(htm|html)$/i,
use:[ 'html-withimg-loader']
}
CSS进阶
打包Less
- 安装
//安装less服务
npm install less --save-dev
//安装less-loader
npm install less-loader --save-dev
- 写loader配置
//webpack.config.js
{
test: /\.less$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
, {
loader: "less-loader" // compiles Less to CSS
}]
}
- 引入到入口文件中
import less from './less/black.less';
把less分离
{
test:/\.less$/,
use:extractTextPlugin.extract({
use:[{
loader:"css-loader"
},{
loader:"less-loader"
}],
fallback:"style-loader"
})
}
SASS的打包和分离
和Less非常相似
npm install node-sass sass-loader --save-dev
//webpack.config.js
{
test:/\.scss$/,
use:extractTextPlugin.extract({
use:[{
loader:"css-loader"
},{
loader:"sass-loader"
}],
fallback:"style-loader"
})
}
postcss自动添加CSS属性前缀
postcss
- 安装
npm install postcss-loader autoprefixer --save-dev
- 在项目根目录(和webpack.config.js同级)建立postcss.config.js
//postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
- 提取CSS的loader配置
{
test: /\.css$/,
use: extractTextPlugin.extract({
fallback: 'style-loader',
use: [
{ loader: 'css-loader', options: { importLoaders: 1 } },
'postcss-loader'
]
})
}
消除未使用的CSS
PurifyCSS-webpack
- 安装
purifycss-webpack依赖于purify-css这个包
npm i purifycss-webpack purify-css -D
- 引入glob和purifycss-webpack
同步检查模板,引入node的glob对象使用
//webpack.config.js
const glob = require('glob');
const purifyCssPlugin = require("purifycss-webpack");
- 配置plugins
这里配置了一个paths,主要是需找html模板,purifycss根据这个配置会遍历你的文件,查找哪些css被使用了。
//webpack.config.js
plugins:[
//new uglify()
new htmlPlugin({
minify:{
removeAttrubuteQuotes:true
},
hash:true,
template:'./src/index.html'
}),
new extractTextPlugin("css/index.css"),
new PurifyCSSPlugin({
// Give paths to parse for rules. These should be absolute!
paths: glob.sync(path.join(__dirname, 'src/*.html')),
})
]
使用这个插件必须配合extract-text-webpack-plugin这个插件
给webpack增加babel支持
Babel
Babel其实是一个编译JavaScript的平台,它的强大之处表现在可以通过便宜帮你达到以下目的:
- 使用下一代的javaScript代码(ES6,ES7….),即使这些标准目前并未被当前的浏览器完全支持。
- 使用基于JavaScript进行了扩展的语言,比如React的JSX。
Babel的安装与配置
Babel其实是几个模块化的包,其核心功能位于称为babel-core的npm包中,webpack可以把其不同的包整合在一起使用,对于每一个你需要的功能或拓展,你都需要安装单独的包(用得最多的是解析ES6的babel-preset-es2015包和解析JSX的babel-preset-react包)。
- 安装
npm i babel-core babel-loader babel-preset-env -D
- 在webpack中配置Babel的方法
{
test:/\.(jsx|js)$/,
use:{
loader:'babel-loader',
options:{
presets:[
"env"
]
}
},
exclude:/node_modules/
}
现在打包的代码就是经过处理的了
.babelrc
虽然Babel可以直接在webpack.config.js中进行配置,但是考虑到babel具有非常多的配置选项,如果写在webapck.config.js中会非常的雍长不可阅读,所以把配置写在.babelrc文件里。
- 在项目根目录新建.babelrc文件,并把配置写到文件里。
//.babelrc
{
"presets":["env"]
}
- webpack.config.js里的loader配置
{
test:/\.js$/,
use:{
loader:'babel-loader',
},
exclude:/node_modules/
}
打包后的代码调试
使用了webpack后,所以代码都打包到了一起,给调试带来了麻烦,但是webpack已经为我们充分考虑好了这点,它支持生产Source Maps来方便我们的调试。在使用webpack时只要通过简单的devtool配置,webapck就会自动给我们生产source maps 文件,map文件是一种对应编译文件和源文件的方法,让我们调试起来更简单。
在配置devtool时,webpack给我们提供了四种选项。
- source-map:在一个单独文件中产生一个完整且功能完全的文件。这个文件具有最好的source map,但是它会减慢打包速度;
- cheap-module-source-map:在一个单独的文件中产生一个不带列映射的map,不带列映射提高了打包速度,但是也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试造成不便。
- eval-source-map:使用eval打包源文件模块,在同一个文件中生产干净的完整版的sourcemap,但是对打包后输出的JS文件的执行具有性能和安全的隐患。在开发阶段这是一个非常好的选项,在生产阶段则一定要不开启这个选项。
- cheap-module-eval-source-map:这是在打包文件时最快的生产source map的方法,生产的 Source map 会和打包后的JavaScript文件同行显示,没有影射列,和eval-source-map选项具有相似的缺点。
四种打包模式,有上到下打包速度越来越快,不过同时也具有越来越多的负面作用,较快的打包速度的后果就是对执行和调试有一定的影响。
实战
开发与生产并行设置
- 修改package.json命令
"scripts": {
"start": "set type=dev&webpack-dev-server",
"build": "set type=build&webpack"
},
- 修改webpack.config.js文件
if(process.env.type== "dev"){
var website={
publicPath:"http://localhost:9898/"
}
console.log( encodeURIComponent(process.env.type) );
}else{
var website={
publicPath:"http://www.guoqianchen.com/"
}
console.log( encodeURIComponent(process.env.type) );
}
- MAC下的package.json配置
MAC电脑下需要把set换成export,并且要多加一个&符
"scripts": {
"dev": "set type=dev&webpack-dev-server",
"build": "set type=build&webpack",
"dev_mac": "export type=dev&&webpack-dev-server",
"build_mac": "export type=build&&webpack"
},
模块化
webpack.config.js要使用Common.js方式引入
打包第三方类库
引入jQuery
- 安装jquery
npm install jquery --save
- 引入到JS文件中
import $ from 'jquery'
用plugin引入
ProvidePlugin是一个webpack自带的插件,Provide的意思就是装备、提供。因为ProvidePlugin是webpack自带的插件,所以要先再webpack.config.js中引入webpack。
- webpack.config.js中引入webpack
const webpack = require('webpack');
在webpack.config.js里引入必须使用require,否则会报错的,这点小伙伴们一定要注意。
2.配置plugin模块
plugins:[
new webpack.ProvidePlugin({
$:"jquery"
})
],
配置好后,就可以在你的入口文件中使用了,而不用再次引入了。这是一种全局的引入,在实际工作中也可以很好的规范项目所使用的第三方库。
watch的配置
watchOptions:{
//检测修改的时间,以毫秒为单位
poll:1000,
//防止重复保存而发生重复编译错误。这里设置的500是半秒内重复保存,不进行打包操作
aggregeateTimeout:500,
//不监听的目录
ignored:/node_modules/,
}
webpack --watch
BannerPlugin插件
- 配置plugins
new webpack.BannerPlugin('hello')
在使用这个插件之前必须引入webpack。
const webpack = require('webpack');