简单记录自己学习的点点滴滴, 一定要有产出,才会进步,有错误的地方还望大佬指出
webpack是什么?
webpack是javascript应用程序的静态模块打包器(Static Module bundle),在处理js应用程序时,会在内部形成一个依赖关系图,来映射项目中所用到的各个模块,并生成一个或者多个文件(bundle),以便供浏览器使用;
核心概念有:
loader、plugins、Entry、Output、SourceMap、DevServer、Hmr、Babel
TreeShaking、环境区分、CodeSpilting、打包分析、代码分割、环境变量的使用
自己手动配置下webpack-demo来加深学习:
1.首先新建文件webpack-demo, 打开终端,执行npm init -y,生成package.json文件-项目描述文件
//项目名
"name": "webpack-demo",
//版本信息
"version": "1.0.0",
//项目的描述
"description": "webpack学习记录",
//项目的主入口文件
"main": "index.js",
//配置打包命令的
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
//关键词,可以来描述项目
"keywords": [],
//作者信息
"author": "",
//项目遵循的协议,ISC就是开发源代码的协议
"license": "ISC"
}
2.安装webapck
全局安装 npm i webpack webpack-cli -g 这种是不推荐的,因为我们可能开发不同的项目,webpack版本用的可能是不一样的,会遇到一些版本不匹配的问题
局部安装 npm i webapck webpack-cli -D 比较推荐的
-D 就是–save-dev的缩写 安装的第三方包被记录在package.json里面的"devdependencies",代码如下:表示开发环境依赖的包
"devDependencies": {
"webpack": "^4.16.1",
"webpack-cli": "^3.3.10"
}
我们先使用webpack默认的规则进行打包,在根目录新建src文件夹并且新建index.js与list.js文件,代码如下:
--list.js--
export const list=()=>{
console.log('我是list')
}
--index.js--
import {list} from './list'
list()
在终端执行npx webpack index.js命令,就是打包index.js文件 npx webpack 就会去node_modules中寻找安装的webpack版本
默认会生成dist/main.js文件,此时代码已经帮我们进行了压缩等操作
想要定制化的配置,我们需要在webpack.config.js文件中
3.webpack的配置需要在根目录下新建webpack.config.js文件
基础配置:mode(配置环境),entry(入口文件),output(输出文件)
const path=require('path')
module.exports={
// 默认是production,打包压缩文件,开发是:development,不会压缩文件
mode:"production",
//入口文件
entry:'./src/index.js',
// 打包后输出的文件地址以及名称
output:{
// 自定义打包文件名
filename:"bundle.js",
// 写绝对路径
path:path.resolve(__dirname,'dist')
}
}
终端输入:npx webapck --config webapck.config.js命令后就会打包出bundle.js文件
安装webpack-dev-server用来启动我们的服务 安装npm i webpack-dev-server@3.11.2 -D
每次打包我们都要使用好长的命令,真实项目中我们都是把命令配置在package.json中的
"scripts": {
"build": "webpack", //默认也是会去node_modules中去查找webpack的
"dev":"webpack-dev-server"
},
接下来,只需要在项目终端运行npm run build即可实现打包,npm run dev启动我们的服务
4.html-webpack-plugin
打包的时候自动生成我们需要的html文件(可以配置根据我们的模板自动生成),并且将打包好的js,css引入到html中,完成解放了我们的双手,需要插件html-webpack-plugin
npm i html-webpack-plugin@4.0.0
//引入插件
const HtmlWebapckPlugin=require('html-webpack-plugin')
//使用插件,直接在plugins中配置
module.exports={
mode:'development',
entry:'./src/index.js',
output:{
filename:'bundle.js',
path:path.resolve(__dirname,'dist')
},
plugins:[
new HtmlWebapckPlugin({
// 模板html的位置,如果不配置这一项,也会生成一个html文件,但是内容是空的;
// 所以项目中一定会配置这一项
template:"./src/index.html"
})
]
}
上面的是单入口文件的配置,如果是多入口文件该如何开发呢?
src目录新建文件如下目录:当然这是为了学习用,html文件项目中可以放到public文件夹中
module.exports={
mode:'development',
entry:{
index:path.resolve(__dirname,'./src/index.js'),
demo:path.resolve(__dirname,'./src/demo.js')
},
output:{
filename:'[name].[hash:8].js',
path:path.resolve(__dirname,'dist')
},
plugins:[
new HtmlWebapckPlugin({
// 模板html的位置,如果不配置这一项,也会生成一个html文件,但是内容是空的;
// 所以项目中一定会配置这一项
template:"./src/index.html",
filename:'index.html',
chunks:['index'] //与入口文件写的模块名要一样
}),
new HtmlWebapckPlugin({
template:"./src/demo.html",
filename:'demo.html',
chunks:['demo']
})
]
}
5.clean-webpack-plugin
我们发现每次打包dist目录都会存在老的打包版本,需要手动去删除,再打包,再次为了解放双手,实现自动的打包前删除dist目录,引入另外一个插件:clean-webpack-plugin
npm i clean-webpack-plugin@4.0.0 -D
//引入插件,这次要单独导入,加个中括号,一定要注意
const {CleanWebpackPlugin}=require('clean-webpack-plugin')
//配置
module.exports={
.....
plugins:[
.....
new CleanWebpackPlugin() //直接配置使用
]
}
6.我们接下来处理css,less,sass文件,需要loader来帮忙,loader如下:
postcss-loader:就是做浏览器的兼容处理的,在css前面加上前缀
less less-loader:less-loader就是把less格式转化为css格式的
sass sass-loader:sass-loader就是把sass格式的转化为css格式的
css-loader:处理css文件,webpack只认识js和json,需要css-loader来转化
style-loader:将处理好的css以style标签的方式直接注入到html中
npm i style-loader@2.0.0 css-loader@5.2.7 less-loader@7.3.0 sass-loader@7.3.1 -D
npm i postcss-loader@3.0.0 -D
还要安装与postcss-loader对应的autoprefixer这个包
npm i autoprefixer -D
版本可以自己选择,注意的是:有的版本过高是不能使用的,因为我们使用的是webpack4
处理css的配置:
module.exports={
.....
module:{
rules:[
{
test:/\.css$/, //匹配css文件
//直接使用loader,垂直方向写执行的顺序是从下到上;
//['style-loader','css-loader','postcss-loader']-->从右往左执行
use:[
'style-loader',
'css-loader',
{ //配置postcss-loader有两种方式,方式一全部在webapck.config.js中配置,如下:
loader:"postcss-loader",
options:{
plugins:[require('autoprefixer')]
}
}
]
}
]
},
......
}
配置postcss-loader第二种方式,在根目录新建postcss.config.js文件,在里面配置options选项;
postcss.config.js里面的代码如下:
module.exports={
plugins:[
require('autoprefixer')
]
}
处理less的配置:
{
test:/\.less$/, //匹配less文件
//使用loader,postcss-loader的配置是选择的第二种方式,新建postcss.config.js
use:['style-loader','css-loader','less-loader','postcss-loader']
}
处理sass的配置:sass是css的扩展语言,并不是以.sass结尾创建文件的,一般是以.scss结尾的,这个注意下
{
test:/\.scss$/, //处理scss文件
//使用loader
use:['style-loader','css-loader','sass-loader','postcss-loader']
}
上面处理后的css最后是以style标签的方式注入到html文件中,我们想要把css文件单独提取出来,以link的方式引入到html中,就需要一个插件:mini-css-extract-plugin;
mini-css-extract-plugin把js中import导入的样式文件,单独打包成一个css文件,结合html-webpack-plugin,以link的形式插入到html文件中。
npm i mini-css-extract-plugin@1.6.2 -D
//引入插件
const MiniCssExtractPlugin=require('mini-css-extract-plugin')
//配置使用插件
moduel:{
rules:[
....
{
test:/\.css$/
use:[
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
},
....
]
},
plugins:[
.....
new MiniCssExtractPlugin({ //可以不配置,可以指定打包输出css的文件名
filename:'[name].css'
})
]
index.html中的代码:可以看到css是以link方式引入的
7.我们接下来处理图片,字体等静态资源,需要的loader如下:file-loader,url-loader
npm i file-loader@6.2.0 url-loader@4.1.1 -D
使用file-loader处理图片的:在src下新建assets文件夹,再新建images文件夹:src/assets/images/lufei.jpeg
index.js文件中引入图片并且挂载,代码如下:
console.log('我是taotao')
// 引入图片资源
import imgurl from './assets/images/lufei.jpeg'
// 创建img节点
const img=new Image()
// 挂载图片资源
img.src=imgurl
// 将img节点挂载到body上
document.body.appendChild(img)
webpack.config.js中配置file-loader
{
test:/\.(png|jpe?g|gif)$/i, //匹配图片格式的文件
use:[
{
loader:'file-loader', //返回的是文件的路径
options:{
name:"[name].[hash:8].[ext]", //输出的文件名 hash:8就是随机生成hash值
outputPath:"images" //配置输出后的文件所放的文件夹的地方 dist/images/lufei.jpeg
}
}
]
}
打包后输出的html格式如下:图片也在页面上显示出来了
使用url-loader处理图片:url-loader 返回的是文件的base64编码
注意点:url-loader内部封装了file-loader。即使用url-loader时,只需要安装url-loader即可,不需要安装file-loader。如果需要使用file-loader,url-loader会自己调用的
index.js文件的代码如下:
console.log('我是taotao')
// 引入图片资源
import imgurl from './assets/images/lufei.jpeg'
// 控制台打印引入的图片,查看url-loader将图片转化的结果
console.log(imgurl)
// 创建img节点
const img=new Image()
// 挂载图片资源
img.src=imgurl
// 将img节点挂载到body上
document.body.appendChild(img)
webpack.config.js的配置如下:
{
test:/\.(png|jpe?g|gif)$/i, //匹配图片格式的文件
use:[
{
loader:'url-loader',
options:{
name:"[name].[hash:8].[ext]", //输出的文件名 hash:8就是随机生成hash值
outputPath:"images", //配置输出后的文件所放的文件夹的地方 dist/images/lufei.jpeg
limit:102400 //限制图片的大小,如果小于这个值就使用url-loader转化为base64格式,如果是大于这个值就会使用file-loader直接返回文件路径
}
}
]
}
引入的图片大小是80多kb,为了实现可以转化为base64的,我把上面limit设置成100kb,可以看下控制台打印的结果如下:打印出了base64的格式
注意点:
使用 base64 来加载图片也是有两面性的:
优点:节省请求,提高页面性能
缺点:增大本地文件大小,降低加载性能
项目中我们要根据实际情况,小的图片使用url-loader,大的图片还是使用file-loader吧
8.babel
webpack只能处理部分的javascript高级语法,有一些高级语法的新特性,webpack处理不了,只
通过Babel,可以帮我们将高级语法转化为低级语法再交给webpack,安装相应的babel
npm i babel-loader@8.2.5 @babel/core@7.19.6 @babel/preset-env@7.19.4 -D
{
test:/\.js$/i, //匹配.js结尾的文件
loader:'babel-loader', 使用babel-loader转化
exclude:/node_modules/ //排除掉node_modules中的文件
},
根目录新建.babelrc文件来配置babel-loader才会生效,代码如下:
{
"presets": ["@babel/preset-env"]
}
src/index.js 代码如下:
const arr=[1,2,3]
arr.map(item=>{
return item+1
})
终端执行npm run build,会发现bundle.js中const 已经转化为var 但是map并没有转化;
使用了@abbel/preset-env后 标准引入的语法:箭头函数,let,const等是可以转换的
但是引入的全局变量,部分原生对象新增的原型链上的方法不可以转化 例如:promise.symbol,set,map等
@babel/polyfill插件来帮忙,配套的还有core-js
注意的点是:@babel/polyfill是全局变量的方式注入,开发项目使一般是没有影响的 但是当开发类库,UI组件时,可能会造成全局变量的污染
npm i @babel/polyfill@7.12.1 core-js@3.25.5 -D
.babelrc文件的代码改为如下:
{
"presets":[
["@babel/preset-env",{
"useBuiltIns": "usage", //三个选项值 entry全部引入 false不引入 usage按需引入所需的babel处理插件内容
// 还需配置core-js,不然会打包会提示,默认是corejs2,我们需要corejs3
// 因为新的特性现在都会放到corejs3中
"corejs":3
}]
]
}
我们还可以使用 @babel/plugin-transform-runtime来代替@babel/ployfill,以闭包的方式注入,保证全局环境不被污染 这个也是有配套的@babel/runtime-corejs3
npm i @babel/plugin-transform-runtime@7.19.6 @babel/runtime-corejs@7.19.6 -D
.babelrc文件的代码改为如下:
{
"plugins":[
[
"@babel/plugin-transform-runtime",
{
"corejs":3
}
]
]
}
9.sourcemap:可以让我们在打包文件下查看错误的代码位置
mode:'development',
//开发环境一般配置cheap-module-eval-source-map,可以查看源代码
//生产环境,我们不希望源代码被查看,可以配置none,或者cheap-module-source-map
devtool:'cheap-module-eval-source-map',
entry:{
index:path.resolve(__dirname,'./src/index.js'),
// demo:path.resolve(__dirname,'./src/demo.js')
},
index.js代码如下:
import './assets/css/index.less'
console.log(qqq) //打印一个不被定义的变量,肯定是错的,我们打包后看下:
const arr=[1,2,3]
arr.map(item=>{
return item+1
})
启动服务npm run dev,打开页面控制台会有报错,并指出在多少行在js文件的第2行
10.HMR 热更新 hot module replacement
配置热更新有四步如下:
使用webpack-dev-server作为服务器启动
devServer配置 hot:true
plugins hotModuleReplacementPLugin
js模块中增加module.hot.acceput增加hmr代码
list.js文件代码:
export const list=()=>{
console.log('我是list111')
}
index.js文件代码:
import {list} from './list'
alert('111111')
//配置热更新的代码
if(module.hot){
module.hot.accept('./list',()=>{
console.log('list模板更新了')
list()
});
module.hot.decline('./list') //关闭热更新
}
配置webpack.config.js
....
const Webpack=require('webpack')
module.exports={
.....
plugins:[
new Webpack.HotModuleReplacementPlugin()
],
devServer:{
contentBase:path.join(__dirname,'dist'),
port:9000, 启动服务的端口号
hot:true 启动热更新
}
}
npm run dev 启动服务,
修改list.js文件的代码后保存后,发现alert(‘111111’)并不会弹出,说明热更新配置好了
以上总的webpack.config.js配置文件的代码如下:
const path=require('path')
const HtmlWebapckPlugin=require('html-webpack-plugin')
const {CleanWebpackPlugin}=require('clean-webpack-plugin')
const MiniCssExtractPlugin=require('mini-css-extract-plugin')
const Webpack=require('webpack')
module.exports={
mode:'development', //开发环境
//开发环境cheap-module-eval-source-map,生产环境cheap-module-source-map或者none
devtool:'cheap-module-eval-source-map',
entry:{
index:path.resolve(__dirname,'./src/index.js'),
// demo:path.resolve(__dirname,'./src/demo.js') //多入口
},
output:{
filename:'[name].[hash:8].js',
path:path.resolve(__dirname,'dist')
},
module:{
rules:[
{
test:/\.js$/i,
loader:'babel-loader',
exclude:/node_modules/
},
{
test:/\.css$/, //匹配css文件
use:[ //直接使用loader,垂直方向写执行的顺序是从下到上; ['style-loader','css-loader','postcss-loader']-->从右往左执行
MiniCssExtractPlugin.loader,
'css-loader',
{ //配置postcss-loader有两种方式,方式一全部在webapck.config.js中配置,如下:
loader:"postcss-loader",
options:{
plugins:[require('autoprefixer')]
}
}
]
},
{
test:/\.less$/,
use:[ MiniCssExtractPlugin.loader,'css-loader','less-loader','postcss-loader']
},
{
test:/\.scss$/,
use:['style-loader','css-loader','sass-loader','postcss-loader']
},
// 处理图片的
{
test:/\.(png|jpe?g|gif)$/i, //匹配图片格式的文件
use:[
{
loader:'url-loader',
options:{
name:"[name].[hash:8].[ext]", //输出的文件名 hash:8就是随机生成hash值
outputPath:"images", //配置输出后的文件所放的文件夹的地方 dist/images/lufei.jpeg
limit:10240 //限制图片的大小,如果小于这个值就使用url-loader转化为base64格式,如果是大于这个值就会使用file-loader直接返回文件路径
}
}
]
}
]
},
plugins:[
new HtmlWebapckPlugin({
// 模板html的位置,如果不配置这一项,也会生成一个html文件,但是内容是空的;
// 所以项目中一定会配置这一项
template:"./src/index.html",
filename:'index.html',
chunks:['index'] //与入口文件写的模块名要一样
}),
// new HtmlWebapckPlugin({
// template:"./src/demo.html",
// filename:'demo.html',
// chunks:['demo']
// }),
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({ //可以不配置,可以指定打包输出css的文件名
filename:'[name].css'
}),
new Webpack.HotModuleReplacementPlugin()
],
devServer:{
contentBase:path.join(__dirname,'dist'),
port:9000,
hot:true
}
}
相关的配置文件代码如下:
.babelrc文件:
安装相应的插件二选一:
//plugins方式
{
"plugins":[
[
"@babel/plugin-transform-runtime",
{
"corejs":3
}
]
]
}
或者:presets方式
{
"presets":[
["@babel/preset-env",{
"useBuiltIns": "usage",
"corejs":3
}]
]
}
postcss.config.js文件代码:
module.exports={
plugins:[
require('autoprefixer')
]
}
记录自己的学习,有不对的地方还望大佬指出,谢谢。加油,学习前端每一天!!!