阿里云主机折上折
  • 微信号
Current Site:Index > Integration of Express with front-end frameworks

Integration of Express with front-end frameworks

Author:Chuan Chen 阅读数:30054人阅读 分类: Node.js

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

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.