I made a little app that would take in a docx template using docxtemplater and have the user input their data on an HTML page, then apply the data on the docx file and output a finished document.
This worked on the browser, and it still works, but when I tried to implement Electron, I get this error when I press on submit
(node:2792) electron: Failed to load URL: file:///C:/process-document with error: ERR_FILE_NOT_FOUND
here is my code:
const express = require('express');
const bodyParser = require('body-parser');
const PizZip = require("pizzip");
const Docxtemplater = require("docxtemplater");
const fs = require('fs');
const path = require('path');
const electron = require('electron');
const url = require('url');
const rl = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
const {app, BrowserWindow, Menu} = electron;
app.on('ready', function() {
// create a new window
mainWindow = new BrowserWindow({});
// load THE HTML into the mainWindow we made
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}));
// quit app when the X is pressed on the main page
mainWindow.on('closed', function() {
app.quit();
});
// build menu from template which is currently mainMenuTemplate which only has "file"
const mainMenu = Menu.buildFromTemplate(mainMenuTemplate);
// now we insert the menu we just made
Menu.setApplicationMenu(mainMenu);
});
const mainMenuTemplate = [
{
label: 'File',
submenu:[
{
label: 'Add Item',
click(){
console.log("add an item")
}
},
{
label:'Clear Item'
},
{
label: 'Quit',
accelerator: process.platform == 'darwin' ? 'Command+Q' : 'Ctrl+Q',
click(){
app.quit()
}
}
]
}
];
const appyy = express();
const port = 3000;
appyy.use(express.static(path.join(__dirname, 'public')));
appyy.use(bodyParser.urlencoded({ extended: true }));
appyy.use(bodyParser.json());
appyy.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
appyy.post('/process-document', (req, res) => {
// Retrieve data from the form submission
console.log('req.body: ', req.body);
const {
firstName,
lastName,
telephone,
faxNum,
address,
dateOfBirth,
birthPlace,
idNum,
idDate,
daira,
wilaya,
commune,
number} = req.body;
const todayDate = getFormattedDate();
// Process the data and generate the document
// Load the docx file as binary content
const content = fs.readFileSync(path.resolve(__dirname, 'public', "FilahaNew.docx"), "binary");
const zip = new PizZip(content);
const doc = new Docxtemplater(zip, {
paragraphLoop: true,
linebreaks: true,
});
// Render the document with user input
doc.render({
firstName,
lastName,
telephone,
faxNum,
address,
dateOfBirth,
birthPlace,
idNum,
idDate,
daira,
wilaya,
commune,
number,
todayDate,
});
console.log({firstName,
lastName,
telephone,
faxNum,
address,
dateOfBirth,
birthPlace,
idNum,
idDate,
daira,
wilaya,
commune,
number});
const generatedDocBuffer = doc.getZip().generate({
type: "nodebuffer",
// compression: DEFLATE adds a compression step.
// For a 50MB output document, expect 500ms additional CPU time
compression: "DEFLATE",
});
// Save the filled template to a new file
const outputPath = path.resolve(__dirname, 'public', `${firstName}${lastName}.docx`);
fs.writeFileSync(outputPath, generatedDocBuffer);
console.log(`Filled template saved as "${outputPath}"`);
rl.close();
;
// Send the generated document back as a response
res.setHeader('Content-Type', 'application/msword');
res.setHeader('Content-Disposition', 'attachment; filename=output.docx');
res.send(generatedDocBuffer);
});
appyy.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
function getFormattedDate() {
const today = new Date();
const day = String(today.getDate()).padStart(2, '0');
const month = String(today.getMonth() + 1).padStart(2, '0');
const year = today.getFullYear();
return `${day}/${month}/${year}`;
}
and the other JS file that makes this also work is script.js
console.log('Script loaded'); // Add this line at the beginning of script.js
document.addEventListener('DOMContentLoaded', function () {
const form = document.getElementById('documentForm');
const output = document.getElementById('output');
form.addEventListener('submit', async function (event) {
event.preventDefault();
console.log('Form submitted'); // For debugging
const formData = new FormData(form);
try {
const response = await fetch('http://localhost:3000/process-document', {
method: 'POST',
body: formData,
});
console.log(formData)
if (response.ok) {
console.log('response OK'); // For debugging
const generatedDocuments = await response.text();
const generatedDocument = JSON.stringify(generatedDocuments)
const iframe = document.createElement('iframe');
iframe.srcdoc = generatedDocument;
iframe.style.width = '100%';
iframe.style.height = '500px';
output.appendChild(iframe);
} else {
console.log('no working'); // For debugging
output.textContent = 'Error generating the document.';
}
} catch (error) {
console.error('Error:', error);
output.textContent = 'An error occurred. Please try again.';
}
});
});
I need my Electron app to work the same way as it does in HTML
What appeared to be the problem at the beginning was that the fetch request on script.js was not working when it was written fetch('/process-document', {}) so instead I wrote fetch('http://localhost:3000/process-document', {}) and that still gave me the same error.