紧跟前文: WebPack5.0 快速入门 简单的了解了:WebPack的使用,接下来康康项目中的管理吧;
经过上述链接学习: 我们已经掌握了WebPack基本操作,优化之前的Demo:完善login登录页面,优化目录结构:
为什么需要搭建开发环境😗❓ 经过上述,我们已经满足了模块打包的使用,
同时发现一个严重问题: 每次改动代码,都要重新打包,很麻烦❗❗ 那么如何解决呢❓
Webpack-dev-server 是一个基于 Node.js 构建的轻量级开发服务器:
专为 Webpack 打包生成的资源文件提供服务: 它在本地开发环境中启动一个实时的 Web 服务器,极大地提高了开发效率;
NPM安装软件包:webpack-dev-server 软件包到当前项目;
npm i webpack-dev-server --save-dev
webpack-dev-server:仅用于开发环境,请 不要 在生产环境中使用它们!
//省略...
module.exports = {
mode: 'development', //开发模式
devServer: { //Webpack-dev-server配置
hot: true, //启用热模块替换功能
port: 9000, //指定开发服务器的端口号
compress: true, //启用 Gzip 压缩,提高传输效率
static: './dist', //指定静态文件的目录,./dist 目录下的文件将被作为静态资源提供服务;
},
//省略...
}
mode
配置选项用于指定构建的模式 提供了三种模式: development
开发模式)、production
生产模式)、`none无模式)
devServer:{ Webpack 中的配置选项 }
: 用于配置 Webpack-dev-server 的行为,提供本地实时重载、热部署、功能;package.json
中配置脚本:webpack-dev-server
支持: 命令行设置配置,且优先级高于配置文件中的,推荐用命令行设置;
"scripts": {
"build": "webpack",
"dev": "webpack serve --port 5400 --mode=development --open"
},
"dev": "webpack serve --port 5400 --mode=development --open"
运行启动开发模式 自动打开浏览器 端口5400NPM快速运行命令: npm run dev
webpack–dev-server:其原理是 通过在内存中创建虚拟文件系统来提供开发服务器功能;
监听内存中的./dist
目录,启动一个基于 Node.js 的服务器通常是 Express 服务器)
而Express服务器默认启动的是: public/index.html
页面,
因为:此案例没有index.html
,所以打开一个空页面: 可以通过配置定义默认开启页面;
定义一个index.html
页面,并默认跳转:login.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>
<script>
// webpack-dev-server 的 Web 服务,自动跳转到我们规定的首页
location.href = '/login/index.html'
</script>
</body>
</html>
添加 webpack.config.js 模板映射配置: 实际开发过程中结合项目结构目录进行配置;
//WebPack配置: 省略...
module.exports = {
////省略...
plugins: [ //插件: 给Webpack提供更多功能;
new HtmlWebpackPlugin({
template: path.resolve(__dirname,'public/index.html'), // 模板文件
filename: path.resolve(__dirname,'dist/index.html'), // 输出文件
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname,'public/login.html'), // 模板文件
filename: path.resolve(__dirname,'dist/login/login.html'), // 输出文件
}),
new MiniCssExtractPlugin({
filename: './[name]/index.css' // 输出css文件目录
}),
],
}
模式名称 | 模式名字 | 特点 | 场景 |
---|---|---|---|
开发模式 | development | 调试代码,实时加载,模块热替换等 | 本地开发 |
生产模式 | production | 压缩代码,资源优化,更轻量等 | 打包上线 |
如何设置影响 Webpack呢?
module.exports = {
//mode: 'development'
mode: 'production'
}
production:生产模式 压缩代码,资源优化,更轻量等;
development:开发模式 非压缩代码,调试代码,实时加载,模块热替换等;
"scripts": {
"build": "webpack --mode=production",
"dev": "webpack --mode=development",
},
在大型项目中,经常出现的需求,根据不同的环境而需要不同的配置: 如:
style-loader加载器
MiniCssExtractPlugin.loader加载器
如此:不同环境需要不同的配置如何,轻松便捷的实现环境切换呢?
webpack.config.js配置导出函数::局限性大,只接受 2 种模式: 此处不详细介绍🔈
//...省略部分代码,
//将 webpack.config.js 配置为导出一个函数,根据 mode 参数动态调整配置
module.exports = (env, argv) => {
if (argv.mode === 'development') { config.devtool = 'source-map'; }
if (argv.mode === 'production') { /** .... */ }
return config;
};
cross-env
是一个用于跨平台设置环境变量的工具,特别适用于在 Windows 和 Unix 系统之间进行兼容
通过 cross-env
你可以在命令中设置变量,并在 Webpack 配置中使用这些变量来区分不同的环境:
安装 cross-env
: npm install --save-dev cross-env
配置 package.json
: 在 package.json
中添加脚本,使用 cross-env
设置环境变量
"scripts": {
//....省略部分代码;
"build3": "cross-env NODE_ENV=production webpack --mode=production",
"dev3": "cross-env NODE_ENV=development webpack --mode=development"
},
配置 webpack.config.js
: 将 webpack.config.js
配置中根据 NODE_ENV
环境变量动态调整配置;
//为方便管理引入Node 文件资源管理模块;
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
//WebPack配置:
module.exports = {
//...省略部分代码,
module:{ //加载器:
rules: [ //规则列表:
//优化-提取 css 代码
{
test: /\.css$/i, //匹配所有的 .css 文件
use: [
process.env.NODE_ENV === 'development'?'style-loader':MiniCssExtractPlugin.loader
,"css-loader" ],
},
//打包Less代码
{
test: /\.less$/i, //匹配所有的 .less 文件
use: [process.env.NODE_ENV === 'development'?'style-loader':MiniCssExtractPlugin.loader
,"css-loader","less-loader"],
},
],
},
}
process.env.NODE_ENV === 'development'?'style-loader':MiniCssExtractPlugin.loader
使用:三元运算符,根据命令行参数判断,而切换不同的加载器:
开发模式使用:style-loader
、生产模式使用:MiniCssExtractPlugin.loader
加载器;
🆗,上述我们通过命令行设置环境变量,实现开发\生产环境配置的切换:
但是: cross-env 设置的只支持Node.Js
环境生效,前端的代码无法访问 process.env.NODE_ENV
那么,开发者如何在前端代码中判断开发\生产环境呢😗❓:DefinePlugin插件,支持定义、获取配置中的值;
DefinePlugin
是 Webpack 提供的一个插件,用于在:编译时定义全局常量
这些常量可以在代码中使用: 并在编译时被替换为指定的值,并支持表达式赋值;
Webpack.config.js
中定义常量,值: process.env.NODE_ENV
即可轻松判断运行开发、生产环境;//引入webpack包其内置插件: DefinePlugin...
const webpack = require('webpack');
//WebPack配置:
module.exports = {
//插件: 给Webpack提供更多功能;
plugins: [
//...省略部分代码,
//使用DefinePlugin插件定义: 程序全局变量;
new webpack.DefinePlugin({
//全局变量定义规则:
//"字符串":"字符串,因为: 插件底层会直接替换文,所以使用JSON.stringify来确保正确的字符串格式;"
'MODEI': JSON.stringify(process.env.NODE_ENV),
'MODEII': 'process.env.NODE_ENV',
'VERSION': '版本1.0.0',
})
],
}
注意:定义常量值需要使用JSON.stringify
转换,如果需要进行环境判断还需要结合:cross-env参数
启动命令行: cross-env NODE_ENV=production webpack --mode=production
\ --mode=development
前端项目中,开发模式下打印语句生效,生产模式下打印语句失效:
//1.webpack 中配置 DefinePlugin 插件
//2.前端代码判断开发\生产环境,给console.log函数对象重新赋值,生产环境则打印语句失效;
if (process.env.NODE_ENV === 'production') {
console.log = function() {}
}
console.log('开发模式下好用,生产模式下失效')
前端项目中,Axios开发环境、生产环境可能使用的请求IP不同,也可以使用其进行管理:
webpack.config.JS: DefinePlugin中定义不同环境的axios请求;
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = (env, argv) => {
const isDevelopment = process.env.NODE_ENV === 'development';
const isProduction = process.env.NODE_ENV === 'production';
return {
mode: isDevelopment ? 'development' : 'production',
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'API_BASE_URL': JSON.stringify(isProduction ?
'https://api.example.com' : 'http://localhost:3000'),
}),
],
};
};
请求.JS: axios根据不同的环境,请求不同的IP路径接口;
import axios from 'axios';
const apiClient = axios.create({
baseURL: API_BASE_URL,
headers: {'Content-Type': 'application/json', },
});
因为:WebPack打包之后,代码被压缩和混淆:如果发送错误无法正确定位源代码位置(行数和列数:
JS文件
是被压缩管理的,浏览器定位错误位置:24行;JS
20行错误: 虽然此处误差还可以接受,如果项目变大那么则非常不方便定位异常;Source Map 会将编译后的代码映射回原始源代码: 这样你在调试时可以看到原始代码,而不是编译后的代码;
注意:Source Map 仅适用于开发环境,不要在生产环境使用(防止被轻易查看源码位置)
使用Source Map: 可以在 webpack.config.js
中配置 devtool
选项,常见的 devtool
选项有:
为了方便管理:WebPack.config.js 不同环境及其配置,可以将将整个配置定义在一个对象中:统一 module.exports=xxx
//为方便管理引入Node 文件资源管理模块;
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
//引入webpack包其内置插件: DefinePlugin...
const webpack = require('webpack');
//1.定义WebPack配置为一个对象 config = { 其中定义配置属性 };
const config = {
//...省略...部分配置代码;
}
//2.可以在其外部通过.xxx形式新增属性,也更方便判断处理;
//开发环境下使用 sourcemap 选项
if (process.env.NODE_ENV === 'development') {
config.devtool = 'inline-source-map'
}
//3.最后将对象统一赋值给 module.exports 暴漏出去;
module.exports = config;
const config = { 其中定义配置属性 }
设置 Webpack 如何设置路径别名,方便我们引入目标模块:
在 Webpack 中设置解析别名路径可以使代码更简洁,提升可读性和维护性,以下是如何配置别名路径的步骤:
/** indexJS中引入并使用 /utils/checkJS文件暴漏函数 */
//import { checkPhone, checkCode } from '../utils/check.js' 原路径;
import { checkPhone, checkCode } from '@/utils/check.js' //别名+路径;
//对于路径前缀特别长的代码编写过程实在是不方便管理和维护,如果中途需要切换路径使用: 路径别名,可以轻松方便的进行管理;
//...省略部分代码...
const config = {
//...省略部分代码...
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'别名': '别名映射的路径地址',
}
}
}
实际开发过程中:我们会使用很多的第三方库: 这导致在打包部署:dist部署文件夹
会非常的大;
如何才能,减少打包的大小呢?——>CDN: 在部署打包时候,三方依赖可以使用CDN进行配置;
什么是CDN: Content Delivery Network
全称:内容分发网络,是一组分布在不同地理位置的服务器群;
将三方依赖,使用远程私人、公司CDN服务器中访问,就可以极大的减轻本地的包大小,减轻服务器运行压力;
生产环境的第三方依赖使用CND进行管理,减轻服务器内存
开发环境因为是本地所以: 还是建议NPM使用本地的包,实际情况根据公司而定,部分公司其实用不上这个😓
广告: AXIOS学习📄🔗
NPM安装axios 依赖: npm install axios --save
使用三方axios包,登录页面打开查询北京的天气情况: 此处接口来源,中国气象局公共API;
import axios from 'axios'
/** 省略部分代码 */
/** 测试使用axios 查询南京的天气: */
axios.get('http://www.nmc.cn/rest/weather?stationid=CxOWZ&_=1721313627036')
.then(response => {
console.log(response.data);
console.log(response.data.data.real.warn.alert);
})
.catch(error => {
console.error(error);
});
BootCDN - Bootstrap 中文网开源项目免费 CDN 加速服务
如何根据生产环境,而使用CND依赖呢: webpack.config.js
中 externals外部扩展选项,防止某些 import 的包被打包)
//为方便管理引入Node 文件资源管理模块...省略
//WebPack配置:
const config = {
//...省略...部分代码
//入口 entry: path.resolve(__dirname, 'src/login/index.js'),
entry: {
'login': path.resolve(__dirname, 'src/login/index.js')
},
plugins: [ //插件: 给Webpack提供更多功能;
new HtmlWebpackPlugin({
template: path.resolve(__dirname,'public/login.html'), // 模板文件
filename: path.resolve(__dirname,'dist/login/login.html'), // 输出文件
//自定义属性,在html模板中 <%=htmlWebpackPlugin.options.useCdn%> 判断是否访问使用;
useCdn: process.env.NODE_ENV === 'production'
//指定引入打包后的JS模块和 entry 的 key 匹配
chunks: ['login']
}),
],
}
// 开发环境下使用 sourcemap 选项...省略
// 生产环境下使用相关配置
if (process.env.NODE_ENV === 'production') {
// 外部扩展(让 webpack 防止 import 的包被打包进来)
config.externals = {
// key:import from 语句后面的字符串
// value:留在原地的全局变量(最好和 cdn 在全局暴露的变量一致
'axios': 'axios'
}
}
module.exports = config;
在html模板中,通过自定义属性判断是否使用CND资源:
并通过在webpack.config.js
中配置管理了,html模板对应使用的.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">
<!-- <link href="../src/login/login.css" rel="stylesheet"> -->
<title>数据管理平台</title>
</head>
<body>
<div class="login-wrap">
<div class="title">头条</div>
<div>
<form class="login-form">
<div class="item">
<input type="text" class="form-control" name="mobile" placeholder="请输入手机号" value="">
</div>
<div class="item">
<input type="text" class="form-control" name="code" placeholder="默认验证码" value="">
</div>
<div class="item">
<button type="button" class="btn btn-primary btn">登 录</button>
</div>
</form>
</div>
</div>
<% if(htmlWebpackPlugin.options.useCdn){ %>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.6/axios.min.js"></script>
<% } %>
<!-- 个人觉得好鸡肋,还需要事先定义好JS引用位置; -->
<!-- <script src="../src/login/index.js"></script> -->
<!-- webpack.config.js plugins new HtmlWebpackPlugin({ chunks: 指定引入文件对应JS }) -->
</body>
</html>
启动命令: cross-env NODE_ENV=production webpack --mode=production
🆗,到此就完成了,查看d
ist
中代码: 可以清楚的看到体积变小了,且页面上Axios也是CND引用 还不影响最终效果
Webpack打包多页面应用是一种常见的需求,特别是在需要处理多个独立页面的项目中:
entry
和多个HTML模板HtmlWebpackPlugin
假设你的项目目录结构如下:
src/
├── pages/
│ ├── page1/
│ │ ├── app.js
│ │ ├── index.html
│ ├── page2/
│ │ ├── app.js
│ │ ├── index.html
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
page1: './src/pages/page1/app.js',
page2: './src/pages/page2/app.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name]/[name]-bundle.js',
},
plugins: [
new HtmlWebpackPlugin({
template: './src/pages/page1/index.html',
filename: 'page1.html',
chunks: ['page1'],
}),
new HtmlWebpackPlugin({
template: './src/pages/page2/index.html',
filename: 'page2.html',
chunks: ['page2'],
}),
],
};
entry
中配置多个入口,每个入口对应一个页面的主文件[name]
占位符生成不同页面的打包文件, 为每个页面配置一个HtmlWebpackPlugin实例,指定模板文件和包含的chunks
chunks: 指定引入打包后的JS模块和 entry 的 key 匹配
splitChunks
是 Webpack 提供的一个强大的功能,用于优化代码打包;
它的主要目的是将重复的模块代码分离到单独的文件中,以减少重复打包的内容,从而提高加载性能:
splitChunks
的配置项:
async
默认值,只对异步加载的模块进行拆分)、initial
对入口模块进行拆分) 、 all
对所有模块进行拆分)
cacheGroups
自定义 chunk
分组,设置 test
对模块进行过滤,符合条件的模块分配到相同的组module.exports = {
optimization: {
splitChunks: {
chunks: 'all', // 对所有的chunk进行拆分
minSize: 20000, // 拆分 chunk 的最小体积
minChunks: 1, // 需在一个模块中共享才进行拆分
maxAsyncRequests: 30, // 按需加载时的最大并行请求数
maxInitialRequests: 30, // 入口点的最大并行请求数
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
},
};
优化策略:
通过合理的拆包策略,可以显著提升应用程序的性能,代码分离通过将代码按需加载,减小初始下载量;
而打包分离将应用程序拆分成多个块,实现增量更新,减少不必要的下载;
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。