Next.js intercept response - node.js

Here is snippet of what my server looks like
nextApp.prepare().then(() => {
createServer((req, res) => {
const parsedUrl = parse(req.url!, true);
handleNextRequest(req, res, parsedUrl);
}).listen(port);
});
Once I get the response for the request, how can I append html comment or any tag basically?
What I wanted to do is, before and after body tag, I want to add some comments.
Current structure
<body></body>
What I want
<!--someContext-->
<body> some content </body>
<!--someMoreContext-->

You can do it by editing the _document special file of Next that used as a base template to the page.
// ./pages/_document.js
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument

Related

How to FTP upload a buffer (pdf buffer) using NodeJS?

I converted a HTML to pdf using html-pdf-node, but I am not find a way to store this PDF in my server using FTP.
My Code:
const html_to_pdf = require('html-pdf-node');
const generatePDF = () => {
// The test HTML file
let content = `
<html>
<head>
<title>Test Application</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h2>Just a Test</h2>
</div>
</body>
</html>
`;
// generating the PDF
let options = {
format: 'letter',
margin: {
right: '40px',
left: '40px'
}
};
let file = { content };
html_to_pdf.generatePdf(file, options).then((pdfBuffer) => {
console.log(pdfBuffer); // This is the pdfBuffer. It works because if I send this buffer to my email as an attachment, I can open the PDF
// How can I create and store a test.pdf file inside my server using FTP connection?
});
}
Thank you
Using ftp should do it - https://www.npmjs.com/package/ftp
Installation: npm i ftp and usage something like:
const Client = require("ftp");
// snip snip some code here
html_to_pdf.generatePdf(file, options).then((pdfBuffer) => {
const c = new Client();
c.on("ready", function () {
c.put(pdfBuffer, "foo.pdf", function (err) {
if (err) throw err;
c.end();
});
});
const secureOptions = {
host: "localhost",
port: 21,
user: "TheGreatPotatoKingOfEurope",
password: "5uper_5eekrit!"
};
c.connect(secureOptions);
});

React: How to update the DOM with API results

My goal is to take the response from the Google API perspective and display the value into a div within the DOM.
Following a tutorial : https://medium.com/swlh/combat-toxicity-online-with-the-perspective-api-and-react-f090f1727374
Form is completed and works. I can see my response in the console. I can even store the response into an object, array, or simply extract the values.
The issue is I am struggling to write the values to the DOM even though I have it saved..
In my class is where I handle all the API work
class App extends React.Component {
handleSubmit = comment => {
axios
.post(PERSPECTIVE_API_URL, {
comment: {
text: comment
},
languages: ["en"],
requestedAttributes: {
TOXICITY: {},
INSULT: {},
FLIRTATION: {},
THREAT: {}
}
})
.then(res => {
myResponse= res.data; //redundant
apiResponse.push(myResponse);//pushed api response into an object array
console.log(res.data); //json response
console.log(apiResponse);
PrintRes(); //save the values for the API for later use
})
.catch(() => {
// The perspective request failed, put some defensive logic here!
});
};
render() {
const {flirty,insulting,threatening,toxic}=this.props
console.log(flirty); //returns undefined, makes sense upon initialization but does not update after PrintRes()
return (
<div className="App">
<h1>Please leave a comment </h1>
<CommentForm onSubmit={this.handleSubmit} />
</div>
);
}
}
When I receive a response from the API I use my own function to store the data, for use later, the intention being to write the results into a div for my page
export const PrintRes=() =>{
// apiResponse.forEach(parseToxins);
// myResponse=JSON.stringify(myResponse);
for (var i = 0; i < apiResponse.length; i++) {
a=apiResponse[i].attributeScores.FLIRTATION.summaryScore.value;
b=apiResponse[i].attributeScores.INSULT.summaryScore.value;
c=apiResponse[i].attributeScores.THREAT.summaryScore.value;
d=apiResponse[i].attributeScores.TOXICITY.summaryScore.value;
}
console.log("hell0");//did this function run
// render(){ cant enclose the return in the render() because I get an error on the { , not sure why
return(
<section>
<div>
<p>
Your comment is:
Flirty: {flirty}
</p>
</div>
<div>
<p>
Your comment is:
insulting: {insulting}
</p>
</div>
<div>
<p>
Your comment is:
threatening: {threatening}
</p>
</div>
<div>
<p>
Your comment is:
toxic: {toxic}
</p>
</div>
</section>
);
}
Variables and imports at the top
import React from "react";
//needed to make a POST request to the API
import axios from "axios";
import CommentForm from "../components/CommentForm";
var myResponse;
var apiResponse= [];
let a,b,c,d;
let moods = {
flirty: a,
insulting:b,
threatening:c,
toxic:d
}
If I understand correctly You need to create a state where you store data from api.
States in react works like realtime stores to refresh DOM when something change. this is an example to use it
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
apiData: undefined
};
}
fetchData() {
this.setState({
apiData: "Set result"
});
}
render() {
const { apiData } = this.state;
return (
<div>
<button onClick={this.fetchData.bind(this)}>FetchData</button>
<h3>Result</h3>
<p>{apiData || "Nothing yet"}</p>
</div>
);
}
}
you can check it here: https://codesandbox.io/s/suspicious-cloud-l1m4x
For more info about states in react look at this:
https://es.reactjs.org/docs/react-component.html#setstate

Trying to figure a way to read all the files in a directory, re-create and write files programmatically

I'm trying to use node built in file structure module/package in trying to read and write files. I'm looking for a way on how I can read all the files in specific directory, re-create the files and write for any changes.
Basically if I have a file called templates/_template-1.html it would re-create it to a different directory called pages/template-1.html. Instead of having to declare each file manually within the gulpfile.js. The code below is currently a work in progress.
It basically prints tpl files written then re-writes them to basic html.
/*------------------ INDEX -------------------*/
/* Build index file for the final HTML form
*/
gulp.task("build:index", function() {
let templateFiles = glob.sync("templates/**/*.tpl"),
templates = {},
RESPONSIVE_HTML = fs.readFileSync("_responsive.html", "utf8"),
THE_HTML = fs.readFileSync("_design-system.html", "utf8"),
THE_VISUAL_LIBRARY = fs.readFileSync("_visual-library.html", "utf8");
// Discover all templates
for (let file in templateFiles) {
file = templateFiles[file];
let template = /templates\/(.+?)\.tpl/gi.exec(file)[1],
text = fs.readFileSync(file, "utf8");
template = path.basename(file, '.tpl');
templates[template] = text;
}
// --------------------------------------------------------
// Visible templates:
_.each(templates, (partial, name) => {
interpolateTemplate(partial, name, templates);
});
// replace the main HTML file
for (let template in templates) {
RESPONSIVE_HTML = RESPONSIVE_HTML.replace(new RegExp(`{[#$]${template}}`, "g"), templates[template]);
THE_HTML = THE_HTML.replace(new RegExp(`{[#$]${template}}`, "g"), templates[template]);
THE_VISUAL_LIBRARY = THE_VISUAL_LIBRARY.replace(new RegExp(`{[#$]${template}}`, "g"), templates[template]);
}
fs.writeFileSync("design-system.html", beautify(THE_HTML), "utf8");
fs.writeFileSync("responsive.html", beautify(RESPONSIVE_HTML), "utf8");
fs.writeFileSync("visual-library.html", beautify(THE_VISUAL_LIBRARY), "utf8");
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>BDO Components</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.7.5/beautify.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.7.5/beautify-css.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.7.5/beautify-html.js"></script>
<script src="assets/js/libs.js" type="text/javascript"></script>
<link rel="stylesheet" href="assets/css/assets-page.css" />
<link rel="stylesheet" href="assets/css/component-guide.css" />
</head>
<body>
<div class="display-panels">
{$control-bar}
<div class="preview-pane -hide-code">
{$globals}
{$design-references}
{$component-modifiers}
<div class="section-block element-group --show-code --components -component"
data-name="Typesetting">
{$typesetting}
</div>
<div class="section-block element-group --show-code --components -component"
data-name="Elements">
{$elements}
</div>
<div class="section-block element-group --show-code --components -component"
data-name="Low Level Components">
{$low-level-components}
</div>
<div class="section-block element-group --show-code --components -component"
data-name="High Level Components">
{$high-level-components}
</div>
</div>
<div class="index-group">
</div>
</div>
<script src="assets/js/app.js" type="text/javascript"></script>
</body>
</html>
You can use the function called readdir on fs. It will return a list of filenames which you can traverse and do whatever you need to do.
Basically, this will read all files inside dirname, read content of each filename returned, modify it, write it back.
(I wrapped fs functions with promises for better flow)
function readFiles(dirname) {
let fileNames = [];
let fileContents = [];
const results = [];
return readdir(dirname)
.then((_fileNames) => {
fileNames = _fileNames;
// map filenames to array of readFile promises
return Promise.all(fileNames.map((filename) => readFile(filename)))
})
.then((allFilesContent) => {
fileContents = allFilesContent;
// for each file, push an object with name + content to a new array
fileNames.forEach((fileName, index) => {
results.push({
name: fileName, // <-- you can also change the file paths here if needed
content: beautify(fileContents[index]) // <-- modify the content here as you please
});
});
})
// map that array to a writeFile promise array
.then(() => results.map((file) => writeFile(file.name, file.content)))
.then(() => console.log('all files written successfully'))
.catch((err) => console.error(err));
}
// FS FUNCTIONS AS PROMISES:
function readFile(filepath) {
return new Promise((resolve, reject) => {
fs.readFile(filepath, 'utf-8', function(err, content) {
if (err) { return reject(err); }
resolve(content);
});
});
}
function readdir(dirname) {
return new Promise((resolve, reject) => {
fs.readdir(dirname, function(err, filenames) {
if (err) { return reject(err); }
resolve(filenames);
});
});
}
function writeFile(filename, content) {
return new Promise((resolve, reject) => {
fs.writeFile(filename, content, function(err) {
if (err) { return reject(err); }
resolve();
});
});
}
I have a series of modules around slurping whole directories (recursively), and then doing stuff, like making a web page, with the results.
https://github.com/AWinterman/node-fsj and https://github.com/AWinterman/fsj-render
it should be pretty easy for you to add what you want.

Download PDF from node API via FTP

I have PDF on a remote server. I have API with node and I want, from my website, download the PDF.
I'm using jsftp to upload and read PDF. It works fine :
let str = '';
FTP.get('path/to/my/file', (err, socket) => {
socket.on("data", d => {
str += d.toString();
});
socket.on("close", err => {
if (err) {
console.error("There was an error retrieving the file.", err);
}
// HERE I HAVE THE FILE IN STRING
});
socket.resume();
});
On the close event I have the file in String, but I don't succeed to send it to the browser. I've tried things like :
let s = new Readable();
s.push(str);
s.push(null);
s.pipe(res);
OR
res.end(str);
But nothing happen in browser
I'm using Polymer for my ajax request
<iron-ajax
id="openPdf"
content-type="application/json"
method="POST"
url="/api/karaweb/pdf"
on-response="handleOpenPdfResponse"
on-error="errorMessage"></webservice-request>
Any solutions ?
Thanks
I have a mixin called PdfDownloaderMixin; here is the whole code:
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<dom-template id="pdf-downloader-mixin">
<script>
/* #polymerMixin */
const PdfDownloaderMixin = (superClass) => class extends superClass {
constructor() {
super();
}
downloadPdf(blobData) {
let fileObjectUrl = window.URL.createObjectURL(blobData);
window.open(fileObjectUrl);
}
}
</script>
</dom-template>
Then you use like this in your element:
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/iron-ajax/iron-ajax.html" />
<link rel="import" href="pdf-downloader-mixin.html" />
<dom-module id="attachment-handler">
<template>
<iron-ajax id="getAttachmentAjax"
url="[[rootPath]]api/session/getattachment"
debounce-duration="300"
handle-as="blob"></iron-ajax>
</template>
<script>
class AttachmentHandler extends PdfDownloaderMixin(Polymer.Element) {
static get is() { return 'attachment-handler'; }
getAttachment() {
this.$.getAttachmentAjax.generateRequest().completes.then((req) => {
req.succeeded && this.downloadPdf(req.response);
});
}
}
customElements.define(AttachmentHandler.is, AttachmentHandler);
</script>
</dom-module>

Invariant Violation: React error #130

So i was currently trying to render the code for a custom sidebar found in the site: How to build a custom sidebar in React
. But i am getting the error:
Element type is invalid: expected a string (for built-in components)
or a class/function (for composite components) but got: undefined.
Check the render method of TheSidebar
I cannot comprehend what is wrong with it, but still, i am new to React. Running it on Node. Any help is appreciated.
Here is the code:
const React = require('react');
const ReactDOM = require('react-dom');
const { IndexLink, Link } = require('react-router');
// import './Sidebar.scss'
const classNames = require('classnames');
class TheSidebar extends React.Component {
constructor(props) {
super(props);
this.state = {
showMenu: false
}
this.toggleMenu = this.toggleMenu.bind(this)
}
componentDidMount() {
document.addEventListener('click', this.handleClickOutside.bind(this), true);
}
componentWillUnmount() {
document.removeEventListener('click', this.handleClickOutside.bind(this), true);
}
toggleMenu() {
this.setState({ showMenu: !this.state.showMenu })
}
handleClickOutside(event) {
const domNode = ReactDOM.findDOMNode(this);
if ((!domNode || !domNode.contains(event.target))) {
this.setState({
showMenu: false
});
}
}
render() {
const showMenu = this.state.showMenu;
const sidebarClass = classNames({
'sidebar': true,
'sidebar-menu-expanded': showMenu,
'sidebar-menu-collapsed': !showMenu
});
const elementsClass = classNames({
'expanded-element': true,
'is-hidden': !showMenu,
});
return (
<nav className={sidebarClass}>
<img
className="menuIcon"
// src={}
onClick={this.toggleMenu}
/>
<ul>
<li>
<Link className="expandable" to="/setting" title="Setting">
<img
src={'https://png.icons8.com/setting/ffffff'}
alt=""
/>
<span className={elementsClass}>Setting</span>
</Link>
</li>
</ul>
</nav>
);
}
}
module.exports = TheSidebar;
The sidebar is then injected into an App file along with a header and then rendered. The app file and render file are as follows:
const React = require('react');
const Header = require('./Header.jsx');
const TheSidebar = require('./Sidebar.jsx');
class App extends React.Component {
render() {
return(
<div>
<head>
<title>TESTING</title>
</head>
<body>
<div>
<Header />
</div>
<div>
<TheSidebar />
</div>
</body>
</div>
);
}
}
module.exports = App;
And the rendering:
app.set('views', path.join(__dirname, "../views"));
app.set('view engine', 'jsx');
app.engine('jsx', createEngine());
app.get("/testing", function(req, res){
res.render('pages/App.jsx');
});
Link and IndexLink are exported as fields within a default object export, so if you're using "require" then first get the default export:
const ReactRouter = require('react-router')
And then pick out individual fields:
const IndexLink = ReactRouter.IndexLink
const Link = ReactRouter.Link
EDIT: If your react-router version is >= 4.0, then Index is longer inside it. Its in react-router-dom. And IndexLink is no longer available. You should probably revert to 3.x to run this example code
You are not importing the IndexLink and Link component correctly. Check out named imports in ES6.
You should import them like this.
import { IndexLink, Link } from 'react-router'

Resources