How to change base path for assets, images, etc - next.js

I need my app to work well on a subfolder of the main domain. Exactly here
At first I had a plenty of errors of scripts, css and images not being loaded.
I added the following to next.config.js:
basePath: "/out",
Now scripts and css are working well when exported, they have the /out/ in the path.
However the files do not have yet the /out/ in the path, thus they are giving 404 errors.
I tried to follow this tutorial, but it looks like I am still doing something wrong,
My next.config.js now is:
const path = require("path");
module.exports = {
trailingSlash: true,
sassOptions: {
includePaths: [path.join(__dirname, "styles")],
},
basePath: "/out",
assetPrefix: process.env.BASE_PATH || '',
publicRuntimeConfig: {
basePath: process.env.BASE_PATH || '',
},
};
The relevant piece of the package.json is:
"scripts": {
"dev": "node server.js -p $PORT",
"build": "next build",
"prod": "BASE_PATH=/out next build && next export",
"start": "NODE_ENV=production node server.js -p $PORT",
"start2": "next start"
},
The server.js is:
const express = require('express');
const next = require('next');
const path = require('path');
const bodyParser = require('body-parser');
const keys = require("./server/config/keys");
const stripe = require('stripe')(keys.stripeSecretKey);
const routes = require('./routes');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dir: '.', dev });
const handle = routes.getRequestHandler(app);
app.prepare().then(() => {
const server = express();
// Static files
// https://github.com/zeit/next.js/tree/4.2.3#user-content-static-file-serving-eg-images
server.use('/images', express.static(path.join(__dirname, 'images'), {
maxAge: dev ? '0' : '365d'
}));
server.use(bodyParser.json());
server.get('*', (req, res) => {
return handle(req, res)
});
server.post('/api/stripe/checkout', async (req, res) => {
await stripe.charges.create({
amount: req.body.amount,
currency: 'usd',
description: 'Mojosa - React Next Landing Page Templates',
source: req.body.token.id
});
res.send({})
});
const PORT = process.env.PORT || 3000;
server.listen(PORT, (err) => {
if (err) throw err
console.log(`> Read on http://localhost:${PORT}`)
});
})
And here is an example of an image in a component:
<div className="col-lg-6 col-md-12">
<div className="book-image">
<img src='/images/book-img.png' alt="image" />
</div>
With this configuration:
EXPORT - next build && next export on the /out/ folder are working well when uploaded to the live website, BUT images are giving 404
DEV or BUILD they are giving 404 and working much worse than the EXPORT site published on the real domain. If I remove basePath: "/out", the dev mode works excellent
Questions:
How can I make the /out/ path be added to all the images/assets?
I am ok to re-add basePath: "/out",` when exporting.

Just ran into this one too. You'll need to manually prefix anything in your public folder with your basePath (images, fonts etc)
Docs
"Files in the public folder; if you want to serve those assets over a CDN, you'll have to introduce the prefix yourself"
<div className="col-lg-6 col-md-12">
<div className="book-image">
<img src={`${process.env.BASE_PATH}/images/book-img.png`} alt="image" />
</div>

Related

A "routes-manifest.json" couldn't be found

I'm following this tutorial so that I generate a static file during the vercel build. I've tried moving the files around but it always shows a log like:
23:41:48.432 $ node ./pages/api/build.js 23:41:48.493 Build time file created successfully! 23:41:48.495 Done in 0.09s. 23:41:48.507 Error: A "routes-manifest.json" couldn't be found. This is normally caused by a misconfiguration in your project.
Then it links to this. I've checked the issues and everything seems to be fine.
If I remove the "vercel-build": "node ./pages/api/build.js" line from package.json, the error disappears. But also the functionality..
my pages/api/index.js file:
const BuiltTime = require('./built-time');
module.exports = (req, res) => {
res.setHeader('content-type', 'text/plain');
res.send(`
This Serverless Function was built at ${new Date(BuiltTime)}.
The current time is ${new Date()}
`);
};
my pages/build.js:
const fs = require('fs');
fs.writeFile(
'pages/api/built-time.js',
`module.exports = '${new Date()}'`,
(err) => {
if (err) throw err;
console.log('Build time file created successfully!');
}
);
my package.json:
{
...
"scripts":{
"vercel-build": "node ./pages/api/build.js",
}
}
In the end I didn't use "vercel-build". I just run a script before the build:
// package.json
{
"scripts": {
"make-q": "node ./build.js",
"build": "yarn run make-q && next build",
}
The build file can't use import or call typescript files (at least for now):
// build.js
const slugify = require('./utils/slugify');
const fs = require('fs');
const qs = slugify('some string');
fs.writeFile(
'questionsDB.js',
`module.exports = ${JSON.stringify(qs, null, 2)}`,
(err) => {
if (err) throw err;
console.log('file created successfully!');
}
);
Finally, inside the pages/api/test.js:
const db = require('../../db');
module.exports = (req, res) => {
res.setHeader('content-type', 'text/plain');
res.send(`
working:
${db}
`);
};
Now, if I call url/api/test I get the result based on the build.
Things I tried that failed:
Different node version
Update nextjs
remove yarn.lock and build again

MIME type not supported

I'm unable to get my stylesheet to apply to my handlebars. Using this exact same code it was able to load yesterday but now I'm getting this MIME error. So I'm not quite sure why this is happening. Any help would be appreciated.
Server Code
const sequelize = require('./config/connection');
const SequelizeStore = require('connect-session-sequelize')(session.Store);
const app = express();
const PORT = process.env.PORT || 3001;
// Set up Handlebars.js engine with custom helpers
const hbs = exphbs.create({ helpers });
const sess = {
secret: 'Super secret secret',
cookie: {},
resave: false,
saveUninitialized: true,
store: new SequelizeStore({
db: sequelize
})
};
app.use(session(sess));
// Inform Express.js on which template engine to use
app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(routes);
sequelize.sync({ force: false }).then(() => {
app.listen(PORT, () => console.log('Now listening'));
});
main.handlebars link reference
<link rel="stylesheet" type="text/css" href="/css/style.css">
Folder Org
server
public
--css
--style.css
I figured it out. My Folder org was NOT in face as I said it was, and when I moved my css folder under public everything worked again.

Next.js - 'yarn build' failed

When I'm trying to build my Next.js app for production I got the following error:
Seems 'API_KEY' is undefined. Can't destructure this property from publicRuntimeConfig. This error happens on pages where I use getStaticProps or getStaticPaths built in functions.
Here is my next.config.js:
const withPlugins = require("next-compose-plugins");
const withCSS = require("#zeit/next-css");
const withSass = require("#zeit/next-sass");
const withBundleAnalyzer = require("#next/bundle-analyzer");
const nextRuntimeDotenv = require("next-runtime-dotenv");
const withConfig = nextRuntimeDotenv({ public: ["API_URL", "API_KEY"] });
const nextConfig = {
analyzeServer: ["server", "both"].includes(process.env.BUNDLE_ANALYZE),
analyzeBrowser: ["browser", "both"].includes(process.env.BUNDLE_ANALYZE),
bundleAnalyzerConfig: {
server: {
analyzerMode: "static",
reportFilename: "../bundles/server.html",
},
browser: {
analyzerMode: "static",
reportFilename: "../bundles/client.html",
},
},
publicRuntimeConfig: {
PROXY_MODE: process.env.PROXY_MODE,
API_URL: process.env.API_URL,
API_KEY: process.env.API_KEY,
STATIC_PATH: process.env.STATIC_PATH,
},
};
module.exports = withConfig(
withPlugins([[withCSS], [withSass], [withBundleAnalyzer]], nextConfig)
);
I have researched official docs and google similar problem but seems with no result. Any ideas why Next.js yarn build failed?
From the documentation you can find this. A page that relies on publicRuntimeConfig must use getInitialProps ( https://nextjs.org/docs/api-reference/next.config.js/runtime-configuration ) I think you should put it somewhere else. Check the environment variables section https://nextjs.org/docs/api-reference/next.config.js/environment-variables

Wrong MIME type with Custom Next.js Server

I'm writing a Next.js app with a custom server.js file and I can't load my css - I keep getting the following in the browser console:
The resource from “http://localhost:3000/_next/
static/development/pages/index.js?ts=1552499710032”
was blocked due to MIME type (“text/html”)
mismatch (X-Content-Type-Options: nosniff)
and I don't know why. As far as I can tell I have configured my app as I had done for a previous working version. Here is my next.config.js file:
const withCSS = require('#zeit/next-css');
const withImages = require('next-images');
const path = require('path')
const Dotenv = require('dotenv-webpack')
require('dotenv').config()
module.exports = withImages(withCSS({
webpack: config => {
// Fixes npm packages that depend on `fs` module
config.node = {
fs: 'empty'
}
config.plugins = config.plugins || []
config.plugins = [
...config.plugins,
// Read the .env file
new Dotenv({
path: path.join(__dirname, '.env'),
systemvars: true
})
]
return config
}
}))
And here is my server.js file:
const express = require('express')
const next = require('next')
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
const path = require('path');
const options = {
root: path.join(__dirname, '/static'),
headers: {
'Content-Type': 'text/plain;charset=UTF-8',
}
};
app.prepare().then(() => {
const server = express()
server.get('/robots.txt', (req, res) => {
return res.status(200).sendFile('robots.txt', options)
});
server.get('/sitemap.xml', (req,res) => {
return res.status(200).sendFile('sitemap.xml', options)
});
server.get('/', (req, res) => {
return app.render(req, res, '/', req.query)
})
server.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
})
I run my app by using node server.js and I import the css using import "./styles/root.css" (my one and only css file) so no surprises there. What is going wrong?
EDIT: This is trivial enough that it may be a bug. I've opened a report here: https://github.com/zeit/next.js/issues/6647.
You are missing
server.get('*', (req, res) => {
return handle(req, res)
})
in your server.js. your github repo will work fine if you uncomment the above code and restart the server

Express Nodemon and reload not reloading the browser

I did a fresh install of express app. And my
package.json
{
"name": "projects",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "nodemon ./app.js"
},
"dependencies": {
"body-parser": "~1.18.2",
"cookie-parser": "~1.4.3",
"debug": "~2.6.9",
"express": "~4.15.5",
"morgan": "~1.9.0",
"pug": "2.0.0-beta11",
"serve-favicon": "~2.4.5"
},
"devDependencies": {
"browser-sync": "^2.18.13",
"connect-browser-sync": "^2.1.0",
"nodemon": "^1.12.5",
"reload": "^2.2.2"
}
}
app.js
var express = require('express');
var http = require('http');
var reload = require('reload');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = require('./routes/index');
var users = require('./routes/users');
var app = express();
app.set('port', process.env.PORT || 3000);
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
var server = http.createServer(app)
reload(app);
server.listen(app.get('port'), function () {
console.log('Web server listening on port ' + app.get('port'))
});
module.exports = app;
I dont want to use gulp if reload does my job.
When i change the text welcome in index.pug, the chrome is not reloaded. If i refresh i could see the change.
How can i auto reload my page on changes in any of the folder.
Note: nodemon is working fine.Again it doesn't reload the browser.
Reaload plugin reloads the page only if the express server is restarted by nodemon. From the docs:
When you restart the server, the client will detect the server being restarted and automatically refresh the page.
Nodemon does not watch Pug templates, so it's not restarted on template change:
By default, nodemon looks for files with the .js, .mjs, .coffee, .litcoffee, and .json extensions.
You can set .pug extension to be monitored by nodemon. But I think it will lead to unnecessary server restarts because Pug templates seem to be evaluated at runtime when the request for the page is happening.
Don't also forget to add reload script to all your pages by modifying the main layout template:
doctype html
html
head
...
body
block content
script(src='/reload/reload.js')
To achieve that, you need install Livereload to work together with Nodemon. A simple Express APP with necessary changes, it would be like this:
Complete step by step explained
var createError = require("http-errors");
var express = require("express");
var path = require("path");
var cookieParser = require("cookie-parser");
var logger = require("morgan");
var livereload = require("livereload");
var connectLiveReload = require("connect-livereload");
var indexRouter = require("./routes/index");
var usersRouter = require("./routes/users");
const liveReloadServer = livereload.createServer();
liveReloadServer.server.once("connection", () => {
setTimeout(() => {
liveReloadServer.refresh("/");
}, 100);
});
var app = express();
app.use(connectLiveReload());
// view engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "hbs");
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, "public")));
app.use("/", indexRouter);
app.use("/users", usersRouter);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {};
// render the error page
res.status(err.status || 500);
res.render("error");
});
module.exports = app;

Resources