导读
Webpack是一种前端资源构建工具,也可以理解成静态模块打包器。它能将所有的前端资源文件作为模块处理,然后根据模块的依赖关系进行静态分析,打包生成对应的静态资源(称为bundle),它还能处理浏览器端js的兼容性问题。
五个核心概念
Entry 入口指示
指示Webpack以哪个文件为入口起点开始打包,分析构建内部依赖图。
Output 输出指示
指示Webpack打包后的资源bundles输出到哪里去,以及如何命名。
Loader
Loader让Webpack能够处理非Java Script文件,因为webpack自身只理解JS。
Plugins
插件Plugins可以用来执行范围更广的任务,插件的范围包括从打包优化和压缩,一直到重新定义环境中的变量等。
Mode
- developmet开发模式:让代码能在本地调试运行
- production生产模式:让代码能优化上线
- webpack只能处理js/json文件
- 生产环境和开发环境将ES6模块化编译成浏览器能识别的模块化
- 生产环境会压缩JS代码
隔行变色
通过一个小案例来学习webpack的使用。
初始化项目
- 新建项目空白目录,并运行npm init -y 命令,来初始化包管理配置文件 package.json
- 新建src源代码目录
- 新建src -> index.html 首页和src -> index.html脚本文件
- 初始化首页基本结构
- 运行npm install jquery -S 命令,安装jQuery
- 通过ES6模块化的方式导入jQuery,实现列表隔行变色的效果。
- 安装webpack相关的两个包npm install webpack@5.42.1 webpack-cli@4.7.2 -D
配置webpack
- 在项目根目录中,创建webpack.config.js的文件,并初始化以下配置
module.exports={ mode:'development' }
- 在package.json的scripts节点下,新增dev脚本
"scripts": { "dev1":"webpack" }
index.js
//使用es6导入jQuery //使用es6在jquery导入一个成员,用$来接收 import $ from 'jquery' //入口函数 $(function(){ //实现奇偶行变色 $('li:odd').css('background-color','red'); $('li:even').css('background-color','green'); })
打包构建生成main.js
- 可以通过终端npm run dev1来启动webpack进行项目的打包构建
npm run dev1
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>隔行变色</title> <!-- 这样导入会报错,因为js的语法太高级,浏览器不支持, --> <!-- <script src="./index.js"></script> --> <!-- 需要使用webpack来解决兼容性问题, 使用通过webpack对index.js生成的main.js --> <script src="../dist/main.js"></script> </head> <body> <ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> <li>6</li> <li>7</li> <li>8</li> <li>9</li> </ul> </body> </html>结果演示
webpack中的默认约定
在webpack4.x和5.x的版本中,有以下默认约定
- 默认的打包入口文件为src -> index.js
- 默认的输出文件路径为dist -> main.js
- 也可以在webpack.config.js中修改打包的默认的规定
修改webpack.config.js文件
//使用node.ja的道出语法,向外导出一个webpack的配置对象 const path1 = require('path') //导入node.js中专门操作路径的模块 module.exports={ //打包入口文件路径 entry:path1.join(__dirname,'./src/index.js'), //__dirname代表它所处的那一个目录,即文件根目录,用join和后面的路径进行拼接 //输出文件的存放的路径 output:{ path:path1.join(__dirname,'./dist'), //输出文件的名称,并放在js目录下 filename:'js/bundle.js' } }
插件
webpack-dev.server
- 类似于node.js中的nodemon工具
- 每当修改了源代码,webpack会自动进行项目的打包和构建。
安装webpack-dev-server
npm install webpack-dev-server@3.11.2 -D
配置webpack-sev-server
- 修改package.json -> scripts中的dev命令
"scripts": { "dev1": "webpack serve" }
- 再次运行npm run dev1 命令,重新进行项目的打包
- 此时终端会有一个光标一直闪烁,并进行更新和打包
- 在浏览器中访问http://localhost:8080地址,查看自动打包效果
webpack-dev-server会启动一个实时打包的http服务器
npm install webpack-cli@4.9.0 -D
<!-- 加载和引用内存中(根目录)中的bundle.js --> <script src="/bundle.js"></script>
html-webpack-plugin
运行命令安装插件,可以实现直接打开8080端口后就打开首页了。因为上面的代码会有缺点,就是每次访问都要去src里访问,比较麻烦。
npm install html-webpack-plugin@5.3.2 -D
在webpack-config.js中配置html-webpack-plugin,注意此时下面会有上面内容代码。
//使用node.ja的道出语法,向外导出一个webpack的配置对象 //导入html-webpack-plugin插件,得到一个构造函数 const HtmlPlugin=require('html-webpack-plugin') //创建html插件的实例对象 const htmlPlugin=new HtmlPlugin({ template:'./src/index.html',//指定源文件的存放路径 filename:'./index.html'//指定生成文件的存放路径 // 并且生产的首页代码还是放在了内存里,项目结构里看不到 }) //接着使插件生效 const path1 = require('path') //导入node.js中专门操作路径的模块 module.exports={ mode:'development', //打包入口文件路径 entry:path1.join(__dirname,'./src/index.js'), //__dirname代表它所处的那一个目录,即文件根目录,用join和后面的路径进行拼接 //输出文件的存放的路径 output:{ path:path1.join(__dirname,'./dist'), //输出文件的名称 filename:'bundle.js' }, //插件的数组,webpack运行时会加载这些插件 plugins:[htmlPlugin]//通过plugins节点,使htmlplugin插件生效 }
然后重新执行npm run dev1命令
- 通过html插件复制到项目根目录中的index.html页面,也被放到了内存中
- html插件在生成的index.html页面中,会自动注入了打包的bundle.js文件。
devServer节点
追加webpack-config.js配置
devServer:{ open:true,//初次打包完成后,自动打开浏览器 host:'127.0.0.1',//实时打包所使用的主机地址 port:8080//实时打包所使用的端口号 }
loader
因为webpack只能打包js文件,其他类型文件,webpack默认处理不了,需要调用loader加载器才可以正常打包,否则会报错
loader加载器的作用:协助webpack打包处理特定的文件模块,比如:
- css-loader可以打包处理css相关的文件
- babel-loader可以打包处理webpack无法处理的高级js语法。
导入css
在index.js中导入css样式
//导入样式(因为在webpack中,一切皆模块,都可以通过es6导入语法进行导入使用) import './index.css'
此时会报错,因为缺少loader,所以要安装处理css的loader
npm install style-loader@3.0.0 css-loader@5.2.6 -D
配置webpack-config.js里的配置规则,在module -> rules数组中,添加loader规则如下:
//所有第三方文件模块的匹配规则,这里也是放在module.export里 module:{ rules:[ //文件后缀名的匹配规则 {test:/\.css$/,use:['style-loader','css-loader']} ] }
其中test表示匹配的文件类型,use表示对应要调用的loader
loader的调用过程
- webpack默认只能打包处理js文件,处理不了其他文件
- 由于代码中包含css文件,因此webpack处理不了
- 接着webpack会查找webpack-config.js这个配置文件,看module.rules数组中是否配置了对应的loader加载器。
- webpack把这个css文件,先转交给最后一个loader进行处理(即css-loader)
- 当css-loader处理完毕之后,会把处理结果,转交下一个loader(即style.loader)
- 当style.loader处理完毕之后,发现没有下一个loader了,于是就把处理结果,转交给了webpack
- webpack再把结果合并到/dist/bundle.js中,最终生成打包好的文件
- use数组中指定的loader的顺序是固定的
- 多个loader的调用顺序:从后往前调用
导入less
在index.js中导入
//导入less import './index.less'
安装less的loader
npm install less-loader@10.0.1 less@4.1.1 -D
配置webpack-config.js里的module ->rules数组,添加loader规则
//所有第三方文件模块的匹配规则 module:{ rules:[ //文件后缀名的匹配规则 {test:/\.css$/,use:['style-loader','css-loader']}, //因为less的loader需要用到css-loader,所以要把它放在最后面 {test:/\.less$/,use:['style-loader','css-loader','less-loader']} ] }
打包处理样式表中与URL路径相关的文件(比如图片)
安装相关loader
npm i url-loader@4.1.1 file-loader@6.2.0 -D
在index.html中添加img标签,里面的图片路径需要index.js动态指定
<img src="" alt="" class="box">
在index.js中导入图片
//导入图片 import logo from './img/logo.jpg' //给img标签的src动态赋值 $('.box').attr('src',logo) //其中某个模块中,使用from接收到的成员为undefined,则没有必要进行接收,比如以上几个部分。
webpack-config.js添加loader
//所有第三方文件模块的匹配规则 module:{ rules:[ //文件后缀名的匹配规则 {test:/\.css$/,use:['style-loader','css-loader']}, {test:/\.less$/,use:['style-loader','css-loader','less-loader']}, {test:/\.jpg|png|gif$/,use:'url-loader?limit=22229'} ] }
其中?之后的是loader的参数项:
- limit用来指定图片的大小,单位是字节,可以省略不指定
- 只有小于limit(22229)大小的图片,才会被转为base64格式的图片,因为base64不会频繁对服务器发起请求。所以最后生成包里的src也是base64的字符串
babel-loader处理js文件中高级语法
对于那些连webpack都无法处理的高级的js语法,需要借助babel-loader进行打包处理。
安装相关loader
npm install babel-loader@8.2.2 @babel/core@7.14.6 @babel/plugin-proposal-decorators@7.14.5 -D
添加loader规则
//注意:必须使用exclude指定排除项,因为node_modules目录下的第三方包不需要被打包,只需要针对自己写的代码 {test:/\.js$/,use:'babel-loader',exclude:/node_modules/}
配置babel-loader
在项目根目录下,创建babel.config.js的配置文件,定义babel的配置项如下:
module.exports={ //声明babel可用的插件 //将来,webpack在调babel-loader的时候,会先加载plugins插件来使用 plugins:[['@babel/plugin-proposal-decorators',{legacy:true}]] }
配置build命令
"scripts": { "dev1": "webpack serve", "build1":"webpack --mode production" }
- 开发环境中,运行dev1命令
- 项目发布时,运行build1命令
- 加server还是会放在内存里,不加会放在磁盘里
–model是一个参数项,用来指定webpack的运行模式,即生产模式,压缩代码。通过–model指定的参数项,会覆盖webpck.config.js种的model选项。
运行命令重新打包发布
npm run build1
小技巧
优化js和图片的存放路径
//配置url-loader中,多个参数之间使用&符号分隔,打包的图片放在images目录下 {test:/\.jpg|png|gif$/,use:'url-loader?limit=1000&outputPath=imgages'},
自动清理dist目录下的旧文件
每次打包后都要手动删除dist目录下的文件,如果想实现自动清理,可以安装clean-webpack-plugin
npm install clean-webpack-plugin@3.0.0 -D
配置webpack-config.js文件
//左侧花括号是解构赋值 const {CleanWebpackPlugin}=require('clean-webpack-plugin') //插件的数组,webpack运行时会加载这些插件,即使插件生效 plugins:[htmlPlugin,new CleanWebpackPlugin()],
Source Map
开发环境下默认生成的Source Map,记录的是生成后的代码的位置,会导致运行时报错的行号与源代码的行号不一致。
开发环境下,推荐在wenbpack.config.js(module.exports)中添加以下配置,即可保证运行时报错的行号与源代码的行号一致。
devtool:'source-map'
只显示定位行号不暴露源码
实际发布的时候(生产模式)可以将devtool的值设置为:
devtool:'nosources-source-map'
也可以直接关闭sourceMap(即不写devtool)
@的优势
如果一个文件层级很深,会出现很多../的情况,它是由内往外查找,如果使用@表示src源代码目录,它从外往里查找。
@/index.js
配置webpack-config.js文件里的module.exports
resolve:{ alias:{ //告诉webpack,代码中@符号表示src这一层目录 '@':path.join(__dirname,'./src') } }