webpack4核心概念的学习(一)

简单记录自己学习的点点滴滴, 一定要有产出,才会进步,有错误的地方还望大佬指出

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')
    ]
}

记录自己的学习,有不对的地方还望大佬指出,谢谢。加油,学习前端每一天!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值