feat: add proxy middleware for API requests and create production Docker Compose setup
This commit is contained in:
16
.eleventy.js
16
.eleventy.js
@@ -1,4 +1,5 @@
|
|||||||
module.exports = function(eleventyConfig) {
|
module.exports = function(eleventyConfig) {
|
||||||
|
const { createProxyMiddleware } = require('http-proxy-middleware');
|
||||||
|
|
||||||
// Pass through static assets from the "src" directory
|
// Pass through static assets from the "src" directory
|
||||||
eleventyConfig.addPassthroughCopy("src/css");
|
eleventyConfig.addPassthroughCopy("src/css");
|
||||||
@@ -42,6 +43,21 @@ module.exports = function(eleventyConfig) {
|
|||||||
// Add a shortcode for the current year for the footer
|
// Add a shortcode for the current year for the footer
|
||||||
eleventyConfig.addShortcode("year", () => `${new Date().getFullYear()}`);
|
eleventyConfig.addShortcode("year", () => `${new Date().getFullYear()}`);
|
||||||
|
|
||||||
|
// Only add the proxy middleware when in serve mode
|
||||||
|
if (process.env.ELEVENTY_RUN_MODE === "serve") {
|
||||||
|
// Dev server options
|
||||||
|
eleventyConfig.setServerOptions({
|
||||||
|
// When the site is served by Eleventy's dev server, proxy API requests
|
||||||
|
// to the API server which is running in a separate container.
|
||||||
|
middleware: [
|
||||||
|
createProxyMiddleware('/api', {
|
||||||
|
target: 'http://api:3000', // The 'api' service container
|
||||||
|
changeOrigin: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// Set the source and output directories
|
// Set the source and output directories
|
||||||
dir: {
|
dir: {
|
||||||
|
20
docker-compose.prod.yml
Normal file
20
docker-compose.prod.yml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# docker-compose.prod.yml for production
|
||||||
|
# This setup builds and runs the optimized production image.
|
||||||
|
#
|
||||||
|
# To start, run: docker-compose -f docker-compose.prod.yml up --build
|
||||||
|
#
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
target: production # Use the 'production' stage from the Dockerfile
|
||||||
|
container_name: eleventy_prod
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
volumes:
|
||||||
|
# Persist the view count data in a named volume.
|
||||||
|
- views_data:/app/_data
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
views_data:
|
103
package-lock.json
generated
103
package-lock.json
generated
@@ -12,7 +12,8 @@
|
|||||||
"@11ty/eleventy": "^2.0.1",
|
"@11ty/eleventy": "^2.0.1",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"express": "^4.21.2",
|
"express": "^4.21.2",
|
||||||
"fs-extra": "^11.3.1"
|
"fs-extra": "^11.3.1",
|
||||||
|
"nodemon": "^3.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@11ty/dependency-tree": {
|
"node_modules/@11ty/dependency-tree": {
|
||||||
@@ -1190,6 +1191,14 @@
|
|||||||
"uglify-js": "^3.1.4"
|
"uglify-js": "^3.1.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/has-flag": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/has-symbols": {
|
"node_modules/has-symbols": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||||
@@ -1278,6 +1287,11 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ignore-by-default": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA=="
|
||||||
|
},
|
||||||
"node_modules/inflight": {
|
"node_modules/inflight": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||||
@@ -1846,6 +1860,53 @@
|
|||||||
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
|
||||||
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
|
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/nodemon": {
|
||||||
|
"version": "3.1.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz",
|
||||||
|
"integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==",
|
||||||
|
"dependencies": {
|
||||||
|
"chokidar": "^3.5.2",
|
||||||
|
"debug": "^4",
|
||||||
|
"ignore-by-default": "^1.0.1",
|
||||||
|
"minimatch": "^3.1.2",
|
||||||
|
"pstree.remy": "^1.1.8",
|
||||||
|
"semver": "^7.5.3",
|
||||||
|
"simple-update-notifier": "^2.0.0",
|
||||||
|
"supports-color": "^5.5.0",
|
||||||
|
"touch": "^3.1.0",
|
||||||
|
"undefsafe": "^2.0.5"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"nodemon": "bin/nodemon.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/nodemon"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nodemon/node_modules/brace-expansion": {
|
||||||
|
"version": "1.1.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||||
|
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||||
|
"dependencies": {
|
||||||
|
"balanced-match": "^1.0.0",
|
||||||
|
"concat-map": "0.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nodemon/node_modules/minimatch": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||||
|
"dependencies": {
|
||||||
|
"brace-expansion": "^1.1.7"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/normalize-path": {
|
"node_modules/normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||||
@@ -2076,6 +2137,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
|
||||||
"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw=="
|
"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/pstree.remy": {
|
||||||
|
"version": "1.1.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
|
||||||
|
"integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w=="
|
||||||
|
},
|
||||||
"node_modules/pug": {
|
"node_modules/pug": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/pug/-/pug-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/pug/-/pug-3.0.3.tgz",
|
||||||
@@ -2545,6 +2611,17 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/simple-update-notifier": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
|
||||||
|
"dependencies": {
|
||||||
|
"semver": "^7.5.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/slash": {
|
"node_modules/slash": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
|
||||||
@@ -2601,6 +2678,17 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/supports-color": {
|
||||||
|
"version": "5.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||||
|
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||||
|
"dependencies": {
|
||||||
|
"has-flag": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/supports-preserve-symlinks-flag": {
|
"node_modules/supports-preserve-symlinks-flag": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||||
@@ -2636,6 +2724,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz",
|
||||||
"integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg=="
|
"integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/touch": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
|
||||||
|
"bin": {
|
||||||
|
"nodetouch": "bin/nodetouch.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/type-is": {
|
"node_modules/type-is": {
|
||||||
"version": "1.6.18",
|
"version": "1.6.18",
|
||||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||||
@@ -2665,6 +2761,11 @@
|
|||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/undefsafe": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA=="
|
||||||
|
},
|
||||||
"node_modules/universalify": {
|
"node_modules/universalify": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"express": "^4.21.2",
|
"express": "^4.21.2",
|
||||||
"fs-extra": "^11.3.1",
|
"fs-extra": "^11.3.1",
|
||||||
"nodemon": "^3.1.0"
|
"nodemon": "^3.1.0",
|
||||||
|
"http-proxy-middleware": "^3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,12 +3,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
if (viewCountElement) {
|
if (viewCountElement) {
|
||||||
const slug = viewCountElement.dataset.slug;
|
const slug = viewCountElement.dataset.slug;
|
||||||
const serverUrl = 'http://localhost:3000'; // IMPORTANT: Replace with your server's IP/domain
|
|
||||||
|
|
||||||
// Function to fetch and display the view count
|
// Function to fetch and display the view count
|
||||||
const getViews = async () => {
|
const getViews = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${serverUrl}/api/views/${slug}`);
|
const response = await fetch(`/api/views/${slug}`);
|
||||||
if (!response.ok) throw new Error('Failed to fetch views');
|
if (!response.ok) throw new Error('Failed to fetch views');
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
viewCountElement.textContent = `${data.count} views`;
|
viewCountElement.textContent = `${data.count} views`;
|
||||||
@@ -24,7 +23,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
// Use a flag in localStorage to prevent incrementing on every refresh
|
// Use a flag in localStorage to prevent incrementing on every refresh
|
||||||
const viewed = localStorage.getItem(`viewed-${slug}`);
|
const viewed = localStorage.getItem(`viewed-${slug}`);
|
||||||
if (!viewed) {
|
if (!viewed) {
|
||||||
await fetch(`${serverUrl}/api/views/${slug}`, { method: 'POST' });
|
await fetch(`/api/views/${slug}`, { method: 'POST' });
|
||||||
localStorage.setItem(`viewed-${slug}`, 'true');
|
localStorage.setItem(`viewed-${slug}`, 'true');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
Reference in New Issue
Block a user