Integration of Express with front-end frameworks
Integration Methods Between Express and Frontend Frameworks
Express, as a lightweight Node.js web framework, is often used in conjunction with frontend frameworks like React, Vue, or Angular. There are two main integration approaches: Server-Side Rendering (SSR) and the frontend-backend separation development model. SSR is implemented through template engines (e.g., EJS, Pug) or framework-specific solutions (e.g., Next.js), while in the separation model, Express only provides API interfaces.
Server-Side Rendering (SSR) Integration
Using Template Engines
Express natively supports template engines, such as rendering dynamic pages with EJS:
// app.js
const express = require('express');
const app = express();
app.set('view engine', 'ejs');
app.get('/', (req, res) => {
res.render('index', { title: 'Express + EJS' });
});
app.listen(3000);
Corresponding EJS template file:
<!-- views/index.ejs -->
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h1><%= title %></h1>
</body>
</html>
Integration with Next.js
For React projects, you can extend Next.js with a custom Express server:
// server.js
const express = require('express');
const next = require('next');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
server.get('/custom-route', (req, res) => {
return app.render(req, res, '/custom-page', req.query);
});
server.all('*', (req, res) => {
return handle(req, res);
});
server.listen(3000);
});
Frontend-Backend Separation Mode
Basic REST API Configuration
When Express serves as a pure backend service, CORS and JSON parsing need to be configured:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.use(express.json());
app.get('/api/data', (req, res) => {
res.json({ items: [{ id: 1, name: 'Item 1' }] });
});
app.listen(3001);
Frontend fetch call example:
fetch('http://localhost:3001/api/data')
.then(response => response.json())
.then(data => console.log(data));
File Upload Integration
Handling file uploads with multer:
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
app.post('/upload', upload.single('file'), (req, res) => {
console.log(req.file);
res.status(200).send('Uploaded');
});
Frontend upload component example (React):
function Uploader() {
const handleSubmit = (e) => {
e.preventDefault();
const formData = new FormData();
formData.append('file', e.target.files[0]);
fetch('/upload', {
method: 'POST',
body: formData
});
};
return <input type="file" onChange={handleSubmit} />;
}
Real-Time Communication Solutions
WebSocket Integration
Creating a real-time service with the ws library:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
ws.on('message', (message) => {
wss.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
});
});
Frontend connection example:
const socket = new WebSocket('ws://localhost:8080');
socket.addEventListener('message', (event) => {
console.log('Received:', event.data);
});
Deep Integration with Socket.IO
Combining Express with Socket.IO to implement namespaces:
const io = require('socket.io')(server);
io.of('/chat').on('connection', (socket) => {
socket.on('new-message', (msg) => {
io.of('/chat').emit('message', msg);
});
});
Corresponding React component:
useEffect(() => {
const socket = io('http://localhost:3000/chat');
socket.on('message', (msg) => {
setMessages(prev => [...prev, msg]);
});
return () => socket.disconnect();
}, []);
Static Resource Hosting
Production Environment Deployment Configuration
Hosting frontend build artifacts with Express:
const path = require('path');
app.use(express.static(path.join(__dirname, 'client/build')));
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
});
Development Environment Proxy Settings
Configuring http-proxy-middleware to resolve cross-origin issues:
const { createProxyMiddleware } = require('http-proxy-middleware');
app.use('/api', createProxyMiddleware({
target: 'http://localhost:3001',
changeOrigin: true
}));
Corresponding Vue configuration (vue.config.js):
module.exports = {
devServer: {
proxy: 'http://localhost:3000'
}
}
Authentication Integration Solutions
JWT Authentication Implementation
Generating JWT tokens with Express:
const jwt = require('jsonwebtoken');
app.post('/login', (req, res) => {
const token = jwt.sign({ userId: 123 }, 'secret', { expiresIn: '1h' });
res.json({ token });
});
Frontend axios interceptor configuration:
axios.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) config.headers.Authorization = `Bearer ${token}`;
return config;
});
OAuth2.0 Integration
Implementing GitHub authentication with Passport:
const passport = require('passport');
const GitHubStrategy = require('passport-github').Strategy;
passport.use(new GitHubStrategy({
clientID: GITHUB_CLIENT_ID,
clientSecret: GITHUB_CLIENT_SECRET,
callbackURL: "http://localhost:3000/auth/github/callback"
}, (accessToken, refreshToken, profile, done) => {
return done(null, profile);
}));
app.get('/auth/github', passport.authenticate('github'));
app.get('/auth/github/callback',
passport.authenticate('github', { failureRedirect: '/login' }),
(req, res) => res.redirect('/')
);
Performance Optimization Strategies
Server-Side Caching Configuration
Enabling Redis caching for API responses:
const redis = require('redis');
const client = redis.createClient();
function cacheMiddleware(req, res, next) {
const key = req.originalUrl;
client.get(key, (err, data) => {
if (data) return res.json(JSON.parse(data));
next();
});
}
app.get('/heavy-route', cacheMiddleware, (req, res) => {
// Time-consuming operation
const result = { data: '...' };
client.setex(req.originalUrl, 3600, JSON.stringify(result));
res.json(result);
});
Static Resource Compression
Enabling gzip compression:
const compression = require('compression');
app.use(compression({ level: 6 }));
Error Handling Mechanisms
Unified Error Handling Middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
error: process.env.NODE_ENV === 'development' ?
err.message : 'Internal Error'
});
});
Frontend Error Catching
React error boundary example:
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
fetch('/api/log-error', {
method: 'POST',
body: JSON.stringify({ error, info })
});
}
render() {
return this.state.hasError
? <div>Error occurred</div>
: this.props.children;
}
}
Micro-Frontend Architecture Support
Module Federation Integration
Providing remote entry points for Module Federation via Express:
app.get('/remoteEntry.js', (req, res) => {
res.sendFile(path.resolve(__dirname, 'dist/remoteEntry.js'));
});
Webpack configuration example:
// webpack.config.js
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'host',
remotes: {
remoteApp: 'remoteApp@http://localhost:3001/remoteEntry.js'
}
})
]
}
Testing Strategy Implementation
API Testing Solution
Testing Express routes with Jest:
const request = require('supertest');
const app = require('../app');
describe('GET /api/users', () => {
it('responds with JSON', async () => {
const response = await request(app)
.get('/api/users')
.expect('Content-Type', /json/)
.expect(200);
expect(response.body).toHaveProperty('users');
});
});
E2E Testing Configuration
Full-stack testing with Cypress:
// cypress/integration/api.spec.js
describe('API Tests', () => {
it('creates new item', () => {
cy.request('POST', '/api/items', { name: 'Test' })
.its('body')
.should('include', { id: 1 });
});
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:常用插件与扩展库介绍