学习了两个星期,断断续续终于还是把webpack4学完了,我学习的时候webpack5是已经出来了的,但是大同小异先学webpack4再过渡到webpack5可以了解他们之间的差异,本次学习无项目实战,主要为webpack的配置详解,过程中因为版本问题也遇到了一些错误,在此记录我的学习笔记,这是跟做的版本,即有详细的步骤,后续还会想整理再发布一个知识点版的,大家一起进步!笔记如有错误,欢迎评论指正。
文章目录
一、webpack概述
1、什么是webpack
基于Node.JS开发出来的一个前端项目的自动化构建工具。webpack是一个现代Javascript应用程序的模块打包器(module bundler),分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,Less、TypeScript等),并将其打包为合适的格式以供浏览器使用。
Webpack的工作方式是:把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个浏览器可识别的JavaScript文件。
webpack能做的事情:
代码转换:es6转换成es5,less转换成css
文件优化:压缩代码体积,压缩文件
代码分割:将相同代码抽离
模块合并:将一些模块自动合并,按功能分类
自动刷新:在本地创建服务,热更新代码
代码校验:检测代码是否符合规范
自动发布:将打包后的代码自动发布
2、需要提前掌握的内容
- 需要node基础,以及npm的使用
- 掌握es6语法
3、最终掌握的webpack哪些内容
- webpack常见配置
- webpack高级配置
- webpack优化配置
- ast抽象语法树
- webpack中的tapable
- 掌握webpack流程,手写webpack
- 手写webpack中常见的loader
- 手写webpack中常见的plugin
4、需求
假设我们创建了一个html页面,并且使用less
(css预处理器)写好了样式,接着创建js文件,在js文件中使用es6语法引入jQuery,一切工作就绪之后,打开浏览器,发现样式不生效,js报错,原因很简单,因为浏览器不认识less
,es6新语法
。代码如下:
less:
body,html{
margin: 0;
padding: 0;
height: 100%;
background-color: pink;
#title{
color: aqua;
}
}
es6:
import $ from 'jquery'
$('#title').click(()=>{
$('body').css('backgroundColor','green')
})
这时我们需要一个能将这些浏览器不认识的东西转化成浏览器可以认识的东西,因此前端有了一个构建工具,我们只要会使用这个构建工具即可,即本次学习的webpack
5、webpack处理的简单流程
首先webpack会从入口资源开始,将所有的资源引入,形成一个chunk
即代码块,然后这些代码块里面的less,es6等,会被转化为css,可识别的js,转化的过程就叫做打包,最终形成bundle
文件
6、五个核心概念
6.1 entry
入口,指示webpack以哪个文件为入口七点开始打包,分析构建内部依赖图
6.2 output
输出,只是webpack打包后的资源bundles输出到哪里去,以及如何命名
6.3 loader
loader让webpack能够去处理那些非JavaScript文件(webpack自身只理解JavaScript),压缩图片等
6.4 plugins
插件,可以用于执行范围更广的任务,插件的范围包括,从打包优化和压缩,一种到重新定义环境中的变量
6.5 mode
模式(mode),指示webpack使用相应模式的配置
选项 | 描述 | 特点 |
---|---|---|
development | 会将process.NODE_NEV的值设置为development。 启用NamedChunksPlugin和NamedModulesPlugins |
能让代码本地调试运行的环境 |
production | 会将process.NODE_NEV的值设置为production。 启动FlagDependencyUsagePlugin,FlagIncludedChunksPlugin, ModuleConcatenationPulgin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin和UglifyJsPlugin |
能让代码优化上线运行的环境 |
开发模式配置较简单
生产模式更复杂,因为代码需要优化
- 由于css打包之后是在js里面的所以js文件会很大,需要压缩
- 由于先生成js再把css插入js中,所以会出现闪屏现象
- 由于js,css有兼容性问题,所以要处理
因为这些事情比较多,所以放在生产模式下
二、webpack初体验
1、简单使用webpack
1.1 打包js
使用npm创建一个package.json然后使用命令下载webpack与webpcak-cli
npm i webpack -g
#全局安装webpack
npm i webpack-cli -D
#本地安装生产依赖 -D即Dev
趁下载之时解释一下-g -D -s的区别
npm i xx -g:npm install xx --global的简写,对模块进行全局安装。
所谓全局安装,是指把模块安装到操作系统上,全局是指操作系统,全局安装完成后,一般会安装到AppDataAppData\Roaming\npm目录下。如:npm install webpack -g,就是全局安装webpack,在操作系统的任何一个目录下都可以使用webpack所提供的指令。
npm i xx -D:npm install xx --save-dev的简写,对模块进行局部安装,模块写入到 devDependencies 对象。
- 局部的意思是只针对当前项目,模块一般安装到项目文件夹下的node_modules文件夹下。
- devDependencies对象,是我们开发的时候需要用到的一些包,只用于开发阶段,真正打包上线的时候并不需要这些包,因为这些工具只是你用来打包代码的,是用来识别特定文件以及代码,帮助我们生产最终文件的。如npm i vue-loader vue-template-complier -D,就是在Vue项目中安装vue模板文件的解析插件,经过配置后即可在项目中解析vue模板
npm i xx -S:npm install xx --save 的简写,同上也是对模块进行局部安装,不同的是模块写入到 dependencies对象。
- 模块同上一样将安装到项目文件夹下的node_modules文件夹下。
- dependencies对象,这个与devDependencies不同,是需要发布到生产环境中的,就比如你要跑一个基于vue的项目,所以需要vue.js来支持,vue.js文件就需要跟随项目到最终的生产环境。npm i vue -S即可将Vue模块安装到项目的依赖中,并一同发布到生产环境。
安装好之后创建src
目录(放源代码目录),build
(放打包后的文件),index.js文件在src中,作为webpcak的入口文件
接下来测试验证:
//验证是否能够处理这些文件
function add(a,b){
return a+b;
}
console.log(add(1,2));
运行指令:
开发环境:webpack ./src/index.js -o ./build/built.js --mode=development
webpack会以 ./src/index.js为入口文件开始打包,打包后输出到 ./build/built.js 整体打包环境是开发环境 生产环境:webpack ./src/index.js -o ./build/built.js --mode=production
使用开发环境命令后生成了打包后的文件,文件明显更大了。因为多了一些东西,暂时我们只需要关注一下最下面,eval函数里面是我们需要打包的代码。此处由于学习时自己使用的版本与教学中的版本不一致,一些代码不相同不作细说。
生成的文件测试可以直接在html页面中引入正常使用
1.2 测试打包其他
新建json
文件,使用es6语法在index.js中引入,输入命令打包文件,打包好后的文件在html中引入,测试可以输出
新建css
文件,同样操作,报错
1.3 结论
1.webpack可以打包js
,json
文件,不能处理css
,img
等资源
2.生产和开发环境将es6模块化编译成浏览器能识别的模块化
3.生产环境比开发环境多一个压缩js代码
三、开发环境配置
1、打包样式资源(loader的使用)
首先我们进行一下webpack的配置,下面给出超详细代码加注释
/**
* webpack的配置文件
* 作用:指示webpack干哪些活,当你运行webpack时,回家再里面的配置
*
* 所有构建工具都是基于nodejs平台运行的,模块化默认采用commonjs
*/
//resolve用来拼接绝对路径的方法
const {
resolve } = require('path')
module.exports= {
//webpack配置
//入口起点
entry:'./src/index.js',
//输出
output:{
//输出文件名
filename:'built.js',
//输出路径,__dirname是nodejs的变量,代表当前文件的目录绝对路径
path:resolve(__dirname,'build')
},
//loader的配置
module:{
rules:[
//详细loader配置
{
//匹配哪些文件,即要打包哪些文件
test:/\.css$/,
use:[
//user数组中loader的执行顺序:从右到左,从下到上依次执行
//创建style标签,将js中的样式资源插入里面,添加到head
'style-loader',
//将css文件变成commonjs模块加载js中,里面内容是样式字符串
'css-loader'
]
}
]
},
plugins:[
// plugin的配置
],
//模式
mode:'development',//生产模式
//mode:production
}
然后在项目中下载需要的包,我学习的时候我是创建的新目录,所以全部包需要重新下载,但是为了后面节约时间,我们可以把包放在上一级目录,这里不但需要下载webpack
和webpack-cli
还要下载style-loader
和css-loader
npm i webpack webpack-cli -D
npm i css-loader style-loader -D
下载好后,将打包后的js引入html,可以成功显示!
那此时能否打包less呢,测试,不行。需要增加less-loader
另写一个loader
{
// 不同文件需要不同的loader处理
test:/\.less$/,
use:[
'style-loader',
'css-loader',
//加载less的loader
'less-loader'
]
}
下载包
npm i less -D
npm i less-loader -D
输入webpack命令,打包成功,运行成功!
2、打包html资源(plugin的使用)
前面是loader的使用:
配置loader,下载相关包,webpack打包,运行。
现在是plugin
的使用:
下载,引入,打包运行
npm i html-webpack-plugin -D
#下载
plugins:[
// plugin的配置
//html-webpcak-plugin
//功能:默认会创建一个空的html,自动引入打包输出的所有资源(js/css),无结构
//需要有结构的html文件,则在下面加上template
new HtmlWebpackPlugin({
//复制 './src/index.html'文件,并且自动引入打包输出的所有资源(js/css)
template:'./src/index.html'
})
]
再次输入命令打包,发现出口多了一个html文件,并且默认引入了built.js,运行该文件,与之前效果相同!
3、打包图片资源
这里再新建一个文件夹,因此又回顾了一下写配置文件,按之前的样子搭建好文件目录结构
其中src/index.html写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>webpack</title>
</head>
<body>
<div id="box1"></div>
<div id="box2"></div>
<div id="box3"></div>
</body>
</html>
index.less
#box1 {
width: 100px;
height: 100px;
background: url(./beibei.jpg) no-repeat;
}
#box2 {
width: 200px;
height: 200px;
background: url(./CBN.jpg) no-repeat;
}
#box3 {
width: 300px;
height: 300px;
background: url(./didi.jpg) no-repeat;
}
div{
img{
width: 100%;
}
}
此时测试打包,看能否打包图片资源,很明显,报错
显然我们需要手写配置
{
test:/\.(jpg|png|gif)$/,
//多个loader时,使用use,一个时可以直接使用loader
//下载两个包url-loader file-loader,前者依赖于后者
loader:'url-loader',
options:{
//图片大小小于8kb,就会被base64处理
//优点:减少请求数量(减轻服务器压力)
//缺点:图片体积更大(文件请求速度更慢)
limit: 8 * 1024
}
}
加上这个loader,下载两个包
npm i url-loader file-loader -D
打包运行,这里我放的三张图片分别是7kb,45kb,27kb,运行之后会发现只输出了两张图片,就是除了7kb的,因为7kb的被base64处理了可以在网页上直接运行,but不会输出,运行html,成功!
但是此时还不能完全解决图片资源的问题,在html,假设我们使用img标签来引入图片,由于webpack使用的是我们自己的模板,里面的路径还是我们自己的,此时就会出现路径问题,那我们需要继续配置loader
{
test:/\.html$/,
//处理html中的图片问题,负责引入,从而可以被url-loader处理
loader:'html-loader'
}
然后下载,注意下载的文件夹位置,我们统一是放在一个大的目录中
npm i html-loader -D
运行之后报错,“Automatic publicPath is not supported in this browser”,具体情况可以参考报错详情。在output
中添加publicPath:'./'
即可,运行打包后的html文件,成功!
打包生成的html文件中的img
标签代码如下:
<img src="./99f0b5ce5fa4911d32768ac724309052.jpg" alt="">
99f0b5ce5fa4911d32768ac724309052
是图片的哈希值,名字太长了我们希望可以短一些,可以设置一些名字,可以使用name
来更改名字
{
test:/\.(jpg|png|gif)$/,
//多个loader时,使用use,一个时可以直接使用loader
//下载两个包url-loader file-loader,前者依赖于后者
loader:'url-loader',
options:{
//图片大小小于8kb,就会被base64处理
//优点:减少请求数量(减轻服务器压力)
//缺点:图片体积更大(文件请求速度更慢)
limit: 8 * 1024,
//由于输出的图片名字,是图片内容生成的哈希值,我们可以更改他的名字
//给图片重命名
//[hash:10]取文件的前十位哈希值
//[ext]保持原来的扩展名
name:'[hash:10].[ext]'
}
}
4、打包其他资源
其他资源即字体图标等。这里使用的字体图标是阿里矢量库的,经过前面的学习,相信无论是你我,都已经可以自己写出来了
{
//打包除了html/css/js资源以外的资源
exclude:/\.(css|js|html)$/,
//使用file-lodaer打包
loader:'file-loader'
}
5、devServer
由于我们在开发中要不断添加代码不断打包,每次添加完代码都要输入webpack进行打包一次,这很麻烦。devServer就是帮助我们来处理这件事的,我们可以只写代码,他自动帮我们打包。上配置。
//开发服务器devServer:用来自动化(自动编译,自动打开浏览器,自动刷新浏览器)
//特点:只会在内存中编译打包,不会有任何输出到本地代码
//启动devServer指令为:webpack-dev-server,因为我们是本地安装,因此指令为npx webpack-dev-server
devServer:{
contentBase:resolve(__dirname,'build'),
//启动gzip压缩,使代码体积更小
compress:true,
//服务器端口号
port:3000
}
devServer
是独立于之前写的五个模块之外的,所以要单独写一个。
下载devServer
npm i webpack-dev-server -D
运行,报错!!!作为刚学习的我真的弄了非常久。详情dev启动报错
更改之后成功运行!(成功的标志是不可继续输入命令,即正在运行服务器)
并且更改会编译成功!这里虽然编译成功,但是不会自动刷新网页,并且所有东西不报错时,尝试删除publicPath
6、总结
开发环境配置
// resolve用来拼接绝对路径的方法
const {
resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引用plugin
module.exports = {
// webpack配置
entry: './src/js/index.js', // 入口起点
output: {
// 输出
// 输出文件名
filename: 'js/build.js',
// __dirname是nodejs的变量,代表当前文件的目录绝对路径
path: resolve(__dirname, 'build'), // 输出路径,所有资源打包都会输出到这个文件夹下
},
// loader配置
module: {
rules: [
// 详细的loader配置
// 不同文件必须配置不同loader处理
{
// 匹配哪些文件
test: /\.less$/,
// 使用哪些loader进行处理
use: [
// use数组中loader执行顺序:从右到左,从下到上,依次执行(先执行css-loader)
// style-loader:创建style标签,将js中的样式资源插入进去,添加到head中生效
'style-loader',
// css-loader:将css文件变成commonjs模块加载到js中,里面内容是样式字符串
'css-loader',
// less-loader:将less文件编译成css文件,需要下载less-loader和less
'less-loader'
],
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
// url-loader:处理图片资源,问题:默认处理不了html中的img图片
test: /\.(jpg|png|gif)$/,
// 需要下载 url-loader file-loader
loader: 'url-loader'