1. Pengantar Platform eCommerce MERN
MERN adalah singkatan dari MongoDB, Express, React, dan Node.js — stack teknologi populer untuk membangun aplikasi web fullstack modern. Dalam panduan ini, Anda akan belajar membangun platform eCommerce lengkap dari awal menggunakan MERN stack dengan praktik terbaik tahun 2023.
Platform ini akan mencakup fitur penting seperti katalog produk, keranjang belanja, autentikasi user, dan integrasi pembayaran.
2. Teknologi MERN Stack
- MongoDB: Database NoSQL berbasis dokumen yang scalable.
- Express.js: Framework backend minimalis untuk Node.js.
- React.js: Library frontend untuk membangun UI interaktif.
- Node.js: Runtime JavaScript untuk backend server.
3. Struktur Proyek eCommerce
Struktur proyek MERN yang direkomendasikan:
ecommerce-platform/
├── backend/
│ ├── controllers/
│ ├── models/
│ ├── routes/
│ ├── middleware/
│ ├── config/
│ ├── server.js
│ └── package.json
├── frontend/
│ ├── public/
│ ├── src/
│ │ ├── components/
│ │ ├── features/
│ │ ├── pages/
│ │ ├── store/
│ │ ├── App.jsx
│ │ └── index.jsx
│ └── package.json
└── README.md
4. Setup Lingkungan Pengembangan
Pastikan Node.js dan MongoDB sudah terinstall. Buat folder proyek dan inisialisasi backend dan frontend:
mkdir ecommerce-platform
cd ecommerce-platform
# Setup backend
mkdir backend
cd backend
npm init -y
npm install express mongoose dotenv cors jsonwebtoken bcryptjs
# Setup frontend
cd ..
npx create-react-app frontend
cd frontend
npm install react-router-dom @reduxjs/toolkit react-redux axios tailwindcss postcss autoprefixer
npx tailwindcss init -p
5. Membangun Backend dengan Node.js & Express
Buat server Express sederhana di server.js
:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.use(express.json());
app.get('/', (req, res) => {
res.send('API eCommerce berjalan!');
});
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server berjalan di port ${PORT}`));
6. Database MongoDB & Mongoose
Buat koneksi MongoDB dan model produk:
// config/db.js
const mongoose = require('mongoose');
const connectDB = async () => {
try {
await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
console.log('MongoDB connected');
} catch (error) {
console.error(error);
process.exit(1);
}
};
module.exports = connectDB;
// models/Product.js
const mongoose = require('mongoose');
const productSchema = new mongoose.Schema({
name: { type: String, required: true },
description: String,
price: { type: Number, required: true },
countInStock: { type: Number, required: true, default: 0 },
imageUrl: String,
}, { timestamps: true });
module.exports = mongoose.model('Product', productSchema);
7. Autentikasi & Authorization dengan JWT
Implementasi autentikasi user menggunakan JWT dan bcryptjs untuk hashing password.
// controllers/authController.js
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const User = require('../models/User');
exports.register = async (req, res) => {
const { name, email, password } = req.body;
const hashedPassword = await bcrypt.hash(password, 10);
const user = new User({ name, email, password: hashedPassword });
await user.save();
res.status(201).json({ message: 'User registered' });
};
exports.login = async (req, res) => {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user) return res.status(400).json({ message: 'User not found' });
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) return res.status(400).json({ message: 'Invalid credentials' });
const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '1d' });
res.json({ token });
};
8. Membangun Frontend dengan React
Buat halaman utama dan komponen produk sederhana:
// src/components/ProductCard.jsx
export default function ProductCard({ product }) {
return (
<div className="border rounded p-4 shadow-sm">
<img src={product.imageUrl} alt={product.name} className="w-full h-48 object-cover mb-4 rounded" />
<h3 className="text-lg font-semibold mb-2">{product.name}</h3>
<p className="text-gray-700 mb-2">Rp {product.price.toLocaleString()}</p>
<button className="bg-indigo-600 text-white px-4 py-2 rounded hover:bg-indigo-700">Tambah ke Keranjang</button>
</div>
);
}
9. State Management dengan Redux Toolkit
Gunakan Redux Toolkit untuk mengelola state global seperti produk dan keranjang belanja.
// src/store/cartSlice.js
import { createSlice } from '@reduxjs/toolkit';
const cartSlice = createSlice({
name: 'cart',
initialState: { items: [] },
reducers: {
addItem: (state, action) => {
const item = action.payload;
const exist = state.items.find(i => i._id === item._id);
if (exist) {
exist.qty += 1;
} else {
state.items.push({ ...item, qty: 1 });
}
},
removeItem: (state, action) => {
state.items = state.items.filter(i => i._id !== action.payload);
},
},
});
export const { addItem, removeItem } = cartSlice.actions;
export default cartSlice.reducer;
10. Integrasi Frontend & Backend
Gunakan Axios untuk mengambil data produk dari backend dan menampilkannya di frontend.
// src/features/products/ProductList.jsx
import { useEffect, useState } from 'react';
import axios from 'axios';
import ProductCard from '../../components/ProductCard';
export default function ProductList() {
const [products, setProducts] = useState([]);
useEffect(() => {
axios.get('http://localhost:5000/api/products')
.then(res => setProducts(res.data))
.catch(err => console.error(err));
}, []);
return (
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
{products.map(product => (
<ProductCard key={product._id} product={product} />
))}
</div>
);
}
11. Testing & Debugging
Gunakan Jest dan React Testing Library untuk testing frontend, serta Mocha dan Chai untuk backend.
// Contoh test sederhana React
import { render, screen } from '@testing-library/react';
import ProductCard from '../components/ProductCard';
test('renders product name', () => {
const product = { name: 'Laptop', price: 10000, imageUrl: '' };
render(<ProductCard product={product} />);
expect(screen.getByText(/Laptop/i)).toBeInTheDocument();
});
12. Deployment & Best Practices
Deploy backend ke Heroku atau AWS, dan frontend ke Vercel atau Netlify. Gunakan environment variables dan HTTPS.
# Build frontend React
cd frontend
npm run build
# Deploy frontend ke Vercel
vercel --prod
# Deploy backend ke Heroku
cd ../backend
heroku create your-app-name
git push heroku main
heroku config:set MONGO_URI=your_mongodb_connection_string
heroku open
13. Source Code Contoh Lengkap
Berikut contoh potongan source code backend dan frontend yang bisa Anda gunakan sebagai referensi untuk membangun platform eCommerce MERN.
// backend/server.js
const express = require('express');
const cors = require('cors');
const mongoose = require('mongoose');
require('dotenv').config();
const app = express();
app.use(cors());
app.use(express.json());
mongoose.connect(process.env.MONGO_URI)
.then(() => console.log('MongoDB connected'))
.catch(err => console.error(err));
const productSchema = new mongoose.Schema({
name: String,
description: String,
price: Number,
countInStock: Number,
imageUrl: String,
}, { timestamps: true });
const Product = mongoose.model('Product', productSchema);
app.get('/api/products', async (req, res) => {
const products = await Product.find();
res.json(products);
});
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server berjalan di port ${PORT}`));
// frontend/src/components/ProductCard.jsx
export default function ProductCard({ product }) {
return (
<div className="border rounded p-4 shadow-sm">
<img src={product.imageUrl} alt={product.name} className="w-full h-48 object-cover mb-4 rounded" />
<h3 className="text-lg font-semibold mb-2">{product.name}</h3>
<p className="text-gray-700 mb-2">Rp {product.price.toLocaleString()}</p>
<button className="bg-indigo-600 text-white px-4 py-2 rounded hover:bg-indigo-700">Tambah ke Keranjang</button>
</div>
);
}
14. Referensi & Channel Pembelajaran