最近这几天看到前端的项目都需要启动一个服务,并且监听一个端口(3000)。好像之前一开始学习时,前端还只是静态网页,打开浏览器就能够访问了。而现在的这种变化原理是什么呢?这让我比较好奇,所以就打算探索一下
为什么需要服务器
在很早之前,大家都是直接编写HTML、CSS、JavaScript文件,使用 file://协议打开本地文件 , 浏览器可以直接解析和运行。而现在各种框架的出现,改变了前端项目开发的环境。
现在项目大部分都使用JSX语法,浏览器无法直接理解,如下所示:
javascript
// JSX (浏览器不认识)
const App = () => <div>Hello World</div>;
// 需要转换成普通JavaScript
const App = () => React.createElement('div', null, 'Hello World');
除此之外,现代前端项目大都使用 ES6 模块, CommonJS
等,比如:
javascript
import React from 'react';
import './App.css';
浏览器需要特殊处理这些导入语句。
开发服务器的作用
现在的前端启动的一个服务,主要的作用就是向前端发送 html,css,js 文件,因为这些文件可能需要转换。现代前端开发服务器本质上就是一个文件服务器 + 实时编译器,主要工作就是:
1. 接收浏览器请求 → 转换文件 → 返回标准文件
makefile
浏览器请求: GET /app.js
↓
开发服务器: 读取 app.jsx → 编译成 app.js → 返回给浏览器
2. 实际的转换过程
原始文件(需要转换):
.jsx
→.js
.tsx
→.js
.scss/.less
→.css
.vue
→.js + .css
- ES6 modules → 浏览器兼容的模块
最终返回给浏览器的:
- 标准的 HTML
- 标准的 CSS
- 标准的 JavaScript
3. 简化理解
可以把开发服务器想象成一个"实时翻译器":
arduino
浏览器说:"我要 main.js"
服务器想:"让我把 main.jsx 翻译一下..."
服务器说:"给你标准的 main.js"
4. 为什么需要这个服务?
因为我们写的代码:
jsx
// 我们写的 (main.jsx)
import React from 'react';
const App = () => <div>Hello</div>;
浏览器需要的:
jsx
// 浏览器能懂的 (main.js)
const React = require('react');
const App = () => React.createElement('div', null, 'Hello');
开发服务器就像一个"智能文件服务器",它不只是简单地发送文件,还会根据浏览器的请求实时转换文件格式,确保浏览器收到的都是它能理解的标准Web文件。
开发环境 VS 生产环境
上面的这部分主要还是针对开发环境,但是在生产环境则又有所不同了,如下:
markdown
# 开发环境
浏览器 → 开发服务器 → 实时转换 → 返回文件
- 需要启动服务器
- 实时编译转换
- 文件分散存储
# 生产环境
打包构建 → 生成静态文件 → 直接部署
也就是说,前端项目在发布到生产环境中前,还是需要转换。通过打包构建的方式,将所有的开发环境的文件打包成只有 html,css,js
的静态文件,生成的文件结构具体如下:
csharp
build/
├── index.html # 入口HTML文件
├── static/
│ ├── css/
│ │ └── main.abc123.css # 已编译的CSS
│ └── js/
│ ├── main.def456.js # 已编译的JS
│ └── chunk.789xyz.js # 代码分割的文件
└── favicon.ico
这样的静态文件就和最开始开发前端项目的类似了。打包后的文件可以直接放到任何Web服务器:
- Nginx:直接serve静态文件
- Apache:配置静态文件目录
- CDN:上传到阿里云OSS、AWS S3等
- GitHub Pages:直接托管静态文件
访问方式也更加的简单了:
css
用户浏览器 → Web服务器(Nginx) → 直接返回静态HTML/CSS/JS
也可以再添加 nginx
配置:
bash
server {
listen 80;
server_name example.com;
root /var/www/build;
location / {
try_files $uri $uri/ /index.html;
}
}
打包后就是传统的静态网站了!所有的JSX、TypeScript、SCSS都已经转换成了浏览器能直接理解的HTML、CSS、JavaScript文件,可以部署到任何静态Web服务器上,不再需要Node.js环境。
Docker 环境
在 Docker 环境中,前端项发布的容器还是一个 server
,具体原因如下:
- 隔离性:容器是独立环境,必须通过端口通信
- 访问性:外界需要通过端口映射访问服务
- 一致性 :无论静态还是动态应用,都需要Web服务器 即使是静态文件,在Docker中也需要Nginx或类似服务器来监听端口并提供HTTP服务。这与传统静态部署(直接放到已有的Web服务器目录)不同。一般的
Dockerfile
如下:
bash
# 多阶段构建
FROM node:16 AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 生产阶段
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
# Nginx监听80端口
更加清晰的表达,就是在镜像中有一个 web
服务器,一般就是 nginx
,具体流程如下:
用户请求 → Docker宿主机:8080 → 容器内Nginx:80 → 静态文件 → 返回
总之,无论是传统部署还是容器化部署,都需要这样一个"中间人"(Web服务器)来让浏览器能够通过HTTP协议访问到静态文件