webpack

本文详细介绍了如何自定义Webpack的入口和出口,配置CSS和Less加载器,使用file-loader和url-loader优化图片,以及整合Babel、HMR和各种插件。此外,还包括了Webpack 5的asset/module/type打包方式、插件如clean-webpack-plugin和html-webpack-plugin的应用,以及关键配置项如mode和devServer的设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


###webpack全局安装

npm i webpack@5.37.1 webpack-cli@4.7.0 -g
webpack --v

###webpack 初使用(全局打包)

//文件目录
├── 项目目录
│   ├── src
│	│	├── js
│	│	│	├── math.js
│	│	│	└── format.j
│	│	└── index.js
├	└── index.html
// index.js
import { sum } from './js/math'
const { dateFormat } = require('./js/format')

console.log(sum(1, 2, 3, 4, 5), dateFormat('2021/10/22'));

// format.js
function dateFormat(str) {
  return new Date(str)
}
module.exports = {
  dateFormat
}
// math.js
export function sum(...args) {
  const arr = [...args]
  return arr.reduce((pre, curr) => pre + curr, 0)
}

在项目目录下, 终端输入webpack, 即生成dist文件, 将文件导入index.html中, 在server中打开
总结: 
	将不同模块化js文件通过 webpack 打包后生成的js文件能被browser识别

###局部安装webpack与配置局部打包命令

以下命令均在项目根目录下运行:

局部安装:
npm i webpack@5.37.1 webpack-cli@4.7.0 -D

配置局部打包命令
1: 生成项目包配置文件 package.json
	npm init -y

2: 在package.json中配置script
	"scripts": {
    "build": "webpack"
  }

3: 运行 npm run build
总结: 
	1: 为什么需要局部安装webpack
	答: 每个脚手架(vue react) 都是用不同版本的webpack作为打包工具, 如果使用全局webpack可能会产生版本兼容性问题
	
	2: 为什么需要配置局部打包命令, 直接使用webpack不行吗?
	   答: 直接使用webpack实际上使用的还是电脑全局安装的webpack进行打包, 而局部打包命令少见或繁琐(npx webpack), 所以需要配置一个通俗的打包命令

自定义webpack打包的入口与出口

// webpack 默认从项目目录下的src文件下的index.js开始打包, 并打包至项目目录下dist/main.js (自动生成)
//若想指定打包的入口(entry) 和 出口(output) 则需要在项目目录下新建并配置webpack.config.js文件


const { join } = require('path')

module.exports = {
  entry: "./src/main.js", //指定入口文件名为main.js
  output: {
    path: join(__dirname, "./build"), //语法要求出口目录必须为绝对路径, 这里采用node.js语法拼接
    filename: 'js/bundle.js' //指定打包后的文件名
  }
}

css-loader的安装与配置

// webpack只内置了对js文件的打包, 如果想打包其他资源, 需要安装基于webpack的插件

// css-loader的安装 

// 1: 项目目录下 运行该命令
 npm i css-loader
 
 // 2:在webpack.config.js中配置模块规则
module.exports  = {
	module: {
        rules:[  //规则有很多, 所以用数组
            { test:'/\.css$/', use:[ 'css-loader' ] } //每个正则对应一个文件, 可能不仅需要一个loader,所以用正则  
        ]
    }
} 

style-loader的安装, 引入style标签

// 安装好cssloader后, css样式并不出来, 原因是 css-loader只负责解析css模板, 样式生效还需要引入外联css文件或嵌入style标签// style.loader可以将css-loader解析出来的css以style标签的形式嵌入html找那个步骤一: 安装style-loader	npm i style-loader -D步骤二: 配置 webpack.config.jsmodule.exports = {  module: {    rules: [      { test: /\.css$/, use: ["style-loader", "css-loader"] }     ]						//use内的顺序有严格要求, 对cssloader的加载顺序, 以数组内从后向前加载. 应该是先解析css,再挂载  }							//style标签, 所以先写style-loader 后写css-loader}

less 与 less-loader的安装与配置, 解析less文件

// 想解析less文件需要先安装less, 该插件提供less compile的能力 , 再安装less-loader 这个loader提供了模块化的能力// 安装步骤1: npm i less less-loader -D2:配置webpack.config.jsonmodule.exports = {  module: {    rules: [      { test: /\.less$/, use: ["style-loader", "css-loader", "less-loader"] } //注意顺序    ]  }}

###postcss-loader 与 其插件 postcss-preset-env

postcss-loader是一个转换css的加载器, postcss-preset-env可以为css自动添加浏览器兼容前缀, 识别一些新的css语法, 并将其转换成兼容的css语法, 比如 color:#12345678 ,传统的16进制只能容纳六位, 新特性可以增加到8, 最后两位代表alpha(透明度), postcss-preset-env可以将其转换成rgba的形式// 写法一: 插件和loader配置在一起module.exports = {  module: {    rules: [{        test: /\.css$/,        use: [          "style-loader",          "css-loader",          {            loader: "postcss-loader",            options: {              postcssOptions: {                plugins: [require("postcss-preset-env")]              }            }          }        ]      }    ]  }}//写法二 :postcss-loader配置与webpack配置分离, webpack.config.js中只配置postcss,插件配置写在postcss.config.js中//webpack.config.js中的配置module.exports = {  module: {    rules: [{        test: /\.css$/,        use: [          "style-loader",          "css-loader",          "postcss-loader"        ]      }    ]  }}//postcss.config.js中的配置module.exports = {  plugins: [    require('postcss-preset-env')  ]}

file-loader 与 打包图片

第一步:
	安装: npm i file-loader -D
第二步: 
	配置webpack.config.js

module.exports = {
  module: {
    rules: [
      { test: /\.(png|svg|jpe?g|gif)/, use: ['file-loader '] }
    ]
  }
}
记录:	老师安装file-loader后打包图片, 就会在指定的出口目录生成依赖的图片, 但我生成了两张 

###file-loader 与 src引入图片

// 通过src 修改图片img图片的路径时应该使用这种方式

import imgSrc from "../img/xxx.png"  //直接导入图片, 并将图片赋值给img元素的src

const imgEl = document.createElement('img')
imgEl.src = imgSrc

###file-loader的配置项 修改图片输出的目录和输出图片名称

// webpack.config.js配置项
module.exports = {
    module:{
        rules:[
            {
                test:/\.(jpe?g|png|gif)/,
                use:{
                    loader:"fileloader",
                    options:{
                        outputPath:'image' // 输出的图片模块将在指定出口目录下,生成一个image目录存放图片
                        name:'[name]_[hash:6].[ext]' // 内置占位符[name] 图片的原名称 [hash:6] 截取6位的hash值
                    //语法糖 name:'image/[name]_[hash:6].[ext]'
                    }								//防止文件冲突, [ext] extense的缩写, 后缀的意思,取元文件的后缀	
                }
            }
        ]
    }
}

url-loader 与 base64编码

// url-loader 与 file-lorder用法基本一致, url-loader的优势在于, 能将小图片以base64的编码格式进行编码, 嵌入js或css文件中, 伴随js, css文件一起下载到客户端, 从而减少了因图片的网络请求, 是一种优化性能的手段

// webpack.config.js 配置
module.exports = {
    module:{
        rules:[
            {
                test:/\.(png|jpe?g|gif|svg)/,
                use:{
                    loader:"url-loader",
                    options:{
                        outputPath:'image',
                        name:'[name]_[hash].[ext]',
                        limit:100 * 1024  // limit 用以规定低于多少大小的文件编码成base64, 单位是比特, 这里指定100kb
                    }					//以下被编码, 过大的图片不适合编码成base64
                }
            }
        ]
    }
}

webpack5对图片的打包方式: asset module type

// 在webpack5中已经不推荐使用 url-loader 或者 file-loader对图片进行打包, 取而代之的是内置的asset module type 资源模型类型, 配置方式如下

module.exports = {
    module:{
        rules:[
            {
                test:/\.(png|jpe?g|gif)/,
                type:'asset', // 不再使用use配置项, 使用type
                generator:{ //生成器
                    filename:'img/[name]_[hash:6][ext]' //asset中的[ext]包括了.
                },
                parser:{ //解析器 
                    maxSize:100 * 1024
                }
            }
        ]
    }
}

打包字体图标

// 通过file-loader打包module.exports = {    module:{        rules:[            {                test:/\.(eot|ttf|woff|svg)$/,                use:{                    loader:"file-loader",                    options:{                        outputPath:"fonts",                        name:"[name]_[hash].[ext]"                    }                }            }        ]    }}//通过 asset/resource打包, 等同于file-loadermodule.exports = {    module:{        rules:[            {                test:/\.(eot|ttf|woff|svg)$/,                type:'asset/resource',                generator:{                    filename:'fonts/[name]_[hash:6][ext]' //再次强调, asset中的[ext]前面不用加.                }            }        ]    }}

##插件

clean-webpack-plugin 一个在打包时, 自动清理原先打包目录的插件

// 第一步: 安装插件 npm i clean-webpack-plugin -D// 第二步: 配置webpack.config.jsconst { CleanWebpackPlugin } = require('clean-webpack-plugin')module.exports = {    plugins:[        new CleanWebpackPlugin()    ]}
:	`大多数!`插件都是暴露一个类(构造函数), 使用方式即为new 

html-webpack-plugin 打包index.html 以及 仿vue自定义html模板

// html-webpack-plugin 为webpack内置的插件, 可以自动生成一个index.html 并自动导入对应的依赖// vue 的index目录示意简图├──项目目录	├── node_nodules    ├── public    │	├── index.html	│	└── favicon.icon    .....<!-- vue3 index.html 模板 --><!DOCTYPE html><html lang="cn-ZH">  <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">    <link rel="icon" href="<%= BASE_URL %>favicon.ico">    <title><%= htmlWebpackPlugin.options.title %></title>  </head>  <body>    <noscript>      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without 			  JavaScript enabled. Please enable it to continue.</strong>    </noscript>    <div id="app"></div>    <!-- built files will be auto injected -->  </body></html>
其中 <%= BASE_URL %> 在webpack内置插件DefinePlugin中定义, title读取的是HtmlWebpackPlugin插件配置项的title内容
// 配置DefinePlugin 和 HtmlWebpackPlugin//第一步:下载依赖插件  npm i html-webpack-plugin -D//第二步: webpack.config.js中配置const HtmlWebpackPlugin = require('html-webpack-plugin')const { DefinePlugin } = require('webpack')module.exports = {    plugins:[        new HtmlWebpackPlugin({            title:'想出现在index.html title标签的内容',            // filename:'index.html',     //在filename中可以指定输出的文件目录和文件名, 默认生成在根目录下index.html            template:'./public/index.html'        }),        new DefinePlugin({            BASE_URL:"'./'"       //注意! 这里只写一对引号引用的是上下文的变量, 使用两对引号引用的是字符串        })    ]}

copy-webpack-plugin 还原vue 对 favicon.icon的打包复制配置

//实现目标: 对public的目录下所有文件(除被html-webpack-plugin管理的index.html文件) 在打包时进行copy// 第一步:	npm i copy-webpack-plugin -D//第二步: 配置webpack.config.jsconst CopyWebpackPlugin = require('copy-webpack-plugin')module.exports = {    plugins:[			//目录下除了index.html必须有文件才能用, 否则会报错        new CopyWebpackPlugin({            patterns:[             // 匹配规则(模式)可能有很多, 所以是数组                {                    from:'public',                    to:'./',                    globOptions:{       //是 glob 不是 global                        ignore:['**/index.html']                    }                }            ]        })    ]}	

mode配置项

// mode配置项有两个值 "developement","production" 当选择dev模式时, 再指定devtool为 "source-map" 即能与入口js文件同时生成一个map映射文件, 当项目跑起来后, 如果有错误, 方便错误信息的定位,调试.module.exports = {    mode: 'development',    devtool:'source-map'}

Babel

什么是babel : 一个独立的库,本质上是编译器, 将js从es6转成es5, ts转成js..等, 可以脱离webpack使用, 而webpack也集成了babel.			babel自身也依赖了许多插件, 来对不同的语法进行转换(比如箭头函数转普通函数即是一个插件), 一般使用babel的预设插件能			达到预期的转换效果
// 独立使用 babel// 使用步骤: //1:安装babelnpm i @babel/core @babel/cli -D//2:安装babel预设插件npm i @babel/preset-env -D//3:局部调用babelnpx babel demo.js --out--dir dist --presets=@babel/preset-env  //将当前目录的某js文件使用预设插件编译到指定文件夹或者npx babel demo.js --out-file test.js --presets=@babel/preset-env 									//将当前目录的某js文件使用预设插件编译到当前目录,指定文件名------------------------------------------------------------------------------------------------------------// 编译前的文件const demo = 1;const handler = () => console.log('this is a demo')//编译后的文件"use strict";var demo = 1;var handler = function handler() {  return console.log('this is a demo');}

Babel编译大致原理

源代码 --> 词法分析生成数组 ---> 语法分析生成AST树 ---> 遍历AST树并运用插件进行编译 ---> 生成新的AST语法树 ---> 生成目标代码

babel-loader 链接babel与模块化的loader

// 第一步: 安装npm i babel-loader @babel/core @babel/preset-env -D//第二步配置 webpack.config.jsmodule.exports = {    module:{        rules:[            {                test:/\.js$/,                use:{                    loader:'babel-loader',                    options:{                        presets:[                            '@babel/preset-env'                        ]                    }                }            }        ]    }}// 或者单独配置 babel.config.jsmodule.exports = {    presets:[        "@babel/preset-env"    ]}

vue-loader 打包单文件组件(.vue)

// vue-loader依赖@vue/compiler-sfc, 并且vue-loader的使用需要配置插件详情如下// sfc:  single file components 单文件组件编译器// 步骤一: 安装npm i vue@nextnpm i vue-loader@next @vue/compiler-sfc -D// 配置webpack.config.jsimport { VueLoaderPlugin } from 'vue-loader/dist/index'import { DefinePlugin } from 'webpack'module.exports = {    module:{        rules:[            {                test:/\.vue/,                loader:'vue-loader'            }        ]    },    plugins:[        new VueLoaderPlugin(),        new DefinePlugin({            __VUE_OPTIONS_API__:true, // 是否在vue3中兼容vue2api            __VUE_PROD_DEVTOOLS__:false  //是否关闭开发时提示        })    ]}

自动编译 watch

// 当每次修改代码, 都要重新编译, 非常繁琐, 可以配置watch, 来达到一次编译(npm run build)后, 每次修改代码自动编译// 方式一: 在package.json中配置{    "scripts":{        "build":"webpack --watch"    }}// 方式二: 在webpack.config.js中配置module.exports = {    watch:true}

webpack-dev-server

// 什么是 webpack-dev-server?webpack-dev-server 可以启动一台基于express框架编写的服务器, 将当前资源进行打包, 自动部署到服务器当中, 并且每次修改代码, 不需要重新打包, server会自动打包部署, webpack-dev-server的优势还在于, 并不是将资源打包到磁盘当中, 而是内存当中// webpack-dev-server的安装与部署// 第一步:安装npm i webpack-dev-server -D   //注意: 需要搭配 webpack5和webpack-cli 4.9以上// 第二步 :配置项目包管理文件 package.json{    scripts:{        "build": "webpack",        "serve": "webpack serve"        }}// 第三步: 运行webpack-dev-servernpm run serve

配置 webpack-dev-server

// contentBase 选项可以在 资源并不在服务器时, 客户端又向服务器索要了资源, 指定一个目录, 让服务器从这里拿资源返回给客户端// 在webpack.config.json中配置:module.export = {    devServer:{        contentBase:'./public'  //指定public文件夹为资源替代目录    }}

HMR

// 什么是HMR : hot module replace 模块热替换, 在webpack中每一个文件(css,img,js,vue..) 被视为一个模块, 当一个模块中内容    发生改变时候, 整个页面都会刷新, 有时候我们不希望这么做, HMR的功能即是让一个模块的内容被修改时, 只修改页面中该模块的内容, 其    他的模块内容并不改变// webpack-dev-server提供了HMR的能力, 配置如下// 1: 指定需要配置HMR的模块, 如为demo.js配置热替换main.js :import somthing from './demo.js'module.hot && module.hot.accept('./demo.js', ()=>{  // 回调函数不是必须的, 当热替换时被调用    console.log('demo.js进行了HMR')})// 2: 在webpack.config.js中配置module.exports = {    target:'web',    devServer:{        hot:true    }}

HMR 原理

开启HMR后, 启动webpack-dev-server, 实际上开启了两个服务器, 一个是基于express写的服务器, 用于响应http请求, 一个是soket长链接服务器, 该服务器可以与客户端之间建立长链接, 当服务器数据被修改时, 主动向浏览器发送修改的数据, 浏览器拿到数据后做出相应模块的修改

webpack-dev-server 其他配置项

// 在webpack.config.js中module.exports = {    devServer:{        host:'127.0.0.1',  //指定域名/ip        port:'8090',	 //指定端口号	        open:true,		//是否自动打开默认浏览器, 默认为false        compress:true  //是否以gzip的形式向客户端发送数据,默认为false 一般不开启, 自己玩没意义    }					//开启后查看浏览器接受的js文件的响应头, 发现Content-Encoding:gzip}

webpack-dev-server 配置网络请求代理

为什么要配置代理?: 当打包好的资源发送到客户端, 其中的js文件中有网络请求, 并且跨域了, 浏览器就会受到浏览器同源策略的影响拿不到数据, 但同源策略是浏览器的, 服务器之间的通信不受到同源策略的影响, 此时, 浏览器只需要委托webpack-dev-server向目的地发送请求, 拿到数据, 再返回给浏览器, 客户端就能顺利的拿到数据// 配置示例:module.export = {	devServer:{        // proxy: "http://127.0.0.1:9999"                   只能代理一个服务器, 所有的请求都被发送到这个服务器        "/api":{            target:"http://127.0.0.1:9999",            pathRewrite:{ "^apt":"" },            changeOrange:true        },        "/list":{            target:"http://127.0.0.1:9999",            pathRewrite:{ "^/list":"" },            changeOrange:true        },    }}

resolve 配置项

// resolve 用于配置weback打包项目时, 如何解析路径的, extensions指定解析的扩展名, 配置上.vue后, 引入组件不需要加.vue扩展   名,alias可以为一个路径起别名, 导入时可以使用别名来代替路径const { join } = require('path')module.exports = {    resolve:{        extensions:['.js','.json','.vue','.ts'],        alias:{            '@':join(__dirname, './src')        }    }}

拆分webpack.config.js

文件目录├── config│	├── webpack.comm.config.js│	├── webpack.dev.config.js├─	└── webpack.prod.config.js// package.json 文件配置{	"scripts":{        "serve":"webpack serve --config ./config/webpack.dev.config.js"        "build":"webpack --config ./config/webpack.prod.config.js"    }}// webpack.comm.config.js文件module.exports = {	target:'web',    entry:"./src/index.js",    output:{        filename:'js/bundle.js'    },    resolve:{       extensions:[],       alias:[]    },    module:{        rules:[]    },    plugins:[]}// webpack.dev.config.js 文件const const { merge } = require('webpack-merge')const comm = require('./webpack.comm.config')module.exports = merge(comm, {  mode: 'development',  devtool: 'source-map',  devServer: {}})// weback.prod.config.jsconst { CleanWebpackPlugin } = require("clean-webpack-plugin")const CopyWebpackPlugin = require("copy-webpack-plugin");const { merge } = require('webpack-merge')const comm = require('./webpack.comm.config')module.exports = merge(comm,{  mode: 'production',  plugins: [    new CleanWebpackPlugin(),    new CopyWebpackPlugin(),  ]})

publicPath 打包后直接打开index.html

module.exports = {	publciPath:'./'}// 打包后的文件不部署在服务器上, 直接点开是有问题的, 主要是index.html引用文件路径, 如果双击点开, 使用file协议读取文件是读不到

vue-cli的安装与更新

// 全局安装vue-clinpm i @vue/cli -g// 更新 vue-clinpm updata @vue/cli -g// 创建脚手架vue create 项目名称
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值