目录
4.3.1 webpack插件一:webpack-dev-server
4.3.2 webpack插件二:html-webpack-plugin
5.2.1 把js文件统一放到js目录中、图片放到images目录下
5.2.2 dist目录的自动删除-clean-package-plugin插件
一、前端工程化的概念
webpack:前端工程化的一种具体解决方案
前端工程化:在企业级的前端项目开发中,把前端开发所需的工具、技术、流程、经验等进行规范化、标准化。 前端工程化的解决方案
目前主流的前端工程化解决方案:
webpack ( 🔗:webpack中文文档 ) (主要用这个)
parcel ( 🔗:parcel中文网 )
二、webpack的基本使用
主要功能:提供了友好的前端模块化开发支持,以及代码压缩混淆(减小体积)、处理浏览器端JavaScript的兼容性(将高级的代码转换成低级的没有兼容问题的代码,有对应不同版本的解决方案)、性能优化等强大的功能。
优点:让程序员把工作的重心放在具体功能的实现上,提高了前端开发效率和项目的可维护性。
*目前Vue, React等前端项目,基本上都是基于webpack进行工程化开发的。
三、案例——初始化隔行变色案例
(1)新建项目空白目录,运行npm init -y,初始化包管理配置文件package.json
(2)新建src源代码目录
(3)新建src/index.html首页和src/index.js脚本文件
(4)初始化页面基本结构.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>Document</title> </head> <body> <ul> <li>这是第 1 个li</li> <li>这是第 2 个li</li> <li>这是第 3 个li</li> <li>这是第 4 个li</li> <li>这是第 5 个li</li> <li>这是第 6 个li</li> <li>这是第 7 个li</li> <li>这是第 8 个li</li> <li>这是第 9 个li</li> </ul> </body> </html>
(5)运行npm install jquery -S,安装jQuery。(等价于npm install jquery --save、npm i jquery -S,save是将导包的配置写入package.json的意思,不加--save也会写入)
(6)通过ES6模块化的方式导入jQuery,实现隔行变色效果
----------index.js import $ from 'jquery' $(function(){ $('li:odd').css('background-color','red') $('li:even').css('background-color','pink') })
并在index.html中引入index.js.
<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>Document</title> <script src="./index.js"></script> </head>
(7)右键,浏览器中打开
运行结果:未实现预期效果,报错。原因为语法过于高级导致。需要使用webpack解决
小技巧:
(1)vscode里html文件输!会生成html模板
(2)html中多个<li>的快捷方式:ul>li{这是第 $ 个li}*9,生成9个li
(3)vscode右键无在浏览器中打开的选项。解决方案如下:安装插件
四、案例——采用webpack解决初始化隔行变色不生效问题
4.1 webpack的安装
4.1.1 webpack 包安装
在终端运行npm install webpack@5.42.1 webpack-cli@4.7.2 -D
此处的-D和上面的-S效果相同,都是将信息写入package.json。只不过写的位置不同而已
-D是放入devDependencies【开发阶段用、上线后不需要使用】下,-S放入dependencies【开发和上线后都需要使用】下。
-D的全写是--save-dev
"dependencies": {
"jQuery": "^1.7.4",
"jquery": "^3.6.0"
},
"devDependencies": {
"webpack": "^5.42.1",
"webpack-cli": "^4.7.2"
}
知识点:如何判断一个包是-S还是-D呢?
进入npmjs.com。搜报名,如webpack。查看install的方式。如下webpack采用-D方式
4.1.2 项目中配置webpack
(1)项目根目录中,创建webpack.config.js的webpack配置文件,初始化配置如下:
module.exports = {
mode:'development' //mode用来指创建模式,可选值有development和production
//开发时用development,因为开发追求的是打包的速度,而不是体积;
//发布上线时用production,因为上线追求的是体积小,而不是打包速度;
}
(2)package.json中的script节点下,新增dev脚本
"scripts": {
"dev":"webpack" //script节点下的脚本,可以通过npm run执行,如 npm run dev。
注:此处必须是webpack,但不一定是dev
},
(3)终端执行npm run dev。
从上图可以看出,新增main.js文件,main.js文件是压缩index.js和jquery.js而来的
npm run dev时先读取index.js,再去读取webpack.config.js获取相关配置,再根据配置运行webpack
(4)此时发现在新增dist/main.js文件。main.js是有index.js转化来的,不存在兼容性问题。
所以,在index.html中引入main.js而不是index.js
<!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>Document</title>
<script src="../dist/main.js"></script>
</head>
(5)浏览器中打开index.html,隔行变色效果实现,且控制台无报错:
4.2 webpack的基本使用
4.2.1 webpack的默认约定
在webpack4.x和5.x版本中,有如下的默认约定:
(1)默认的打包入口文件为src/index.js
(2)默认的输出文件路径为dist/main.js
4.2.2 修改webpack的默认约定
在webpack.config.js中,通过entry修改打包的入口,output修改打包的出口。
注:(1)需引入path。path.join是用于路径拼接的
(2)__dirname是取当前文件所在的路径。
const path = require('path')
module.exports = {
mode:'development', //mode用来指创建模式,可选值有development和production
entry:path.join(__dirname,'./src/index1.js'), //打包入口文件路径
output:{
path:path.join(__dirname,'./dist'), //输出文件的存放路径
filename:'bule.js' //输出文件名称
}
}
同步修改index.html,引入bule.js。
<!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>Document</title>
<script src="../dist/bule.js"></script>
</head>
执行npm run dev无报错。
存在问题:每次修改src源代码后都需要执行npm run dev.需要安装插件才可以实现src源代码和dist文件同步更新
4.3 webpack中的插件
最常用的webpack插件有2个:
(1)webpack-dev-server:类似于node.js中的nodemon工具,每当修改了源代码,webpack会自动进行项目的打包和构建
(2)html-webpack-plugin:webpack中的html插件(类似于一个模板引擎插件),可以通过此插件自定义index.html页面的内容
4.3.1 webpack插件一:webpack-dev-server
1、webpack-dev-server的安装:终端执行npm install webpack-dev-server@3.11.2 -D
2、webpack-dev-server的配置:修改package.json中的dev命令为webpack serve
"scripts": {
"dev": "webpack serve"
},
3、运行npm run dev,重新进行项目打包。更新源代码后,自动打包。
问题:执行npm run dev后报错如下:
解决办法:重新安装webpack-cli:终端执行npm install webpack-cli -D。问题解决。
CTRL+C 终止实时打包。
但是此时不能再右键open in brower.因为原地址是file:///D:/vueworkspace/row-cloor/src/index.html。现在需要采用http://localhost:8080/访问
点击源文件,出现效果图。但是发现源代码更改并没有生效。原理是webpack-dev-server实时打包的main.js并不会放到dist目录下,而是放到/main.js。main.js并没有存到物理空间,而是在内存中,所以不会看到,但却是实际存在的。
解决方案:index.html中引入根目录下的main.js.
<!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>Document</title>
<script src="/main.js"></script>
</head>
存在问题:访问http://localhost:8080/首先看到的是目录,不是页面。
解决办法:将src目录下的index.html文件拷贝到项目根目录下。采用html-webpack-plugin插件解决。
4.3.2 webpack插件二:html-webpack-plugin
(1)安装:npm install html-webpack-plugin@5.3.2 -D
(2)配置webpack.config.js文件,三个步骤,如下:将src/index.html文件复制到./index.html
const path = require('path')
// 1、导入HTML插件,得到构造函数
const HtmlPlugin = require('html-webpack-plugin')
// 2、创建HTML插件的实例对象
const htmlPlugin = new HtmlPlugin({
template:'./src/index.html', //源文件的存放路径
filename:'./index.html' //生成的文件的存放路径
})
module.exports = {
mode:'development', //mode用来指创建模式,可选值有development和production
//3、通过plugin节点,使htmlPlugin生效
plugins:[htmlPlugin]
}
html-webpack-plugin插件的作用:
(1)将src/index.html文件复制到./index.html
(2)在生成的index.html中,自动注入了打包的main.js。也就是说index.html中可以去掉<script src="/main.js"></script>
4.4 webpack中的devServer节点
在webpack.config.js中,可以通过devServer节点对webpack-dev-server插件进行更多的配置,示例代码如下:
module.exports = {
mode:'development', //mode用来指创建模式,可选值有development和production
//3、通过plugin节点,使htmlPlugin生效
plugins:[htmlPlugin],
devServer:{
open:true, //初次打包完成,浏览器是否自动打开
host:'127.0.0.1', //实时打包的主机地址
port:80 //实时打包使用的端口号
}
}
注:凡是修改了webpack.config.js或者package.json,必须重启实时打包的服务器,否则无法生效
4.5 webpack中的loader
webpack只能打包以js后缀名结尾的模块,对于非js结尾的模块,需要调用loader加载器才可以正常打包,否则会报错。
loader加载器的作用:协助webpack处理特定的文件模块。如:
(1)css-loader可以打包处理.css相关的文件。
(2)less-loader可以打包处理.less相关的文件
(3)babel-loader可以打包处理webpack无法处理的高级JS语法。
loader的调用过程
4.5.1 打包处理css文件-css-loader
步骤:(1)src下新建css目录,css下新建index.css文件,编辑如下:
li {
list-style: none;
}
(2)在index.js中导入index.css
import $ from "jquery"
import './css/index.css'
$(function(){
$("li:odd").css("background-color","red")
$("li:even").css("background-color","yellow")
})
(3)运行npm i style-loader@3.0.0 css-loader@5.2.6 -D .安装css文件loader
(4)在webpack.config.js的module-rule数组中,添加loader规则:
module.exports = {
mode:'development', //mode用来指创建模式,可选值有development和production
//3、通过plugin节点,使htmlPlugin生效
plugins:[htmlPlugin],
devServer:{
open:true, //初次打包完成,浏览器是否自动打开
host:'127.0.0.1', //实时打包的主机地址
port:80 //实时打包使用的端口号
},
module:{
rules:[
{test:/\.css$/,use:['style-loader','css-loader']}
]
}
}
注:test表示文件的匹配类型,\是转义字符。use表示要调用的loader.use中指定的loader顺序是固定的,多个loader的调用顺序是:从后往前调用
4.5.1 打包处理less文件_less-loader
步骤:(1)src下新建less目录,css下新建index.css文件,编辑如下:
html,
body,
ul{
margin: 0;
padding: 0;
li{
line-height: 30px;
padding-left: 20px;
font-size: 12px;
}
}
(2)index.html文件中引入index.less
import './css/index.less'
(3)运行npm i less-loader@10.0.1 less@4.1.1 -D,安装包
(4)在webpack.config.js中的module-rules中添加loader规则
4.5.2 图片加载器_url-loader
图片设置的两种方式:
<image src='./logo.jpg'>
<image src='data:image/jpg;base64,iVBORw0KGgoAAAANSUhEUgAAAoQAAAJLCAYAAAB+CYcuAAAAAXNSR0IArs4c6QAAIABJREFUeF7svQmYXFW1/v2eGrp6yNBJyJyQhMzzDEkgAyEaQBSBaAQcQLyifuKVCxcFRFSuA14QFK8Kiuj9M0UZxBuBQBIykHkeyEjmuTtDZ+ihxvM9a1efSnV1Vdd0qupU1bufp5+mu/ZZe+3fPq1v1t5rba2urk4HGwmQAAmQAAmQAAmQQNES0CgIi3btOXESIAESIAESIAESUAQoCPkikAAJkAAJkAAJkECRE6AgLPIXgNMnARIgARIgARIgAQpCvgMkQAIkQAIkQAIkUOQEKAiL/AXg9EmA'>
BASE64作为src属性可以防止多次请求,但是图片会比实际的大。一般在获取小图标时建议采用Base64.
图片的base64获取办法:浏览器输入base64。即可获取。
步骤:(1)src下新建images目录,并上传logo.jpg至images目录下
(2)index.html文件中,新增image标签,编辑如下
<!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>Document</title>
<script src="/main.js"></script>
</head>
<body>
<ul>
<li>这是第 1 个li</li>
<li>这是第 2 个li</li>
<li>这是第 3 个li</li>
<li>这是第 4 个li</li>
<li>这是第 5 个li</li>
<li>这是第 6 个li</li>
<li>这是第 7 个li</li>
<li>这是第 8 个li</li>
<li>这是第 9 个li</li>
</ul>
<image src='' alt='' class='box'>
</body>
</html>
(3)index.js中引入logo.jpg,并设置其属性
import $ from "jquery"
import './css/index.css'
import './css/index.less' //只引入,不接收
import logo from './images/logo.jpg' //引入并接收
$(function(){
$("li:odd").css("background-color","red")
$("li:even").css("background-color","yellow")
$('.box').attr('src',logo)
})
(4)运行npm i url-loader@4.1.1 file-loader@6.2.0 -D
(5)在webpack.config.js中配置module-rules参数,添加loader规则:
const path = require('path')
// 1、导入HTML插件,得到构造函数
const HtmlPlugin = require('html-webpack-plugin')
// 2、创建HTML插件的实例对象
const htmlPlugin = new HtmlPlugin({
template:'./src/index.html', //源文件的存放路径
filename:'./index.html' //生成的文件的存放路径
})
module.exports = {
mode:'development', //mode用来指创建模式,可选值有development和production
//3、通过plugin节点,使htmlPlugin生效
plugins:[htmlPlugin],
devServer:{
open:true, //初次打包完成,浏览器是否自动打开
host:'127.0.0.1', //实时打包的主机地址
port:80 //实时打包使用的端口号
},
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用来指定图片的大小,单位是字节Byte.只有小于等于limit大小的图片,才会被转换为base64格式的图片。大于limit的图片,不会转为base64
4.5.3 js加载器_babel-loader
(1)index.js中加入装饰器函数
import $ from "jquery"
import './css/index.css'
import './css/index.less'
import logo from './images/logo.jpg'
$(function(){
$("li:odd").css("background-color","red")
$("li:even").css("background-color","yellow")
$('.box').attr('src',logo)
})
function info(target){
target.info = 'Person info.'
}
@info
class Person{}
console.log(Person.info)
(2)运行npm i babel-loader@8.2.2 @babel/core@7.14.6 @babel/plugin-proposal-decorators@7.14.5 -D引包
(3)在webpack.config.js中配置module-rules参数,添加loader规则如下:
module:{
rules:[
{test:/\.js$/,use:'babel-loader',exclude:/node_modules/}
]
}
(4)项目根目录下新建babel.config.js文件,配置如下:
module.exports = {
plugins:[['@babel/plugin-proposal-decorators',{legacy:true}]]
}
五、打包发布(npm run build)
5.1 配置
在package.json中的script节点下,新增build命令如下:
"scripts": {
"dev": "webpack serve",
"build":"webpack --mode production"
},
执行npm run build打包
--mode是一个参数项,用来指定webpack的运行模式,production代表生产环境,进行代码压缩和性能优化。通过--model指定的参数项,会覆盖webpackage.config.js中的model.
总结:npm run dev和npm run build的区别
npm run dev用于开发阶段,打包后的文件在内存中,并不会展示到物理空间,不显示,有压缩
npm run build用于上线,打包后的文件在物理空间中,体积大
5.2 dist目录的整理
执行npm run build后发现js和图片都在dist目录下,比较乱。理想的情况是新建一个js目录放js文件,images文件夹存放图片。
5.2.1 把js文件统一放到js目录中、图片放到images目录下
在webpack.config.js中配置output节点进行js文件的配置。在module-rules中配置outputPath参数
注:每次打包前需要先把原dist目录删除!!
const path = require('path')
// 1、导入HTML插件,得到构造函数
const HtmlPlugin = require('html-webpack-plugin')
// 2、创建HTML插件的实例对象
const htmlPlugin = new HtmlPlugin({
template:'./src/index.html', //源文件的存放路径
filename:'./index.html' //生成的文件的存放路径
})
module.exports = {
mode:'development', //mode用来指创建模式,可选值有development和production
//3、通过plugin节点,使htmlPlugin生效
plugins:[htmlPlugin],
devServer:{
open:true, //初次打包完成,浏览器是否自动打开
host:'127.0.0.1', //实时打包的主机地址
port:80 //实时打包使用的端口号
},
output:{
path:path.join(__dirname,'dist'),
filename:'js/index.js'
},
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&outputPath=images'},
{test:/\.js$/,use:'babel-loader',exclude:/node_modules/}
]
}
}
5.2.2 dist目录的自动删除-clean-package-plugin插件
为了在每次打包发布时自动清理掉dist目录中的旧文件,可以安装并配置clean-package-plugin插件。插件配置可参考clean-webpack-plugin - npm官网
(1)执行npm i -D clean-webpack-plugin安装插件
(2)在webpack.config.js中配置:一是导入插件,得到构造函数;二是将实例对象添加至plugin数组中
const path = require('path')
const {CleanWebpackPlugin} = require('clean-package-plugin')
// 1、导入HTML插件,得到构造函数
const HtmlPlugin = require('html-webpack-plugin')
// 2、创建HTML插件的实例对象
const htmlPlugin = new HtmlPlugin({
template:'./src/index.html', //源文件的存放路径
filename:'./index.html' //生成的文件的存放路径
})
module.exports = {
mode:'development', //mode用来指创建模式,可选值有development和production
//3、通过plugin节点,使htmlPlugin生效
plugins:[htmlPlugin,new CleanWebpackPlugin()],
devServer:{
open:true, //初次打包完成,浏览器是否自动打开
host:'127.0.0.1', //实时打包的主机地址
port:80 //实时打包使用的端口号
},
output:{
path:path.join(__dirname,'dist'),
filename:'js/index.js'
},
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&outputPath=images'},
{test:/\.js$/,use:'babel-loader',exclude:/node_modules/}
]
}
}
六、Source Map
6.1 什么是Source Map
Source Map就是一个信息文件,里面存储着位置信息。也就是Source Map文件中存储中压缩混淆后的代码所对应的转换前的位置。出错的时候,排错工具将直接显示原始代码,而不是转换后的代码,方便调试。
6.2 默认的Source Map的问题
开发环境下默认生成的Source Map,记录的是生成的代码的位置,会导致报错的行数与源代码行数不一致的情况,如下:
6.3 解决默认的Source Map的问题
开发环境下,推荐在webpack.config.js中添加devtool配置,保证运行时报错的行数和源代码行数保持一致
module.exports = {
devtool:'eval-source-map',
mode:'development', //mode用来指创建模式,可选值有development和production
}
执行npm run dev查看,报错行数与实际保持一致
6.4 生产环境下取消Source Map以保持安全性
生产环境下注释webpack.config.js中的devtool以保持安全性
6.5 Source Map的最佳实践
(1)开发环境下:devtool设置为eval-source-map,报错可定位至具体的文件、行号、点击链接是源文件
(2)生产环境下:关闭Source Map或者devtool设置为nosources-source-map(可定位至具体的文件、行号、点击链接不是源文件)可防止源码泄露
注:import时可采用@代替src目录,避免../../的繁琐。
需在webpack.config.js中进行resolve配置,指定@代表的是src目录:
module.exports = {
mode:'development', //mode用来指创建模式,可选值有development和production
resolve:{
alias:{
'@':path.join(__dirname,'./src/')
}
}
}
import '@/index.js'
七、谷歌浏览器中安装vue-devtools调试工具
(1)谷歌浏览器---设置----拓展程序----右上角打开开发者模式
(2)下载vue-devtools.crx文件(已存网盘)---文件拖至上一步的拓展程序窗口---关闭开发者模式
(3)点击vue-devtools.crx插件详情-----允许访问文件网址设置为true