在网页中会引用css、js、images、iconfont、模板文件等静态资源
网页中引入过多的静态资源会让网页加载速度变慢,因为要发起很多的二次请求,还要处理错综复杂的依赖关系
webpack是基于Node.js开发的前端的一个项目构建工具,官方说法是js应用程序的静态模块打包器,可以实现资源的合并、打包、压缩、混淆等诸多功能
安装两种方式
❶ 运行 npm i webpack -g 进行全局安装,这样就能全局使用webpack的命令
❷ 在项目根目录运行 npm i webpack --save-dev 安装到项目依赖中
webpack能够处理js文件的相互依赖关系,还能处理js兼容问题,无论是CommonJS模块加载方式 var $ = require('jquery') 还是ES6方式 import $ from 'jquery' ,在浏览器中都是不支持的,但经过webpack打包后会转为浏览器能识别的语法
将main.js打包成dist下的bundle.js,当前目录命令行输入
webpack ./src/main.js ./dist/bundle.js
出现错误
ERROR in multi ./src/main.js ./dist/bundle.js
Module not found: Error: Can't resolve './dist/bundle.js' in 'F:webpackDemo'
@ multi ./src/main.js ./dist/bundle.js main[1]
原因是webpack4以上语法更严格,需要改为
webpack ./src/main.js -o ./dist/bundle.js
不过一般是写个配置文件,然后直接输入 webpack 命令进行打包,而不是每次都手写打包的入口文件和出口文件
webpack.config.js
这个最基本的配置文件是一个js文件,通过Node中模块操作,向外暴露一个配置对象
var path = require('path')
module.exports = {
//入口,表示使用webpack打包哪个文件
entry: path.join(__dirname,'./src/main.js'),
output:{ //输出文件相关的配置
path:path.join(__dirname,'./dist'), //指定打包好的文件输出到哪个目录中去
filename:'bundle.js' //指定输出文件的名称
}
}
命令行输入webpack命令后,webpack发现没有提供指定入口和出口,就会去项目根目录查找 webpack.config.js 配置文件,解析执行该文件后得到了配置文件的配置对象,然后根据配置对象指定的入口和出口进行打包构建
webpack-dev-server
配置webpack.config文件后虽然可以只用webpack命令就能进行打包,但手动打包依旧不够方便,此时可使用webpack-dev-server这个工具,来实现自动打包编译功能(类似命令行工具nodemon)
运行命令,把这工具安装到项目的本地开发依赖
npm i webpack-dev-server -D //-D为写入到 devDependencies 对象
需要注意的是webpack-dev-server想要正常运行,还需要本地项目内安装webpack,即便全局安装了,本地也要安装
之后在package.json的scripts字段定义脚本命令,之后dev命令即代表了webpack-dev-server,注意不能在json文件里写注释!!!
最后运行命令 npm run dev ,webpack-dev-server会启动一个服务器,并且文件放在根目录下
webpack-dev-server打包生成的bundle.js文件并没有存放到物理磁盘上,直接托管到了电脑内存中
手动打开这个地址即可
常用命令参数
"scripts": {
"test": "echo "Error: no test specified" && exit 1",
"dev": "webpack-dev-server --open --port 3000 --contentBase src --hot"
}
--open为自动打开网页,--port 3000是设置端口号,--contentBase是默认打开src下的index(托管目录为src,如果删了contentBase则托管目标为根目录),--hot为热重载、热更新
设置--hot后不会每次修改都更新bundle.js,会局部更新页面
方式二,配置dev-server命令参数,相对来说麻烦
var path = require('path')
var webpack = require('webpack')
//通过Node中的模块操作,向外导出一个配置对象
module.exports = {
entry: path.join(__dirname,'./src/main.js'),
output:{
path:path.join(__dirname,'./dist'),
filename:'bundle.js'
},
devServer:{
open:true, //自动打开浏览器
port:3000, //设置启动时运行端口
contentBase:'src', //指定托管的根目录
hot:true //启用热更新,这是启用热更新的第一步
},
plugins:[
new webpack.HotModuleReplacementPlugin() //启用热更新第二步,new一个热更新模块对象
]
}
html-webpack-plugin
网页打开index是物理磁盘的index,但bundle.js不是磁盘里的bundle.js而是在内存里的,怎样让index也放到内存中,而不是每次都是磁盘上拿呢?
之所以把index放内存中是因为--contentBase指令过程比较繁琐,需要指定启动目录,关键还要修改index里的script标签src属性,所以推荐使用
html-webpack-plugin插件配置启动页面
使用步骤
❶ 安装 npm i html-webpack-plugin -D ,导入插件
❷ plugins属性中配置插件
var path = require('path')
var htmlWebpackPlugin = require('html-webpack-plugin')
//通过Node中的模块操作,向外导出一个配置对象
module.exports = {
entry: path.join(__dirname,'./src/main.js'),
output:{
path:path.join(__dirname,',/dist'),
filename:'bundle.js'
},
//只要是插件都要放到plugins节点中去
plugins:[
new htmlWebpackPlugin({
template:path.join(__dirname,'./src/index.html'), //模板路径
filename:'index.html' //自动生成的html文件名称
})
]
}
❸ 修改package.json中scripts节点的dev指令为 dev":"webpack-dev-server"
❹ 最后把index.html中script表注释掉,因为插件会自动把bundle.js注入到index.html页面中
此错误第二次遇到,找不到要加载进内存的index.html模板,两次报错都是因为路径写错!
loader
webpack默认只能打包处理js文件,处理非js文件需要收到安装合适的第三方loader(加载器)
如果要打包处理css文件
❶ 安装 npm i style-loader css-loader -D
❷ webpack.config.js配置文件中新增一个配置节点叫module,里面有个rules数组,用于存放所有第三方文件的匹配和处理规则
var path = require('path')
//通过Node中的模块操作,向外导出一个配置对象
module.exports = {
entry: path.join(__dirname,'./src/main.js'),
output:{
path:path.join(__dirname,',/dist'),
filename:'bundle.js'
},
//这个节点用于配置所有第三方模块加载器
module:{
//所有第三方模块的匹配规则
rules:[
//正则,匹配后缀是.css的文件,匹配成功则使用指定加载器
{test:/.css$/,use:['style-loader','css-loader']}
]
}
}
webpack调用第三方loader的过程:
在入口文件中import './css/index.css',发现import的是非js文件,就会去webpack.config.js配置文件中查找有没有对应的第三方loader规则
如果找到对应的规则,就会调用对应的loader处理这种文件类型
在调用loader时,是从后往前调用的,也就是先css-loader再style-loader
当最后一个loader调用完毕会把处理的结果直接交给webpack进行打包合并,最终输出到bundle.js中去
如果要import是less文件,则要安装less-loader加载器,然后配置
module:{
rules:[
{test:/.less$/,use:['style-loader','css-loader','less-loader']}
]
}
sass文件同理,安装sass-loader,失败的话改为node-sass但后缀名是.scss
url-loader
使用加载器可以打包css文件,但若css样式里有背景图或字体图标,webpack是无法处理其中的url地址的
此时需要安装url-loader,而url-loader依赖file-loader,所以两者都要下载
//这个节点用于配置所有第三方模块加载器
module: {
//所有第三方模块的匹配规则
rules: [
//正则,匹配后缀是.css的文件,匹配成功则使用指定加载器
{test: /.css$/, use: ['style-loader', 'css-loader']},
{test:/.less$/,use:['style-loader','css-loader','less-loader']},
{test:/.scss$/,use:['style-loader','css-loader','sass-loader']},
{test: /.(png|jpg|gif|jpeg|bmp)$/, use: 'url-loader'} //处理图片路径的loader
]
}
之后图片可以正常显示在页面上
loader后面都可以传参
{test: /.(png|jpg|gif|jpeg|bmp)$/, use: 'url-loader?limit=267898&name=[name].[ext]'} //处理图片路径的loader
limit给定的值是图片的大小(单位byte), 若引用的图片大于等于这个值,就不会被转为base64格式的字符串,小于则会
打包后图片名字会被改为哈希值,这样是防止图片重名,但如果我们想保持原来名字,就可使用第二个参数name
图片重名会出现覆盖的问题,就是两张图片都是一样的,如果想用原名又不想解决覆盖问题,可以在名字前加哈希值
{test: /.(png|jpg|gif|jpeg|bmp)$/, use: 'url-loader?limit=267898&name=[hash:8]-[name].[ext]'} //八位哈希值-原名
处理字体文件,加多条匹配规则即可
{test: /.(ttf|eot|svg|woff|woff2)$/, use: 'url-loader'}
babel
在webpack中只能处理一部分ES6新语法,一些更高级的ES6或ES7语法是处理不了的,这时就需要借助第三方的loader把高级语法转为低级语法
❶ webpack中要运行两套命令,安装两套包去实现Babel相关功能
npm i babel-core babel-loader babel-plugin-transform-runtime -D //babel的转换工具
npm i babel-preset-env babel-preset-stage-0 -D //babel的语法,babel-preset-env语法插件包含目前所有ES相关的语法
❷ webpack配置文件,在module节点下rules数组里添加一条新匹配规则
//在配置babel的loader规则时必须把node_modules目录通过exclude选项排除掉
{test: /.js$/,use: 'babel-loader', exclude: /node_modules/}
如果不排除node_modules,则babel会把里面所有第三方js文件都打包编译,这样很小号性能打包速度非常慢,哪怕最终把所有node_modeules中的js转换完毕,项目也无法运行
❸ 项目根目录总新建一个叫 .babelrc 的babel配置文件,此文件是JSON格式
{
"presets":["env","stage-0"],
"plugins":["transform-runtime"]
}
presets为语法,plugins为插件
至此babel配置完成