I deployed my NextJS app as a static website on my own server and it's working well. Except that if I try to access a page that is not the main page through typing the url in the browser, I get a 404. (When I come from the navigation within the app, it's working though!)
As far as I know, to create the paths I need, I just create a .js in the pages folder. This doesn't seem to be enough though?
Does it have anything to do with the process.env.BASE_URL? Or with any router?
Here's one of my files in the pages folder:
import { Fragment, Suspense } from 'react';
import dynamic from 'next/dynamic';
import Loading from '../components/shared/Loading';
import SeoHead from '../components/SeoHead';
import myIMG from '../images/header_myimg.jpg';
const ThemeContent = dynamic(() => import('../components/ThemeContent'));
const ContentXYZ = dynamic(() => import('../components/ContentXYZ'));
const Contact = dynamic(() => import('../components/Contact'));
export default function Sucht(){
return (
<Fragment>
<SeoHead
title="xyz"
description="xyz"
url="/my-url"
/>
<Suspense fallback={<Loading/>}>
<ThemeContent
titleColor="darkblue"
image={myIMG}
imgAlt="xyz"
title="xyz"
subtitle="xyz"
text={<ContentXYZ/>}
/>
<Contact/>
</Suspense>
</Fragment>
);
}
And here is my next.config.js
/** #type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: false,
env:{
BASE_URL: process.env.BASE_URL
},
experimental: {
images: {
layoutRaw: true,
deviceSizes: [320, 380, 500, 750, 1000, 1200, 1450],
formats: ['image/webp'],
loader: "custom"
}
}
}
module.exports = nextConfig
Would you need anything else? I'm sure this is something easy... I really appreciate your help!
(I saw that this question has been asked already but it seems to me they didn't have a static website and didn't host it on their own server. So the answers didn't really fit to my problem?)
I found a solution! I put a .htaccess in the public-folder! I wrote this in the file:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.html [NC,L]
Related
Code
Full codebase & folder structure can be seen in GitHub
Here is the Swagger related route (had to make it a standalone server)
// api/v1.ts
import express = require("express");
import swaggerJSDoc = require("swagger-jsdoc");
import swaggerUi = require("swagger-ui-express");
import packageJSON = require("../package.json");
import path = require("path");
const app = express();
app.use(express.json());
app.use(express.static(path.resolve(__dirname, "../", "public")));
const swaggerSpec = swaggerJSDoc({
swaggerDefinition: some_spec,
apis: ["api/*"]
});
const cssOpts = some_css_override;
app.use("/api/v1", swaggerUi.serve, swaggerUi.setup(swaggerSpec, cssOpts));
module.exports = app;
Problem
When I run vercel dev (locally- localhost:3000/api/v1), I see documentation as expected:
However when I push my code to a branch which triggers a vercel build, I see the following:
Checking the console, I see:
DevTools failed to load source map: Could not parse content for https://colormaster-1unjfn63b-lbragile.vercel.app/api/v1/swagger-ui-bundle.js.map: Unexpected token < in JSON at position 1
DevTools failed to load source map: Could not parse content for https://colormaster-1unjfn63b-lbragile.vercel.app/api/v1/swagger-ui-standalone-preset.js.map: Unexpected token < in JSON at position 1
Even though they respond with 200
I understand that this has something to do with JSON.parse() of HTML content, but not sure how to fix this. Any ideas?
I am facing the exact same problem of you, trying without success to deploy Swagger to Vercel with Express.
I did one step more, and now I'm seen an error in my console:
Refused to apply style from
'https://myurlishere.vercel.app/api-docs/swagger-ui.css' because its
MIME type ('text/html') is not a supported stylesheet MIME type, and
strict MIME checking is enabled.
What I did was, adding a file routes.ts
import { Router } from 'express';
import LanguageController from './controller/LanguageController';
import WordController from './controller/WordController';
const routes = Router();
routes.get("/word", WordController.find);
routes.get("/word/:wordName/language/:languageId", WordController.findByWordAndLanguage);
routes.post("/word", WordController.create);
routes.get("/language", LanguageController.find);
export default routes;
And my server.ts looks like that:
import mongoose from 'mongoose';
import routes from './routes';
const express = require("express");
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config();
}
const app = express();
const cors = require('cors');
mongoose.connect(process.env.MONGODB_URI || "", {
dbName: "WordsThatIKnowMongoDB"
})
.then(() => console.debug("Database connected!"))
.catch(err => { console.debug(err) });
app.use(express.json());
app.use(express.static("/api-docs"));
app.use(cors());
app.use(routes);
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json');
routes.use('/api-docs', swaggerUi.serve);
routes.get('/api-docs', swaggerUi.setup(swaggerDocument));
app.listen(5000, () => {
console.debug("Running on port 5000.");
});
// Export the Express API
module.exports = app;
You will see in the file above that I changed app. to routes. like this:
routes.use('/api-docs', swaggerUi.serve);
routes.get('/api-docs', swaggerUi.setup(swaggerDocument));
I still can't solve this problem, but maybe this new error can help you find the solution. I'm also looking for that.
EDIT: It's solved.
This is the code that solved my problem:
server.ts
import path from 'path';
import cors from 'cors';
import bodyParser from 'body-parser';
import mongoose from 'mongoose';
import routes from './routes';
const express = require("express");
const app = express();
const ROOT_FOLDER = path.join(__dirname, '..');
const SRC_FOLDER = path.join(ROOT_FOLDER, 'src');
// parse requests of content-type - application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));
// parse requests of content-type - application/json
app.use(bodyParser.json());
app.use(cors());
app.use(routes);
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config();
}
mongoose.connect(process.env.MONGODB_URI || "", {
dbName: "WordsThatIKnowMongoDB"
})
.then(() => console.debug("Database connected!"))
.catch(err => { console.debug(err) });
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json');
const options = { customCssUrl: '/public/swagger-ui.css', customSiteTitle: "The Words That I Know API - Swagger" };
app.use('/public', express.static(path.join(SRC_FOLDER, 'public')));
app.use('/', swaggerUi.serve);
app.get('/', swaggerUi.setup(swaggerDocument, options));
app.listen(5000, () => {
console.debug("Running on port 5000.");
});
export default app;
Don't forget to put the styles from Swagger at '/public/swagger-ui.css'. Create a public folder inside src and include a swagger-ui.css file. Inside of this, past swagger styles. You can find swagger styles using inspect on browser, and going to source tab. There you'll find the swagger-ui.css file; remove the commented line after pasting the styles code.
If you prefer an easy way to get the styles code, get this file. https://github.com/deywersonp/ghibli-50-api/blob/main/src/public/css/swagger-ui.css
hey I got the same problem ! the solution I use isn't optimal but it worked
knowing the css file is been wel process localy,all i did is to add custom css to my swagger-ui documentation. so as the css is working localy I copied all the css ( inspected web browser saw the file swagger-ui.css file source code ) , created a css file , paste the css to it , then i added my css file to my static folder.
here is how to add costum css
const options = { customCssUrl: '/public/css/swagger-ui.css',};
router.use('/api-docs-ui', function(req, res, next){
swaggerDocument.host = req.get('host');
req.swaggerDoc = swaggerDocument;
next();
}, swaggerUi.serve, swaggerUi.setup(swaggerDocument, options));
here is how you define your statics files
app.use('/public/css', express.static('public/css'));
so now localy I have 2 css file working but on vercel just one is working!
hope it could help
Also you can use a CDN for you Swagger styles if you don't wont to put the css files into your public folder.
I installed TYPO3 v10.4.9 with boostrap package and created a few custom pages to try things out. I noticed that the "speaking URLs" are not working and I have no idea why. Note that I am a total bigginer in TYPO3, so I'm probably missing something obvious.
Example:
We have a page called Photos. The URL created by "URL Segment" in Page module > "Edit page properties" is https://example.com/photos and the ID of the page is 84.
If I click on the view icon in the Page module, URL https://example.com/photos opens in the frontend and I get a message that says "Not Found - The requested URL was not found on this server".
On the other hand, if I type URL with ID in the browser manually, like so: https://example.com/index.php?id=84, it works perfectly fine. This problem is present for every page I create.
I have created site configuration. Below is the content of config.yaml:
base: 'https://example.com'
baseVariants: { }
errorHandling: { }
languages:
title: 'Example Site'
enabled: true
base: /
typo3Language: default
locale: en_US.UTF-8
iso-639-1: en
websiteTitle: ''
navigationTitle: English
hreflang: en-US
direction: ''
flag: us
languageId: '0'
rootPageId: 1
routes: { }
websiteTitle: ''
.htaccess
AddHandler application/x-httpd-php74 .php
##__HCP_END__##
# Anything after the comment above is left alone
Please help. What am I missing here?
If I should paste some more data to help resolve the problem, please let me know. Thank you in advance.
I found a solution. I copied contents of
https://github.com/TYPO3/TYPO3.CMS/blob/master/typo3/sysext/install/Resources/Private/FolderStructureTemplateFiles/root-htaccess
to .htaccess and now it works perfectly.
Maybe the .htaccess is missing in the root of your installation.
I am trying to create a Browsersync middleware to replace a string in HTML files before they are served to the browser.
I'm not entirely sure this is even possible.
So far I am able to identify when a HTML file is being requested by:
function hublMiddleware (req, res, next) {
var parsed = require("url").parse(req.url);
if (parsed.pathname.match(/\.html$/)) {}
next();
};
I can put a console.log() inside the if statement so I know it's working.
But from here I am genuinely stuck. I have searched for examples of how this may be done, e.g.
res.removeHeader('Content-Length');
res.pipe($.replace(/({{\s|\s}})|({%.*%})/g, '<!---->'))
.pipe(res);
return next();
But to no avail.
I should say I am using Browsersync with Gulp. Any help with this would be much appreciated!
This one does exactly what you want:
bs-rewrite-rules
Here's how I used it:
gulp.task('serve', function () {
browserSync({
port: 8000,
server: {
baseDir: './'
},
plugins: ['bs-rewrite-rules'],
rewriteRules: [
{
match: 'YOUR_GOOGLE_MAPS_API_KEY',
replace:'<MY_ACTUAL_API_KEY>'
}
]
});
gulp.watch(['*.html', 'css/**/*.css', 'js/**/*.js'], reload);
});
using nodejs and swagger-tools v0.8.7 to route endpoints.
"basePath": "/api/myapi" in the api/myapi.json works great, ie: GET, POST, etc... at http://localhost:3000/api/myapi works.
But I still have to access http://localhost:3000/docs/ to get at the UI tool. How can I serve this from http://localhost:3000/api/myapi/docs/ ?
Same question for serving the yaml at /api/myapy/api-docs instead of /api-docs.
Thx.
got what i wanted via:
app.use(middleware.swaggerRouter(
{
swaggerUi: '/myapi.json',
controllers: './lib'
}));
app.use(middleware.swaggerUi(
{
"apiDocs": "/myapi/api",
"swaggerUi": "/myapi.json"
}
));
i'm creating a drupal site that should include a feature that will turn a clean url into a a url with a query string.
The way it should work would be:
user would type any clean url like www.example.com/hobbies/skiing in the url bar.
here is my problem:
inside the .htaccess i've put this line of code:
RewriteRule ^hobbies/([a-zA-Z0-9-]*) /index.php?hobbies=$1 [NC]
in the drupal, i've created a page with PHP Filter enabled, then typed in
<?PHP echo $_GET['hobbies']; ?>
the RewriteRule should turn www.example.com/hobbies/skiing into www.example.com/index.php?hobbies=skiing but i guess the code doesn't work as expected, or drupal has codes running that either skips the .htaccess command or something.
3.once the url has been translated into a dirty url, the page will display what the value of hobbies is, as the code works when you actually type www.example.com/index.php?hobbies=skiing directly into the url bar.
can you help me with this one?
There's a far easier way to do it, Drupal already keeps path parts aside for later which you can access using the arg() function:
if (arg(0) == 'hobbies' && arg(1)) {
$hobby = arg(1);
}
If your path is an alias though arg() will return the original router path (node/1 etc.) so you'll have to be a bit more inventive:
$parts = explode('/', $_SERVER['REQUEST_URI']);
if ($parts[1] == 'hobbies' && isset($parts[2])) {
$hobby = $parts[2];
}
UPDATE
From your comments you'd be better off making a quick custom module for this:
// Implements hook_menu().
function mymodule_menu() {
$items['hobbies/%'] = array(
'title' => 'A title',
'access arguments' => array('access content'),
'page callback' => 'mymodule_page',
'page arguments' => array(1)
);
return $items;
}
function mymodule_page($hobby) {
return $hobby;
}
That will literally print out what ever is after hobbies/ in the content area of the page