使用 React 和 NodeJS 创建一个全栈项目

sxkk20082年前知识分享111

前言

我们都知道 React 非常优秀并且非常出色,我们可以使用 create-react-app 快速搭建一个前端应用。 但是由于 React 构建出来的只是前端静态资源(如:HTML、CSS 、JS 等),往往不能独立部署,我们还需要一个 WEB 服务器,还需要调用 API; 在本文中,我将使用 React 和 NodeJS 创建一个全栈项目。介绍下如何让 Node.js 作为 web 服务器来加载 React 构建出的静态资源,如何让 React 程序可以直接调用 NodeJS API。

准备工作

在开始之前,请确保你的计算机上已经安装了 Node 和 NPM。

创建项目目录

首先我们用命令行创建一个 my-app 的目录,并且进入到 my-app

$ mkdir my-app
$ cd my-app

初始化 React 程序

然后使用 create-react-app 创建一个 React 程序,这部分是客户端的代码, 所以命名为 client

$ npx create-react-app client

使用 NodeJS 来实现我们的 API

创建 API 目录

$ mkdir api
$ cd api

初始化 nodeJS 项目

npm init -y

Express.js 是一个非常轻量的 Node.js 框架,安装 express。

npm i --save express

在 api 文件夹下,建立 server.js

// api/server.js

const express = require('express')
const app = express()
app.use(express.json())

app.get('/', function (req, res) {
  res.send("It's working!")
})

app.listen(3000, () => {
  console.log('app listening on port 3000')
})

把 api 服务起在 3000 端口

package.json 中的 scripts 部分添加启动脚本

"scripts":{
    "start": "node ./api/server.js"
}

然后运行, 访问 http://localhost:3000 ,就可以在浏览器中看到如下效果。

npm start

image.png

React 中访问 API 接口

先在 ./api/server 修养接口返回数据是 json

app.get('/', function (req, res) {
  res.json({ name: '张三' })
})

更改 ./client/src/app.js

import React, { useEffect, useState } from 'react'

export default function App() {
  const [name, setName] = useState('')

  useEffect(() => {
    fetch('http://localhost:3000')
      .then((res) => res.json())
      .then((data) => setName(data.name))
  }, [])

  return <div>Hello {name}</div>
}

这个时候在页面上是看不到效果,看下 chrome 控制台会看到如下提示。

image.png

这是因为在发出 Fetch 请求时发生了跨域请求。为了解决这个问题:

方案一

更改接口允许跨域,我们需要在安装 cors 这个包:

npm install --save cors

更改 ./client/src/app.js, 通过中间件的方式引用这个函数。

const cors = require('cors')

app.use(cors())

然后停止服务, npm start 重新启动 ,然后就可以看到效果了。

image.png

方案二

create-react-app 支持接口代理设置

开发环境

在 client/package.json 设置


proxy:localhost:3000

然后在 jsx 中就可以使用相对路径请求了

useEffect(() => {
  fetch('/api')
    .then((res) => res.json())
    .then((data) => setName(data.name))
}, [])

生产环境

serve.js 中增加以下代码:

if (process.env.NODE_ENV === 'production') {
  // 把静态资源指向 `client/build`
  app.use(express.static(path.resolve(__dirname, '../client/build')))

  // 其他任何没处理的接口都返回 index.html
  app.get('*', (req, res) => {
    res.sendFile(path.resolve(__dirname, '../client/build', 'index.html'))
  })
}

npm 安装 cross-env这个包,区分开发环境还是生产环境.

更改在 api/package.json 设置

{
  "scripts": {
    "dev": "cross-env NODE_ENV=development node ./api/server.js",
    "start": "cross-env NODE_ENV=production node ./api/server.js"
  }
}

方案三

开发环境还是使用 proxy 代理,生产环境使用 nginx 反向代理实现。

本地我使用了 docker-compose

使用以下 docker-compose.yml

web:
  image: nginx
  volumes:
    - ./nginx.conf:/etc/nginx/nginx.conf:ro
  ports:
   - "8080:80"

根目录下建一个 nginx.config

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;
    keepalive_timeout  65;
    gzip  on;

    upstream server {
        server server:3001;
    }
    upstream web {
        server web:3000;
    }

    server {
        listen 80;
        server_name  localhost;
        location / {
            proxy_pass http://web/;
        }

        location ^~ /api/ {
            proxy_pass http://server/api/;
        }
    }
}

启动容器服务

docker-compose up -d

然后访问 http://localhost:8080 ,就可以在浏览器中看到效果了。

最后

小伙伴们,你们会使用那种方案呢,欢迎评论区留言。

希望这篇文章对大家有所帮助,也可以参考我往期的文章或者在评论区交流你的想法和心得,欢迎一起探索前端。

相关文章

AI技术助力,智能OCR识别接口的新媒体探索与价值解读

AI技术助力,智能OCR识别接口的新媒体探索与价值解读

  在信息大爆炸的时代,海量的文字、图片和文档在网络中快速传播,而其准确、高速的识别成为了当代社会的一个重要挑战。为了满足这一需求,新媒体科技不断地推陈出新,其中尤为引人注目...

AI科技:改变世界的技术创新

AI科技:改变世界的技术创新

  随着人工智能(AI)技术的飞速发展,我们正处于一个科技革命的时代。AI已经渗透到各个领域,对我们的生活产生着深远的影响。无论是在医疗保健、交通运输、金融服务还是教育等行业...

这是启动后的界面,这个 demo 不是一个简单的页面,而是一个包含了深度嵌套路由的例子。

下图我开发时的截图,Turbopack 直接在命令行中打印出了构建时间,我们看到启动时间只需要 2.3ms

更新速度

试着修改代码,程序会自动热更新,绝大多数次数更新时间都很快,但偶尔有几次更新时间却很长,图片中有一处需要 16s(我使用的是 Mac M1),这其中的原因就不得而知了,尤大也发布了测评,使用 1000 个节点来对比更新速度,数据显示:根组件与 vite 时间几乎相同,叶子节点比 vite 快 68%,与官方称比 vite 快 10 倍相差甚远。当然目前 Turbopack 还处于 alpha 阶段,期待 Turbopack 能够尽快推出正式版。

Turbopack 特点

  • 开箱即用 TypeScript, JSX, CSS, CSS Modules, WebAssembly 等
  • 增量计算: Turbopack 是建立在 Turbo 之上的,Turbo 是基于 Rust 的开源、增量记忆化框架,除了可以缓存代码,还可以缓存函数运行结果。
  • 懒编译:例如,如果访问 localhost:3000,它将仅打包 pages/index.jsx,以及导入的模块。

为什么不选择 Vite 和 Esbuild?

Vite 依赖于浏览器的原生 ES Modules 系统,不需要打包代码,这种方法只需要转换单个 JS 文件,响应更新很快,但是如果文件过多,这种方式会导致浏览器大量级联网络请求,会导致启动时间相对较慢。所以作者选择同 webpack 一样方式,打包,但是使用了 Turbo 构建引擎,一个增量记忆化框架,永远不会重复相同的工作。

Esbuild 是一个非常快速的打包工具,但它并没有做太多的缓存,也没有 HMR(热更新),所以在开发环境下不适用。

你好,Next.js 13

theme: vuepress highlight: monokai文章为稀土掘金技术社区首发签约文章,14 天内禁止转载,14 天后未获授权禁止转载,侵权必究!前言上周发布了 Next.js 的一个...

百度天工:人工智能赋能产业升级与创新发展

百度天工:人工智能赋能产业升级与创新发展

  随着人工智能技术的快速发展和应用,百度天工作为积极推动智能产业发展的先行者,致力于将人工智能赋能各行各业,推动产业升级与创新发展。百度天工的出现极大地丰富和拓展了人工智能...

删除所有对象中的物体

删除所有对象中的物体截图

将 glb 文件导入 blender

将 glb 文件导入 blender截图

将 glb 文件导入 blender第二步截图

选择您的模型,然后单击 Import glTF 2.0

选择模型导入截图

如何使用 react 和 three.js 在网站渲染自己的3D模型

哈喽,大家好,我是Ai知识分享,今天翻译一篇文章 《How to Use Three.js And React to Render a 3D Model of Your Self》,内容是当下最流行的...

AI技术在教育中的应用及未来发展趋势

AI技术在教育中的应用及未来发展趋势

  随着人工智能技术的飞速发展,AI教育已成为现代教育中备受瞩目的话题。AI技术授课已逐渐成为学校教育的走向,其优势所在,不仅能够提高教学效率,还能够帮助学生更好地理解知识并...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。