I am trying to plug nextjs with keystone js show that i can use reactjs for frontend and keystonejs as CMS but It's not working. I was following a tutorial to do so although it worked in tutorial but i don't know why its not working in my case.
tutorial website
This is how i tried to configure.
keystone.js
// Simulate config options from your production environment by
// customising the .env file in your project's root folder.
require('dotenv').config();
// Require keystone
const keystone = require('keystone');
//var handlebars = require('express-handlebars');
//Next app
const next = require('next');
const dev = process.env.NODE_ENV !== 'production';
const app = next({dev});
// Initialise Keystone with your project's configuration.
// See http://keystonejs.com/guide/config for available options
// and documentation.
keystone.init({
'name': 'cmsblog',
'brand': 'cmsblog',
// 'sass': 'public',
// 'static': 'public',
// 'favicon': 'public/favicon.ico',
// 'views': 'templates/views',
// 'view engine': '.hbs',
// 'custom engine': handlebars.create({
// layoutsDir: 'templates/views/layouts',
// partialsDir: 'templates/views/partials',
// defaultLayout: 'default',
// helpers: new require('./templates/views/helpers')(),
// extname: '.hbs',
// }).engine,
'auto update': true,
'session': true,
'auth': true,
'user model': 'User',
});
//Load your project's Models
keystone.import('models');
// Setup common locals for your templates. The following are required for the
// bundled templates and layouts. Any runtime locals (that should be set uniquely
// for each request) should be added to ./routes/middleware.js
app.prepare()
.then(() => {
// keystone.set('locals', {
// _: require('lodash'),
// env: keystone.get('env'),
// utils: keystone.utils,
// editable: keystone.content.editable,
// });
// Load your project's Routes
keystone.set('routes', require('./routes'));
// Configure the navigation bar in Keystone's Admin UI
keystone.set('nav', {
posts: ['posts', 'post-categories'],
galleries: 'galleries',
enquiries: 'enquiries',
users: 'users',
});
// Start Keystone to connect to your database and initialise the web server
keystone.start();
})
Routes.js
const keystone = require('keystone');
exports = module.exports = nextApp => keystoneApp => {
//setup Route Bindings
const handle = nextApp.getRequestHandler();
keystoneApp.get('/api/posts', (req,res,next) => {
const Post = keystone.list('Post');
Post.model
.find()
.where('state', 'published')
.sort('-publishedDate')
.exec(function(err, results) {
if(err) throw err;
res.json(results);
});
});
keystone.get('*', (req,res) => {
return handle(req,res);
});
};
folder structure
result after visiting localhost:3000
https://medium.com/#victor36max/how-to-build-a-react-driven-blog-with-next-js-and-keystonejs-cae3cd9fb804
The tutorial website says
A Next.js 404 page should show up instead of KeystoneJS page.
Let’s try to make a page with Next.js.
In pages folder, make a new file index.js .
So you can keep it up.
Related
I am trying to create a react google/youtube api project to view all of my youtube videos. I am following this github example repo: https://github.com/paulzmuda/youtube-react-upload
Which I have cloned, installed, and inside gapi-client.js, I added my client_id:
window.gapi.client
.init({
client_id: "1111111111-11111111111111.apps.googleusercontent.com",
fetch_basic_profile: false,
scope: 'profile',
// 'apiKey': 'YOUR_API_KEY',
// 'clientId': 'YOUR_CLIENT_ID',
// 'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly',
// 'discoveryDocs': ['https://www.googleapis.com/discovery/v1/apis/drive/v3/rest']
})
.then(() => {
GoogleAuth = window.gapi.auth2.getAuthInstance();
GoogleAuth.isSignedIn.listen(dispatch(updateSigninStatus));
dispatch(setSigninStatus());
// document.getElementById('sign-in-or-out-button').addEventListener('click', () => {
// this.handleAuthClick();
// });
// document.getElementById('revoke-access-button').addEventListener('click', () => {
// this.revokeAccess();
// });
});
};
I got my client_id variable from the credentials page of my google cloud project (highlighted)
And I added my localhost url to the project
but when i launch the youtube-react-upload project with npm run start:dev, I get this error in my browser window:
"Not a valid origin for the client: http://localhost:3032 has not been registered for client ID 1111111111-11111111111111.apps.googleusercontent.com. Please go to https://console.developers.google.com/ and register this origin for your project's client ID."
I thought I added this localhost var already? Am I missing something?
I have created two dynamic page but error displayed:
exporting a Next.js application via next export disables API routes.
This command is meant for static-only hosts, and is not necessary to
make your application static. Pages in your application without
server-side data dependencies will be automatically statically
exported by next build, including pages powered by getStaticProps.
Learn more: https://nextjs.org/docs/messages/api-routes-static-export
I followed exportPathMap method using next.config.js but could not solve. Could you please check my config code below solve this issue?
Page Root: pages/category/[list]/[id].js and pages/store/[list]/[id].js
next.config.js
module.exports = {
images: {
domains: ["dl8mjowvdz1rh.cloudfront.net", "app.ae"],
},
eslint: {
// Warning: This allows production builds to successfully complete even if
// your project has ESLint errors.
ignoreDuringBuilds: true,
},
exportPathMap: async function (
defaultPathMap,
{ dev, dir, outDir, distDir, buildId }
) {
return {
'/': { page: '/' },
'/category/:list/:id': { page: '/category/:list/:id', query: { title: 'Category Page' } },
'/store/:list/:id': { page: '/store/:list/:id', query: { title: 'Store Page' } },
}
},
};
This is a personal portfolio page that I'm implementing a contact form within, using nodemailer.
The nodemailer thing is all set from server side. I just need some advice on pointing the client post request to the right place in regards to development and deployment.
I figured as much for setting an environment variable for production vs development and hitting the fetch based upon that. Now I'm just wondering how to go about finding whatever I would put in the fetch for production.
would it be just pointing back into my own app:
fetch(www.mydomain.com/send-email, data) ...
I'm in the Heroku docs trying to figure this out.
Basically, I have a huge blind spot which is hitting a server API from Create React App that isn't launched independently on localhost:3000. I have yet to hit a server route from my client that wasn't served locally on localhost. When I push this to Heroku, I need to have the right route or config, what I need is some advice on how to do this.
I understand proxying somewhat. Just wondering what the steps are to properly hit my server route from an client/server deployed on Heroku as opposed to localhost:3000 during deployment.
When I'm in development I pretty much always axios.post a server that I've spun up on localhost:3000,
which I then hit with something like this coming from my client..
axios.post('localhost:3000/send-email', data)
.then( () => {
setSent(true)
})
.then(() => {
resetForm()
})
.catch((err)=> {
console.log('Message not sent', err)
})
}
...which is then handled by an endpoint on the express server listening on localhost:3000, that looks somewhat like what I've pasted below.
const express =
require('express'),
bodyParser = require('body-parser'),
nodemailer = require('nodemailer'),
cors = require('cors'), path = require('path'),
port = process.env.PORT || 3000, publicPath = path.join(__dirname, '..', 'build');
require('dotenv').config();
const app = express();
app.use(cors());
app.use(express.static(publicPath));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.get('*', (req, res) => {
res.sendFile(path.join(publicPath, 'index.html'));
});
app.post('/send-email', (req, res) => {
console.log('request: ', req.body)
let data = req.body;
let transporter = nodemailer.createTransport({
service: 'gmail',
port: 465,
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD
}
});
let mailOptions = {
from: data.email,
to: process.env.EMAIL,
subject: `${data.subject}`,
html: `<p>${data.name}</p>
<p>${data.email}</p>
<p>${data.message}</p>`
};
transporter.sendMail(mailOptions,
(err, res) => {
if(err) {
res.send(err)
} else {
res.send('Success')
}
transporter.close();
});
})
app.listen(port, () => {
console.log(`Server is up on port ${port}!`);
});
folder structure is like this:
main
|-server
|-server.js
|-src
|-components
|-Contact.js
Use the process.env.NODE_ENV variable to differ the environments.
When you run npm start, it is always equal to 'development', when you run npm test it is always equal to 'test', and when you run npm run build to make a production bundle, it is always equal to 'production'. You cannot override NODE_ENV manually.
Therefore, you can create and export a function like
export function apiDomain() {
const production = process.env.NODE_ENV === 'production'
return production ? 'anotherDoman' : 'localhost:3000'
}
or maybe, depending on your requirements
export function apiDomain() {
const { protocol, hostname, origin } = window.location
return hostname === 'localhost' ? `${protocol}//${hostname}` : origin
}
For more details, take a look at https://create-react-app.dev/docs/adding-custom-environment-variables/
I'm working on a project using express and next js and I've found a great example of how to setup an array of data for your redirects in your server.js file. However, if it is possible I would like to build a plugin within WordPress that will allow a user to submit data for redirects so that it could be managed by someone without technical knowledge. My question is, is it possible to fetch data within my server.js file to replace the data in this example?
const express = require('express')
const next = require('next')
const { join } = require('path')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
//This is the data I want to fetch through the WP Rest API
const redirects = [
{ from: '/old-link-1', to: '/new-link-1' },
{ from: '/old-link-2', to: 'https://externalsite.com/new-link-2' },
]
app.prepare().then(() => {
const server = express()
redirects.forEach(({ from, to, type = 301, method = 'get' }) => {
server[method](from, (req, res) => {
res.redirect(type, to)
})
})
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(3000, err => {
if (err) throw err
console.log('> Ready on http://localhost:3000')
})
})
Yes, I believe it's possible do do something like that.
This library would allow you to make an API request within express: https://github.com/request/request
Executed like so:
var request = require('request');
request('http://www.google.com', function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body) // Print the google web page.
}
})
The next step would be to create an endpoint in wordpress with all of the 301's that you want to create:
function my_custom_endpoint(){
return 'Hey look, its some data';
}
// Register the rest route here.
add_action( 'rest_api_init', function () {
register_rest_route( 'yournamespace/v1', 'my_custom_endpoint',array(
'methods' => 'GET',
'callback' => 'my_custom_endpoint'
));
});
Good luck, and happy coding!
So, just incase anyone else stumbles upon the problem of programmatically adding redirects that originate on a WordPress install this is how it can be done. My tech stack is React, Next.js with an Express server pulling in data from a WordPress install that is living elsewhere in the webs.
WordPress:
1) Create a blank WordPress plugin (Google is your friend)
2) Create an activation hook within your plugin to create a database(Again, Google with 'to_url' and 'from_url' for each entry.
3) Register a Rest Route within plugin (Like described above with Tanner's answer)
This Rest Route should be pulling your info from the database and returning it as an array in this format:
[
{ 'from': '/about', 'to': '/about-us' },
{ 'from': '/test3', 'to': '/banks/testing-page' },
]
4) Create a plugin admin page with a form that allows the users to add entries to this database. As your database grows your response from the rest api will grow and your redirects will seamlessly be included in your project.
5) In your React server.js you're going to need the following setup
const request = require("request");
let redirects;
request('https://yourwebsite.com/wp-json/YOUR-ROUTE/v2/redirects', function (error, response, body) {
if (!error && response.statusCode == 200) {
redirects = JSON.parse(body);
}
})
redirects.forEach(({ from, to, type = 301, method = 'get' }) => {
server[method](from, (req, res) => {
res.redirect(type, to)
})
});
Caveats: Make sure when you're manipulating data with forms in php you're taking proper precautions to sanitize and escape everything.
I am attempting to implement a service worker for a boilerplate project I'm working on (https://github.com/jonnyasmar/gravity-bp feedback welcome!), but I've hit a snag :(
Problem:
I'm serving the index.html for this boilerplate virtually as an interpreted Twig template via ExpressJS. However, because I'm generating the service worker assets at build time and that is where I'm pointing it to the cacheable static assets, I can't figure out how to tell the service worker that I want it to cache the virtual index.html file served by ExpressJS at runtime.
My most successful attempts successfully cache all static assets (including the asset-manifest.json generated at build time), but will not cache a virtual index.html.
If I convert it to a static html file, the service worker does successfully cache it.
Please be sure to upvote this question to help get some visibility if you are interested in the answer!
Questions:
Is there a way to correct my code to accomplish this?
Is there anything wrong with doing it this way?
If yes to #2, how would you recommend handling this and why?
See the full source on GitHub.
Relevant code:
webpack.config.js:
output: {
filename: '[name].js',
chunkFilename: '[chunkhash].js',
path: path.resolve(__dirname, 'public'),
publicPath: '/'
},
plugins: {
new ManifestPlugin({
fileName: 'asset-manifest.json',
}),
new SWPrecacheWebpackPlugin({
cacheId: 'gravity-bp',
dontCacheBustUrlsMatching: /\.\w{8}\./,
filename: 'sw.js',
minify: true,
navigateFallback: 'index.html',
stripPrefix: 'public/',
swFilePath: 'public/sw.js',
staticFileGlobs: [
'public/index.html',
'public/**/!(*map*|*sw*)',
],
})
}
sw.ts:
const swUrl: string = 'sw.js';
export const register = (): void =>{
if(process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator){
const sw: ServiceWorkerContainer = navigator.serviceWorker;
sw.register(swUrl).then(registration =>{
registration.onupdatefound = (): any =>{
const installer: ServiceWorker = registration.installing;
installer.onstatechange = (): any =>{
if(installer.state === 'installed'){
if(sw.controller){
console.log('New content available.');
}else{
console.log('Content cached for offline use.');
}
}
};
};
}).catch((error) =>{
console.error('Failed to register service worker:', error);
});
}
};
export const unregister = (): void =>{
if('serviceWorker' in navigator){
navigator.serviceWorker.ready.then(registration =>{
registration.unregister();
});
}
};
server.ts:
import * as path from 'path';
const twig = require('twig').__express;
const express = require('express');
const compression = require('compression');
const pkg = require('../../package.json');
const version = pkg.version;
let app = express(),
ip = '0.0.0.0',
port = 3000,
views = path.resolve('./src/views');
app.use(compression());
app.use(express.static('public'));
app.set('view engine', 'twig');
app.engine('.twig', twig);
app.set('views', views);
// Routes
app.get("*", function(req: any, res: any, next: any){
// vars
res.locals.version = version;
res.render('index');
});
let server = app.listen(port, ip, function(){
let host = server.address().address;
let port = server.address().port;
console.log('Gravity Boilerplate ready at http://%s:%s', host, port);
});
Within the sw-precache-webpack-plugin documentation it talks about using sw-precache options. The one you should investigate is the dynamicUrlToDependencies setting. See some of these links for more info:
https://github.com/GoogleChromeLabs/sw-precache/issues/156
dynamicUrlToDependencies [Object⟨String,Buffer,Array⟨String⟩⟩]
For example, maybe start with this to test:
dynamicUrlToDependencies: {
'/': 'MAGIC_STRING_HERE'
},
So really, you need to configure the sw-precache WebPack plugin to load a server rendered page as the navigateFallback route.