【webpack4系列】编写可维护的webpack构建配置(四)

文章目录

    • 构建配置包设计
    • 功能模块设计和目录结构设计
      • 功能模块设计
      • 目录结构设计
    • 使用ESLint规范构建脚本
    • 冒烟测试介绍和实际运用
      • 冒烟测试 (smoke testing)
      • 冒烟测试执行
      • 判断构建是否成功
      • 判断基本功能是否正常
    • 单元测试和测试覆盖率
      • 测试框架
      • 编写单元测试用例
      • 单元测试接入
      • 测试覆盖率
    • 持续集成和Travis CI
      • 持续集成的作用
      • Github 最流行的 CI
      • 接入 Travis CI
      • travis.yml 文件内容
    • 发布构建包到npm社区
    • Git 提交规范和changelog生成

构建配置包设计

构建配置管理的可选方案:

  • 通过多个配置文件管理不同环境的构建,webpack --config 参数进行控制
  • 将构建配置设计成一个库,比如:xxx-webpack
  • 抽成一个工具进行管理,比如:create-vue-app
  • 将所有的配置放在一个文件,通过 --env 参数控制分支选择

通过多个配置文件管理不同环境的 webpack 配置

  • 基础配置:webpack.base.js
  • 开发环境:webpack.dev.js
  • 生产环境:webpack.prod.js
  • SSR环境:webpack.ssr.js
  • ……

抽离成一个 npm 包统一管理

  • 规范:Git commit日志、README、ESLint 规范、Semver 规范
  • 质量:冒烟测试、单元测试、测试覆盖率和 CI

通过 webpack-merge 组合配置

const merge = require("webpack-merge")
// 省略其他代码
module.exports = merge(baseConfig, devConfig);

功能模块设计和目录结构设计

功能模块设计

构建包设计:

  • 基础配置:webpack.base.js
    • 资源解析
      • 解析ES6
      • 解析vue
      • 解析react
      • 解析css
      • 解析less
      • 解析scss
      • 解析图片
      • 解析字体
    • 样式增强
      • CSS前缀补齐
      • CSS px转成rem
    • 目录清理
    • 多页面打包
    • 命令行信息显示优化
    • 错误捕获和处理
    • CSS提取成一个单独的文件
  • 开发配置:webpack.dev.js
    • 代码热更新
      • css热更新
      • js热更新
    • sourcemap
  • 生产配置:webpack.prod.js
    • 代码压缩
    • 文件指纹
    • Tree Shaking(webpack4自带)
    • Scope Hositing(webpack4自带)
    • 速度优化(基础包CDN等)
    • 体积优化(代码分割)
  • SSR 配置:webpack.ssr.js
    • output的libraryTarget设置
    • css解析ignore

目录结构设计

  • lib 放置源代码
  • test 放置测试代码

结构如下:

+ |- /test
+ |- /lib
+ |- webpack.dev.js
+ |- webpack.prod.js
+ |- webpack.ssr.js
+ |- webpack.base.js
+ |- README.md
+ |- CHANGELOG.md
+ |- .eslinrc.js
+ |- package.json
+ |- index.js`

使用ESLint规范构建脚本

使用 eslint-config-airbnb-base

eslint --fix 可以自动处理空格。

安装的插件:

npm i eslint@7 babel-eslint eslint-config-airbnb-base -D

我们在工程根目录下新建.eslintrc.js,代码如下:

module.exports = {parser: "babel-eslint",extends: "airbnb-base",env: {browser: true,node: true}
};

我们在packagejson中新建一条命令:

"scripts": {"eslint": "eslint ./lib --fix"},

webpack.base.js代码:

const path = require('path');
const glob = require('glob');const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');const setMPA = () => {const entry = {};const htmlWebpackPlugins = [];const entryFiles = glob.sync(path.join(__dirname, './src/*/index.js'));Object.keys(entryFiles).map((index) => {const entryFile = entryFiles[index];const match = entryFile.match(/src\/(.*)\/index\.js/);const pageName = match && match[1];entry[pageName] = entryFile;return htmlWebpackPlugins.push(new HtmlWebpackPlugin({template: path.join(__dirname, `src/${pageName}/index.html`),filename: `${pageName}.html`,chunks: [pageName],inject: true,minify: {html5: true,collapseWhitespace: true,preserveLineBreaks: false,minifyCSS: true,minifyJS: true,removeComments: false,},}),);});return {entry,htmlWebpackPlugins,};
};const { entry, htmlWebpackPlugins } = setMPA();module.exports = {entry,output: {path: path.join(__dirname, 'dist'),filename: '[name]_[chunkhash:8].js',},module: {rules: [{test: /.js$/,use: ['babel-loader'],},{test: /.css$/,use: [MiniCssExtractPlugin.loader, 'css-loader'],},{test: /.less$/,use: [MiniCssExtractPlugin.loader,'css-loader','less-loader',{loader: 'postcss-loader',options: {postcssOptions: {plugins: [['autoprefixer',{overrideBrowserslist: ['last 2 version', '>1%', 'ios 7'],},],],},},},{loader: 'px2rem-loader',options: {remUnit: 75,remPrecision: 8,},},],},{test: /.(png|jpe?g|gif)$/,use: [{loader: 'file-loader',options: { name: '[name]_[hash:8].[ext]' },},],},{test: /.(woff|woff2|eot|otf|ttf)$/,use: [{loader: 'file-loader',options: { name: '[name]_[hash:8].[ext]' },},],},],},plugins: [new MiniCssExtractPlugin({filename: '[name]_[contenthash:8].css',}),new FriendlyErrorsWebpackPlugin(),function errorPlugin() {this.hooks.done.tap('done', (stats) => {if (stats.compilation.errors && stats.compilation.errors.length && process.argv.indexOf('--watch') === -1) {process.exit(1); // 1表示错误码并退出}});},new CleanWebpackPlugin(),].concat(htmlWebpackPlugins),
};

webpack.dev.js代码:

const { merge } = require('webpack-merge');
const webpack = require('webpack');
const baseConfig = require('./webpack.base');const devConfig = {mode: 'development',plugins: [new webpack.HotModuleReplacementPlugin()],devServer: {contentBase: './dist',hot: true,stats: 'errors-only',},devtool: 'cheap-source-map',
};module.exports = merge(baseConfig, devConfig);

webpack.prod.js代码:

const { merge } = require('webpack-merge');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
const cssnano = require('cssnano');
const baseConfig = require('./webpack.base');const prodConfig = {mode: 'production',plugins: [new OptimizeCssAssetsPlugin({assetNameRegExp: /\.css$/g,cssProcessor: cssnano,}),new HtmlWebpackExternalsPlugin({externals: [{module: 'react',entry: 'https://unpkg.com/react@18.2.0/umd/react.production.min.js',global: 'React',},{module: 'react-dom',entry: 'https://unpkg.com/react-dom@18/umd/react-dom.production.min.js',global: 'ReactDOM',},],}),],optimization: {splitChunks: {minSize: 0,cacheGroups: {commons: {name: 'commons',chunks: 'all',minChunks: 2,},},},},
};module.exports = merge(baseConfig, prodConfig);

webpack.ssr.js代码:

const { merge } = require('webpack-merge');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
const cssnano = require('cssnano');
const baseConfig = require('./webpack.base');const prodConfig = {mode: 'production',module: {rules: [{test: /\.css$/,use: 'ignore-loader',},{test: /\.less$/,use: 'ignore-loader',},],},plugins: [new OptimizeCssAssetsPlugin({assetNameRegExp: /\.css$/g,cssProcessor: cssnano,}),new HtmlWebpackExternalsPlugin({externals: [{module: 'react',entry: 'https://unpkg.com/react@18.2.0/umd/react.production.min.js',global: 'React',},{module: 'react-dom',entry: 'https://unpkg.com/react-dom@18/umd/react-dom.production.min.js',global: 'ReactDOM',},],}),],optimization: {splitChunks: {minSize: 0,cacheGroups: {commons: {name: 'commons',chunks: 'all',minChunks: 2,},},},},
};module.exports = merge(baseConfig, prodConfig);

package.json配置:

{"name": "builder-webpack","version": "1.0.0","description": "","main": "index.js","directories": {"lib": "lib","test": "test"},"scripts": {"test": "echo \"Error: no test specified\" && exit 1","eslint": "eslint ./lib --fix"},"keywords": [],"author": "","license": "ISC","devDependencies": {"babel-eslint": "^10.1.0","eslint": "^7.32.0","eslint-config-airbnb-base": "^15.0.0"},"dependencies": {"autoprefixer": "^10.4.15","babel-loader": "^8.3.0","clean-webpack-plugin": "^3.0.0","css-loader": "^3.6.0","cssnano": "^4.1.11","express": "^4.18.2","file-loader": "^6.2.0","friendly-errors-webpack-plugin": "^1.7.0","glob": "^7.2.3","html-webpack-externals-plugin": "^3.8.0","html-webpack-plugin": "^4.5.2","less": "^4.2.0","less-loader": "^6.2.0","mini-css-extract-plugin": "^1.0.0","optimize-css-assets-webpack-plugin": "^5.0.8","postcss": "^8.4.28","postcss-loader": "^4.3.0","prettier": "^2.8.8","px2rem-loader": "^0.1.9","raw-loader": "^0.5.1","style-loader": "^2.0.0","url-loader": "^4.1.1","webpack": "^4.46.0","webpack-cli": "^3.3.12","webpack-dev-server": "^3.11.3","webpack-merge": "^5.9.0"}
}

由于我们最终是要发布到npm上,并且要执行构建,所以依赖需要安装到dependencies。

冒烟测试介绍和实际运用

冒烟测试 (smoke testing)

冒烟测试是指对提交测试的软件在进行详细深入的测试之前而进行的预测试,这种
预测试的主要目的是暴露导致软件需重新发布的基本功能失效等严重问题。

冒烟测试执行

构建是否成

每次构建完成 build 目录是否有内容输出

  • 是否有 JS、CSS 等静态资源文件
  • 是否有 HTML 文件

判断构建是否成功

在示例项目里面运行构建,看看是否有报错

安装rimraf插件

npm i rimraf -D

示例代码:

const path = require("path");
const webpack = require("webpack");
const { rimraf } = require("rimraf");process.chdir(path.join(__dirname, "template"));rimraf("./dist").then(() => {const prodConfig = require("../../lib/webpack.prod.js");webpack(prodConfig, (err, stats) => {if (err) {console.error(err);process.exit(2);}console.log(stats.toString({colors: true,modules: false,children: false}));console.log("webpack build success, run test start...");});}).catch((err) => {console.error(err);});

判断基本功能是否正常

编写 mocha 测试用例

  • 是否有 JS、CSS 等静态资源文件
  • 是否有 HTML 文件

安装插件glob-allmocha

npm i glob-all mocha -D

编写一个检测html的html-test.js:

const glob = require("glob-all");describe("checking generated html files", () => {it("should generate html files", (done) => {const files = glob.sync(["./dist/index.html", "./dist/search.html"]);if (files.length > 0) {done();} else {throw new Error("no html files generated");}});
});

编写一个检测css、js的css-js-test.js:

const glob = require("glob-all");describe("checking generated html files", () => {it("should generate html files", (done) => {const files = glob.sync(["./dist/index_*.js", "./dist/index_*.css", "./dist/search_*.js", "./dist/search_*.css"]);if (files.length > 0) {done();} else {throw new Error("no css js files generated");}});
});

最后测试代码:

const path = require("path");
const webpack = require("webpack");
const { rimraf } = require("rimraf");
const Mocha = require("mocha");const mocha = new Mocha({timeout: "10000ms"
});process.chdir(path.join(__dirname, "template"));rimraf("./dist").then(() => {const prodConfig = require("../../lib/webpack.prod.js");webpack(prodConfig, (err, stats) => {if (err) {console.error(err);process.exit(2);}console.log(stats.toString({colors: true,modules: false,children: false}));console.log("webpack build success, run test start...");mocha.addFile(path.join(__dirname, "html-test.js"));mocha.addFile(path.join(__dirname, "css-js-test.js"));mocha.run();});}).catch((err) => {console.error(err);});

最后使用node执行这个代码js即可。

单元测试和测试覆盖率

测试框架

单纯的测试框架(mocha),需要断言库

  • chai
  • should.js
  • expect
  • better-assert

集成框架,开箱即用

  • Jasmine
  • Jest

编写单元测试用例

  • 技术选型:Mocha + Chai
  • 测试代码:describe, it, except
  • 测试命令:mocha add.test.js

add.test.js示例代码:

const expect = require('chai').expect;
const add = require('../src/add');
describe('use expect: src/add.js', () => {it('add(1, 2) === 3', () => {expect(add(1, 2).to.equal(3));});
});

单元测试接入

mocha官网:https://mochajs.org/,官网示例代码:

var assert = require('assert');
describe('Array', function () {describe('#indexOf()', function () {it('should return -1 when the value is not present', function () {assert.equal([1, 2, 3].indexOf(4), -1);});});
});
  • 1、安装 mocha + chai
npm i mocha chai -D
  • 2、新建 test 目录,并增加 index.js 单位测试文件入口。
const path = require("path");process.chdir(path.join(__dirname, "smoke/template")); // 修改当前工作目录describe("builder-webpack test case", () => {require("./unit/webpack-base-test.js");
});
  • 3、test目录下新建unit目录,存放单元测试文件。

安装断言插件assert:

npm i assert -D

例如test/unit/webpack-base-test.js代码:

const assert = require("assert");describe("webpack.base.js test case", () => {const baseConfig = require("../../lib/webpack.base.js");it("entry", () => {assert.equal(baseConfig.entry.index, "D:/builder-webpack/test/smoke/template/src/index/index.js");assert.equal(baseConfig.entry.search, "D:/builder-webpack/test/smoke/template/src/search/index.js");});
});
  • 4、在 package.json 中的 scripts 字段增加 test 命令
"scripts": {"test": "./node_modules/mocha/bin/_mocha"
},

mocha默认会执行工程目录下的test文件下的index.js。

其中

  • 5、执行测试命令
npm run test

结果:
在这里插入图片描述

测试覆盖率

使用istanbul工具。istanbul 是一个 JavaScript 的代码覆盖率检查工具。

特征:

  • 可检查包括语句、分支和函数覆盖,以及反向工程的代码行覆盖
  • 模块加载钩子 可随时跟踪代码
  • 命令行工具 可运行带覆盖率检查的 node 单元测试,不需要对测试运行进行协作
  • 可生成 HTML 和 LCOV 报表
  • 可作为中间件使用,在浏览器进行测试
  • 可在命令行中以库的形式使用
  • 基于 esprima 解析器和 escodegen 代码生成器

官网地址:https://github.com/gotwarlost/istanbul

安装:

npm i istanbul -D

当然也可以全局安装。

基本用法:

$ cd /path/to/your/source/root
$ istanbul cover test.js

例如上面单元测试入口scripts调整test命令:

"scripts": {"test": "istanbul cover ./node_modules/mocha/bin/_mocha"
},

执行npm run test 结果如图:
在这里插入图片描述

说明:

  • Statements:覆盖的语句
  • Branches:覆盖的分支
  • Functions:覆盖的函数
  • Lines:覆盖的行数

持续集成和Travis CI

持续集成的作用

优点:

  • 快速发现错误
  • 防止分支大幅偏离主干

核心措施是,代码集成到主干之前,必须通过自动化测试。只要有一个测试用例失败,就不能集成。

Github 最流行的 CI

在这里插入图片描述

接入 Travis CI

  • 1、首先 在github上创建一个新项目,上传存放的工程代码,创建示例:
    在这里插入图片描述

  • 2、https://travis-ci.org/ 使用 GitHub 账号登录

目前使用这个Travis CI现在已经改变运营策略,对开源项目也收费了。

  • 3、在 https://travis-ci.org/account/repositories 为项目开启
  • 4、项目根目录下新增 .travis.yml

travis.yml 文件内容

  • install 安装项目依赖
  • script 运行测试用例
language: node_jssudo: falsecache:apt: truedirectories:- node_modulesnode_js:stable #设置相应的版本install:-npm install-D #安装构建器依赖-cd ./test/template-project- npm install -D #安装模板项目依赖script:- npm test

发布构建包到npm社区

添加用户: npm adduser

升级版本

  • 升级补丁版本号:npm version patch
  • 升级小版本号:npm version minor
  • 升级大版本号:npm version major

发布版本:npm publish

具体操作:

  • 1、先去github上拷贝创建的新项目到本地。
  • 2、然后把本地的工程代码拷贝到git目录工程下。
  • 3、npm login登录到npm上

若果以前用的淘宝镜像,那么需要切换回npm.

npm config set registry https://registry.npmjs.org/

然后再执行 npm login,后面输入账号密码以及游戏登录进去
-4 、npm publish 发布到npm上

Git 提交规范和changelog生成

良好的 Git commit 规范优势:

  • 加快 Code Review 的流程
  • 根据 Git Commit 的元数据生成 Changelog
  • 后续维护者可以知道 Feature 被修改的原因

提交格式要求:

  • feat:新增feature
  • fix:修复bug
  • docs:仅仅修改了文档,比如README,CHANGELOG, CONTRIBUTE等等
  • style:仅仅修改了空格、格式缩进、都好等等,不改变代码逻辑
  • refactor:代码重构,没有加新功能或者修复bug
  • perf:优化相关,比如提升性能、体验
  • test:测试用例,包括单元测试、集成测试等
  • chore:改变构建流程、或者增加依赖库、工具等
  • revert:回滚到上一个版本

本地开发阶段增加 precommit 钩子:

  • 安装 husky
  • 通过 commitmsg 钩子校验信息
  • npm install husky --save-dev
"scripts": {"commitmsg": "validate-commit-msg","changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0"
},
"devDependencies": {"validate-commit-msg": "^2.11.1","conventional-changelog-cli": "^1.2.0","husky": "^0.13.1"
}

遵守 semver 规范

概念:语义化的版本控制(Semantic Versioning),简称语义化版本,英文缩写为 SemVer

优势:

  • 避免出现循环依赖
  • 依赖冲突减少

语义化版本(Semantic Versioning)规范格式

  • 主版本号: 做了不兼容的 API 修改(进行不向下兼容的修改)
  • 次版本号: 做了向下兼容的功能性增加(API 保持向下兼容的新增及修改)
  • 修订号: 做了向下兼容的问题修正(修复问题但不影响 API)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/879885.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu截图工具flameshot

最近在使用香橙派做一些东西,有些内容需要截图记录,这里记录一下截图工具的安装和使用过程,方便以后查阅。 Ubuntu截图工具flameshot flameshot 简介flameshot 安装flameshot 相关命令 flameshot 简介 linux系统里面最好用的截屏工具支持图形…

基于python+django+vue的旅游网站系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于协同过滤pythondjangovue…

计算机四级-计算机网络

一、基础知识 1.对计算机网络发展具有重要影响的广域网是:ARPANET 随机争用型的介质访问控制方法起源于:ALOHANET 2.计算机网络发展阶段: A)第一阶段的主要成果是计算机技术与通信技术的结合 B)第二阶段的主要成果…

【例题】lanqiao4425 咖啡馆订单系统

样例输入 3 2 2 1 3 1 2样例输出 3 2样例说明 输入的数组为:【3,1,2】 增量序列为:【2,1】 当增量 h2:对于每一个索引 i,我们会将数组元素 arr[i] 与 arr[i−h] 进行比较,并进行可…

电线电缆制造5G智能工厂物联数字孪生平台,推进制造业数字化转型

电线电缆制造行业作为关键的基础设施建设领域,正积极拥抱新技术,推动生产方式的深刻变革。电线电缆制造5G智能工厂物联数字孪生平台的兴起,不仅为行业注入了新的活力,更为制造业的数字化转型树立了新的标杆。 电线电缆制造5G智能…

es由一个集群迁移到另外一个集群es的数据迁移

迁移es的数据 改下index的索引 就可以了。 查询 用curl -u就可以查询了

Thymeleaf 的创建

pox.xml 文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM…

智能除螨仪——NV040D-SOP8语音芯片方案引领除螨仪新时代

随着物联网技术的快速发展&#xff0c;除螨仪作为家庭清洁的重要工具&#xff0c;其智能化、人性化的设计成为提升市场竞争力的关键。置入语音芯片的除螨仪&#xff0c;通过开机提示、工作状态反馈、操作指引、故障提醒等内容。用户可以更加直观地了解除螨仪的工作状态&#xf…

推荐系统-电商直播 多目标排序算法探秘

前言&#xff1a; 电商直播已经成为电商平台流量的主要入口&#xff0c;今天我们一起探讨推荐算法在直播中所面临的核心问题和解决方案。以下内容参考阿里1688的技术方案整理完成。 一、核心问题介绍 在电商网站中&#xff0c;用户的主要行为是在商品上的行为&#xff0c;直播…

深度学习:(五)初识神经网络

&#xff08;一&#xff09;神经网络的层数 除去输入层&#xff0c;但包括输出层&#xff0c;每一层都有自己的参数。 输入层称为第零层。 &#xff08;二&#xff09;最简单的神经网络&#xff08;逻辑回归&#xff09; 下图中的小圆圈&#xff0c;代表了一种运算。且一个小…

阿里开源多模态大模型Ovis1.6,重塑出海电商AI格局

阿里开源Ovis1.6&#xff1a;多模态领域再夺第一 阿里再一次证明了自己在多模态领域的实力。这一次&#xff0c;阿里国际AI团队开源的多模态大模型Ovis1.6&#xff0c;不仅成功开源&#xff0c;还在多模态评测基准OpenCompass上击败了Qwen2VL-7B、InternVL2-26B和MiniCPM-V-2.…

Docker 进入容器并运行命令的方法

目录 理解 Docker 容器的基本概念 使用 docker exec 进入运行中的容器 基本用法 常用选项解析 选项详解 实际案例演示 1. 进入容器的交互式 Shell 2. 在容器中运行单个命令 3. 以指定用户运行命令 4. 设置环境变量并运行命令 5. 指定工作目录 使用 docker attach 附…

标准库标头 <bit>(C++20)学习

<bit>头文件是数值库的一部分。定义用于访问、操作和处理各个位和位序列的函数。例如&#xff0c;有函数可以旋转位、查找连续集或已清除位的数量、查看某个数是否为 2 的整数幂、查找表示数字的最小位数等。 类型 endian (C20) 指示标量类型的端序 (枚举) 函数 bit_ca…

使用LangGPT提示词让大模型比较浮点数

使用LangGPT提示词让大模型比较浮点数 背景介绍环境准备创建虚拟环境安装一些必要的库安装其他依赖部署大模型启动图形交互服务设置提示词与测试 LangGPT结构化提示词 背景介绍 LLM在对比浮点数字时表现不佳&#xff0c;经验证&#xff0c;internlm2-chat-1.8b (internlm2-cha…

HObject复制耗时试用

测试源码一 //第一步const int N 1000;HObject[] imgs new HObject[N];for (int i 0; i < N; i){HOperatorSet.GenImageConst(out imgs[i], "byte", 1024 i, 1024 i);}//第二步List<HObject> lists new List<HObject>();for(int i 0; i < …

基于PHP的新闻管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于phpMySQL的新闻管理系统。…

MySQL的缓存策略

目录 一、MySQL 缓存方案用来干什么 二、提升MySQL访问性能的方式 1、读写分离&#xff08;MySQL的主从复制&#xff09; 2、连接池 3、异步连接 三、缓存方案是怎么解决的 1、缓存与MySQL一致性状态分析 2、制定热点数据的读写策略 四、缓存方案问题的解决方法 1、缓…

酸枣病虫害智能化防控系统的探索与实践,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建枣类作物种植场景下酸枣病虫害智能检测识别系统

智慧农业&#xff0c;作为现代农业的高级形态&#xff0c;通过集成物联网、大数据、人工智能等先进技术&#xff0c;实现了农业生产过程的精准化、智能化管理。在酸枣等经济作物的种植过程中&#xff0c;病虫害的及时监测与防控直接关系到作物的产量与质量&#xff0c;进而影响…

react hooks--React.memo

基本语法 React.memo 高阶组件的使用场景说明&#xff1a; React 组件更新机制&#xff1a;只要父组件状态更新&#xff0c;子组件就会无条件的一起更新。 子组件 props 变化时更新过程&#xff1a;组件代码执行 -> JSX Diff&#xff08;配合虚拟 DOM&#xff09;-> 渲…

Knife4j 一款基于Swagger的开源文档管理工具

一、简单介绍 1.1 简介 Knife4j 是一款基于Swagger的开源文档管理工具&#xff0c;主要用于生成和管理 API 文档 二、使用步骤&#xff1a; 2.1 添加依赖&#xff1a; <dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spr…