node+nginx实现对react进行一键打包部署--windows版
文章目录
- node+nginx实现对react进行一键打包部署--windows版
- 1.功能展示及项目准备
- 1.1功能展示
- 1.2 项目准备
- 1.2.1技术点
- 1.2.2安装相关配置(windows)
- 2.实现
- 2.1 实现思路
- 2.2 实现步骤
- 2.1 项目准备
- 2.1.1 创建env文件
- 2.1.2 创建api/index.js文件
- 2.1.3 添加解决跨域代码
- 2.2 项目实现
- 2.1 前端部分
- 2.2.1 编写前端带代码
- 2.2 后端部分
- 2.2.1 实现node对项目打包
- 2.2.2 对项目打包文件夹重命名
- 2.2.3 对打包文件夹复制在nginx指定位置
- 2.2.4 配置nginx管理项目代码
- 2.2.5 重启nginx
- 2.2.6 完整代码
- 3.总结
node+nginx实现对react进行一键打包部署–windows版
1.功能展示及项目准备
1.1功能展示

1.2 项目准备
1.2.1技术点
- react
- node
- nginx
- express
- axios
1.2.2安装相关配置(windows)
- 安装nginx
- 使用vite安装react
- 安装node
- 使用node 安装express
- 项目中安装axios (npm i axios --S)
网上有多种安装方法,
这里我就不做过多介绍了
2.实现
2.1 实现思路
2.2 实现步骤
2.1 项目准备
2.1.1 创建env文件
在vite创建的项目文件根目录下新建一个.env文件
//你创建的项目的路径部分路径
VITE_API_URL=D:\OneDrive\桌面\练习项目\学生信息-react
//项目的名称
VITE_APP_NAME=create
2.1.2 创建api/index.js文件
项目的src下创建api文件夹,新建index.js文件,写入以下代码
import axios from 'axios'
axios.defaults.baseURL='http://localhost:3000'export const getStuList=()=>axios({url:'/student/list',method:'get'})export const addStu=(data)=>axios({url:'/student/add',method:'post',data})export const editStu=(data)=>axios({url:'/student/edit',method:'post',data})export const delStu=(data)=>axios({url:'/student/del',method:'post',data})export const buildApp=(data)=>axios({url:'/build/app',method:'post',data})
2.1.3 添加解决跨域代码
向express的项目中的app.js添加以下代码
//用于配置解决跨域问题
var allowCrosDown=function(req,res,next){res.header('Access-Control-Allow-Origin','*')res.header('Access-Control-Allow-Methods','*')res.header('Access-Control-Allow-Headers','*')next()
}
app.use(allowCrosDown)
2.2 项目实现
2.1 前端部分
2.2.1 编写前端带代码
主要是填写要部署后的项目监听端口与文件名称
function App() {const apiUrl = import.meta.env.VITE_API_URL;const appName = import.meta.env.VITE_APP_NAME;const [port,setPort]=useState('')const [buildName,setBuildName]=useState('')const [msg,setMsg]=useState('')async function handelBuild(){let result=await buildApp({TotalPath:apiUrl+'\\'+appName,port:+port,buildName})setMsg(result.data.msg)}return (<><div className='tabelCon'><div className='options'><ul><li><label htmlFor="port">打包后端口号:</label><input type="text" name="port" value={port} onChange={e=>setPort(e.target.value)} placeholder='请输入9000以后的端口号'/></li><li><label htmlFor="buildName">打包后文件名:</label><input type="text" name="buildName" value={buildName} onChange={e=>setBuildName(e.target.value)} placeholder='请输入文件名称'/></li><li><button onClick={handelBuild} className='bulid'>打包文件</button></li><li style={{color:'red'}}>{msg}</li></ul></div>//实现添加信息删除信息部分的html代码//因为与本文章无关便不记录,与兴趣的//可以自己实现一下......</div></>)
}export default App
2.2 后端部分
2.2.1 实现node对项目打包
实现对react进行打包,实现起来就是,
- node进入前端项目的根目录
- 执行npm run build命令
// 使用 child_process.exec 函数执行命令//执行下面代码,在项目中就会看到一个dist文件夹const { exec } = require('child_process');let {TotalPath,port,buildName}=req.bodyconst command = 'npm run build';exec(`cd ${TotalPath} && ${command}`, (error, stdout, stderr) => {if (error) {res.send({msg:error})return;}});
2.2.2 对项目打包文件夹重命名
对打包后的文件进行重命名
- 使用fs.rename()对文件夹进行重命名
//buildName就是要重新命名的名称
let {TotalPath,port,buildName}=req.body
let buildPath=TotalPath+'\\'+'dist'
let newPath=TotalPath+`\\${buildName}`
fs.rename(buildPath, newPath, (err) => {if (err) res.send({msg:error});console.log('重命名成功')})
2.2.3 对打包文件夹复制在nginx指定位置
将打包的文件复制到nginx安装目录中的html文件目录下
- 创建一个文件夹
- 将打包后的内容复制过去
let NginxPath='D:\\前端开发工具\\nginx-1.24.0'// d:\前端开发工具\nginx-1.24.0\conf\nginx.conflet NginxConf=NginxPath+'\\'+'conf'+'\\'+'nginx.conf'const directoryPath = NginxPath+`\\html\\${buildName}`;fs.mkdir(directoryPath, { recursive: true }, err => {if (err) {res.send({msg:error})console.error(`无法创建文件夹 ${directoryPath}: ${err}`);return;}console.log(`文件夹 ${directoryPath} 已成功创建`);copyFolderRecursiveSync(newPath, directoryPath );exec(`cd ${NginxPath} && ${reloadCommand}`, (error, stdout, stderr) => {if (error) {res.send({msg:error})return;}res.send({msg:'项目打包成功、修改名称成功、复制文件到nginx成功、配置成功、重启成功'})});});function copyFolderRecursiveSync(source, target) {// 判断源文件夹是否存在if (!fs.existsSync(source)) {console.log(`源文件夹 ${source} 不存在`);return;}// 创建目标文件夹(如果不存在)if (!fs.existsSync(target)) {fs.mkdirSync(target);}// 读取源文件夹中的内容const files = fs.readdirSync(source);files.forEach(file => {const srcFile = path.join(source, file);const tgtFile = path.join(target, file);// 判断文件是文件夹还是文件if (fs.lstatSync(srcFile).isDirectory()) {// 如果是文件夹,递归复制子文件夹copyFolderRecursiveSync(srcFile, tgtFile);} else {// 如果是文件,直接复制到目标文件夹fs.copyFileSync(srcFile, tgtFile);}});
}
2.2.4 配置nginx管理项目代码
配置nginx管理项目代码
- 修改nginx安装目录下conf中nginx.conf文件内容
- 编写命令,插入代码
//port监听的端口
const { exec } = require('child_process');
const path = require('path');
const fs = require('fs');
const readline = require('readline');
const serve=` server {listen ${port};server_name localhost;location / {root html/${buildName};index index.html index.htm;}error_page 500 502 503 504 /50x.html;location = /50x.html {root html;}}`//这里的59指的是在nginx.conf中插入的位置,//可根据自己的配置文件进行相应的修改insertContentInLine(NginxConf, serve, 59);function insertContentInLine(filePath, content, lineIndex) {// 创建读取文件的流const readStream = fs.createReadStream(filePath);const rl = readline.createInterface({input: readStream,output: process.stdout,terminal: false});let lines = [];let currentLineIndex = 1;rl.on('line', line => {lines.push(line);if (currentLineIndex === lineIndex) {lines.push(content);}currentLineIndex++;});rl.on('close', () => {// 将修改后的内容写回文件fs.writeFileSync(filePath, lines.join('\n'));console.log(`内容已成功插入到第 ${lineIndex} 行`);});
}
2.2.5 重启nginx
对nginx进行重启
- 进入nginx安装目录
- 执行nginx -s reload重启
const reloadCommand='nginx -s reload'let NginxPath='D:\\前端开发工具\\nginx-1.24.0'exec(`cd ${NginxPath} && ${reloadCommand}`, (error, stdout, stderr) => {if (error) {res.send({msg:error})return;}res.send({msg:'项目打包成功、修改名称成功、复制文件到nginx成功、配置成功、重启成功'})});
现在你就实现了点击一键部署项目在本机中了
2.2.6 完整代码
完整代码如下
const { exec } = require('child_process');
const path = require('path');
const fs = require('fs');
const readline = require('readline');
function copyFolderRecursiveSync(source, target) {// 判断源文件夹是否存在if (!fs.existsSync(source)) {console.log(`源文件夹 ${source} 不存在`);return;}// 创建目标文件夹(如果不存在)if (!fs.existsSync(target)) {fs.mkdirSync(target);}// 读取源文件夹中的内容const files = fs.readdirSync(source);files.forEach(file => {const srcFile = path.join(source, file);const tgtFile = path.join(target, file);// 判断文件是文件夹还是文件if (fs.lstatSync(srcFile).isDirectory()) {// 如果是文件夹,递归复制子文件夹copyFolderRecursiveSync(srcFile, tgtFile);} else {// 如果是文件,直接复制到目标文件夹fs.copyFileSync(srcFile, tgtFile);}});
}function insertContentInLine(filePath, content, lineIndex) {// 创建读取文件的流const readStream = fs.createReadStream(filePath);const rl = readline.createInterface({input: readStream,output: process.stdout,terminal: false});let lines = [];let currentLineIndex = 1;rl.on('line', line => {lines.push(line);if (currentLineIndex === lineIndex) {lines.push(content);}currentLineIndex++;});rl.on('close', () => {// 将修改后的内容写回文件fs.writeFileSync(filePath, lines.join('\n'));console.log(`内容已成功插入到第 ${lineIndex} 行`);});
}//暴露接口
router.post('/build/app',(req,res)=>{let {TotalPath,port,buildName}=req.body// let appPath='D:\OneDrive\桌面\练习项目\学生信息-react\create'const command = 'npm run build';const reloadCommand='nginx -s reload'const serve=` server {listen ${port};server_name localhost;location / {root html/${buildName};index index.html index.htm;}error_page 500 502 503 504 /50x.html;location = /50x.html {root html;}}`// 使用 child_process.exec 函数执行命令let NginxPath='D:\\前端开发工具\\nginx-1.24.0'// d:\前端开发工具\nginx-1.24.0\conf\nginx.conflet NginxConf=NginxPath+'\\'+'conf'+'\\'+'nginx.conf'let buildPath=TotalPath+'\\'+'dist'let newPath=TotalPath+`\\${buildName}`const directoryPath = NginxPath+`\\html\\${buildName}`;exec(`cd ${TotalPath} && ${command}`, (error, stdout, stderr) => {if (error) {res.send({msg:error})return;}fs.rename(buildPath, newPath, (err) => {if (err) res.send({msg:error});fs.mkdir(directoryPath, { recursive: true }, err => {if (err) {res.send({msg:error})console.error(`无法创建文件夹 ${directoryPath}: ${err}`);return;}console.log(`文件夹 ${directoryPath} 已成功创建`);copyFolderRecursiveSync(newPath, directoryPath );insertContentInLine(NginxConf, serve, 59);exec(`cd ${NginxPath} && ${reloadCommand}`, (error, stdout, stderr) => {if (error) {res.send({msg:error})return;}res.send({msg:'项目打包成功、修改名称成功、复制文件到nginx成功、配置成功、重启成功'})});});});});
})
3.总结
在这个项目中我们学会了以下知识
- node执行命令
- exec()执行
- node修改文件夹名称
- fs.rename()
- node 复制文件到指定目录下
- fs.copyFileSync
- node 向文件中插入内容
相关文章:
node+nginx实现对react进行一键打包部署--windows版
文章目录 nodenginx实现对react进行一键打包部署--windows版1.功能展示及项目准备1.1功能展示 1.2 项目准备1.2.1技术点1.2.2安装相关配置(windows) 2.实现2.1 实现思路2.2 实现步骤2.1 项目准备2.1.1 创建env文件2.1.2 创建api/index.js文件2.1.3 添加解决跨域代码 2.2 项目实…...
【机器学习】基于Gumbel-Sinkhorn网络的“潜在排列问题”求解
1. 引言 1.1.“潜在排列”问题 本文将深入探索一种特殊的神经网络方法,该方法在处理离散对象时展现出卓越的能力,尤其是针对潜在排列问题的解决方案。在现代机器学习和深度学习的领域中,处理离散数据一直是一个挑战,因为传统的神经网络架构通常是为连续数据设计的。然而,…...
create-react-app创建的项目中设置webpack配置
create-react-app 创建的项目默认使用的是 react-scripts(存在于node_modules文件夹中)来处理开发服务器和构建,它内置了一些webpack相关配置。一般不会暴露出来给开发者,但是在有些情况下我们需要修改下webpack默认配置ÿ…...
【ai】tx2 nx :安装torch、torchvision for yolov5
torchvision 是自己本地构建的验证torchvision nvidia@tx2-nx:~/twork/03_yolov5/torchvision$ nvidia@tx2-nx:~/twork/03_yolov5/torchvision$ python3 Python 3.6.9 (default, Mar 10 2023, 16:46:00) [GCC 8.4.0] on linux Type "help", "copyright",…...
【报错】在终端中输入repo命令后系统未能识别这个命令
1 报错 已经使用curl命令来下载repo工具,但是在终端中输入repo命令后系统未能识别这个命令。 2 分析 通常是因为repo...
【机器学习】K-Means算法详解:从原理到实践
🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 💫个人格言: "如无必要,勿增实体" 文章目录 K-Means算法详解:从原理到实践引言1. 基本原理1.1 簇与距离度量1.2 …...
解决qiankun项目与子应用样式混乱问题
背景 qiankun项目用的是Vue2Antdesign2,但其中一个子应用用的是Vue3Antdesign4。集成之后发现子应用的样式混乱,渲染的是Antdesign2的样式。 解决 以下步骤在子应用里操作 1. 在main.js引入ConfigProvider ,在app全局注册ConfigProvider …...
黑产当前,如何识别异常图片?
在这个人人都是创作者的年代, UGC 已成为诸多平台的重要组成。 有利益的地方就会有黑产存在, 不少 UGC 平台都被黑产「薅羊毛」搞的心烦意乱, 用户传的图片,怎么就变成视频链接了? 正常运营的平台,为何流量…...
数据模型(models)
自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 (1)在App中添加数据模型 在app1的models.py中添加如下代码: from django.db import models # 引入django.…...
【CS.AL】算法核心之贪心算法 —— 力扣(LeetCode)743. 网络延迟时间 - Dijkstra算法题解
文章目录 题目描述References 题目描述 743. 网络延迟时间 - 力扣(LeetCode) 有 N 个网络节点,标记为 1 到 N。 给定一个列表 times,其中 times[i] (u, v, w) 表示有一条从节点 u 到节点 v 的时延为 w 的有向边。 现在…...
25、架构-微服务的驱动力
微服务架构的驱动力可以从多方面探讨,包括灵活性、独立部署、技术异构性、团队效率和系统弹性等。 灵活性和可维护性 灵活性是微服务架构的一个主要优势。通过将单体应用拆分成多个独立的微服务,开发团队可以更容易地管理、维护和更新各个服务。每个微…...
JeecgFlow事件网关概念及案例
事件网关 通常网关基于连线条件决定后续路径,但事件网关有所不同,其基于事件决定后续路径。事件网关的每条外出顺序流都需要连接一个捕获中间事件。 事件网关只有分支行为,流程的走向完全由中间事件决定。可以从多条候选分支中选择事件最先达…...
使用鸿蒙HarmonyOs NEXT 开发 快速开发 简单的购物车页面
目录 资源准备:需要准备三张照片:商品图、向下图标、金钱图标 1.显示效果: 2.源码: 资源准备:需要准备三张照片:商品图、向下图标、金钱图标 1.显示效果: 定义了一个购物车页面的布局&#x…...
iOS 中 attribute((constructor)) 修饰的函数
开发环境声明:此文描述的 attribute((constructor)) 特指使用 Objective-C 开发 iOS、MacOS,Swift 语言不支持这种属性修饰符。 初识 attribute((constructor)) 在 Objective-C 开发中,attribute((constructor)) 是一个 GCC 和 Clang 编译器…...
原生js实现图片预览控件,支持丝滑拖拽,滚轮放缩,放缩聚焦
手撸源代码如下:注释应该很详细了,拿去直用 可以放到在线编辑器测试,记得修改图片路径 菜鸟教程在线编辑器 <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" conten…...
C语言入门课程学习笔记9:指针
C语言入门课程学习笔记9 第41课 - 指针:一种特殊的变量实验-指针的使用小结 第42课 - 深入理解指针与地址实验-指针的类型实验实验小结 第43课 - 指针与数组(上)实验小结 第44课 - 指针与数组(下)实验实验小结 第45课 …...
借助 Cloudflare D1 和 Drizzle 在 Astro 上实现全栈
使用 Cloudflare D1 和 Drizzle ORM 将后端添加到 Astro 项目的分步指南 文章目录 安装 Astro添加 Cloudflare 适配器部署到 Pages安装 wrangler 并登录创建 D1 数据库创建 wrangler.toml 文件将 .wrangler 添加到 .gitignore更新 astro.config.ts安装 Drizzle 依赖项创建 driz…...
SUSE linux 15的网络管理
1 手工配置网络 wicked提供了一种新的网络配置框架。自SUSE 12起,SUSE使用了新的网络管理工具wicked,这个是区别与其他常见发行版的。常见的发行版目前大多使用的是NetworkManager服务进行网络管理。 1.1 wicked网络配置 传统网络接口管理面临的挑战之…...
海康威视-下载的录像视频浏览器播放问题
目录 1、播放异常比对 2、视频编码检查 2.1、正常视频解析 2.2、海康视频解析 2.3、比对工具 3、转码 3.1、maven依赖 3.2、实现代码 4、验证 在前面的文章(海康威视-按时间下载录像文件_海康威视 sdk 下载录像 大小0-CSDN博客)中,通…...
养殖自动化管理系统:开启智慧养殖新篇章
在现代农业的快速演进中,养殖业正经历一场前所未有的技术革命。养殖自动化管理系统,作为这场变革的前沿科技,正逐步成为推动行业高效、环保、可持续发展的关键力量。本文将深入探讨自动化养殖系统如何通过精准管理、智能监控、数据驱动决策&a…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
