Webpack/Gulp/Express error: No such file or directory - node.js

I have a project which consists of a file upload form, which uses an express router and jade/pug template rendering for 2 different views.
I'm attempting to use webpack to compile all my javascript files into one (backend.js), and gulp to compile that backend.js file, along with 3 .pug files, into another directory.
After webpack compiles the js files contained in the project, it places them in build/backend.js:
project-after-webpack
And finally, gulp takes the backend.js file, along with the pug templates located in another folder in the project, and places them in this structure, compiling backend.js to main.js, and turning all my pug files into HTML files:
project-after-gulp
The rest of the project is in the root directory.
One of the javascript files is responsible for rendering views upon certain http requests. This is where I'm having trouble. Without gulp and webpack, i'm able to render .pug views with no problem using res.render(). However, I'm getting a "no such file or directory" error when I use gulp and webpack. This is how I'm attempting to render the form.pug file, which gulp turned into form.html.
router.get('/', function list (req, res, next) {
//res.render('submissions/form.pug'
res.sendFile(path.join(__dirname+'build/submissions/form.html'), {
submission: {},
action: 'Add'
});
});
And the console is telling me ENOENT: no such file or directory, stat '/form.html', even though you can see that there is in fact a file there.
I'm not sure if my path is incorrect, if using the .sendFile function requires anything i'm missing, or if this is just plain impossible. Any help wuold be appreciated.

I think the point of using path.join() (see the docs here) is to build a path string compatible with all operating systems.
It takes all path fragments as arguments like so:
router.get('/', function list (req, res, next) {
//res.render('submissions/form.pug'
res.sendFile(path.join(__dirname, 'build', 'submissions', 'form.html'), {
submission: {},
action: 'Add'
});
});
Maybe a / was missing between __dirname and build otherwise?

Related

Node.js + Express.js: How to use the root (/) for serving static files?

how do we serve a static file located in the root of the directory (/) and not in a folder of it?
I am using Node.js with Express.js, I have tried the following JavaScript code in my index.js file which is located in / (the root of the directory).
Attempt 1
const path = require('path');
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname, 'index.html'));
})
Attempt 2
const path = require('path');
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname, '/'));
})
Same output as Attempt 1
Attempt 3
app.use(express.static('/'));
Didn't work, showed an error: "Cannot GET /".
Attempt 4
app.use(express.static(''));
Didn't work, showed an error: "Path cannot be empty".
Please assist, I have refered to many other possible questions similar to this, and one of the questions didn't have an answer, so I am re-asking.
The argument you pass to express.static needs to be the path to the directory where the file is.
It shouldn't be / which is the root of the entire file system (you might intend it to be the URL path / and not the file system path / but that isn't what it means).
The special variables __dirname will give you the directory the JS file you are currently running is in. You probably want that (assuming a directory structure like this):
.../
|-server.js
|-index.html
So
app.use(express.static(__dirname));
Note that it is generally better to separate out your server-side code and the files you sent to the client. It makes it much easier to maintain the project in the long run and prevents your server side code (which might contain secrets) being exposed over HTTP by the static module.
There isnt any difference if you use / and no / in the script
for express use
app.use(express.static(process.cwd() + '/'));
try this it might be helpful
app.use(express.static('/'));
you do not need the "/" before "js" because it is already included above:
<script src="test.js"></script>

React.js: Heroku: Error: ENOENT: no such file or directory, stat '/app/src/client/build/index.html'

My apologies if this is not the correct way to do this. I have spent 4 days on this problem and eventually figured out a solution I would just like to post this possible solution if anyone else encounters this problem.
I am running a Node.js server with the React client inside of it here is an image of folder structure for reference.
I use a postbuild script in package.json to build my project on heroku
For reasons that are beyond me the following GET catch all statement
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "client", "build", "index.html"))
});
Path was returning '/app/src/client/build/index.html' this is the incorrect path as your app is hosted on /app/client/build/index.html I had to edit my GET catch all statement to the following.
app.get("*", (req, res) => {
res.sendFile(path.resolve("client", "build", "index.html"));
});
It now correctly redirects to my index file and the app works correctly. Like I said unfortunately I cant advise on why the __dirname is not pointing to the right folder so if anyone could shed light on that will be great.
Also the robustness of the solution could be a problem as should Heroku change file structures the GET catch all statement could break.
__dirname returns the path to the folder containing the executed file.
So if the code containing __dirname is in the file '/app/src/app.js', __dirname will resolve as '/app/src'.
If your __dirname is in the file '/app/foo/bar/baz.js', it will resolve as '/app/foo/bar'.
Since you want your path to resolve as '/app/client/...' your fix is good.
The solution you used should be robust enough. path.resolve() will set your working directory (the one where you run your app, so '/app' on heroku I assume) as the root of your path. So unless you change your directory names or move files, you should be OK.

Serving static files with Express.js on heroku. Where do files reside in Heroku?

The issue is Heroku can not find the files of my node project. This prompts the 404 Not found error. The question is how does the generic node Heroku file structure look like? If so, where do the files of my project actually reside in the heroku?
The scenario:
With the express library, I put all files needed to serve a frontend template, in a folder called 'public'. The absolute path leading to 'public' is needed and'_dirname' is the variable that contains that.
app.use(express.static(_dirname+'/public');
Now, Heroku always makes a GET request to the root of the application. As a response I send the
index.html file as the starting template. I also provide its absolute path as '{root:_dirname}'.
app.get('/', function(req, res) {
res.sendFile('public/index.html'{root:_dirname});
});
When the server is run, I get a 404 Not found error. Which means Heroku cannot find the files.
Heroku root folder is named app/. So as expected, providing the local '_dirname' is wrong since the application is now running on Heroku server not locally.
2020-09-10T15:28:12.127567+00:00 app[web.1]: Error: ENOENT: no such file or directory, stat '/app/C:/Users/...
But, pointing at the public folder alone(only /public), assuming app/ is root, still prompts the 404 error not found.
2020-09-10T15:31:23.630358+00:00 app[web.1]: Error: ENOENT: no such file or directory, stat '/index.html'
The Question
Which leads to the question, what does heroku file structure look like? where do project files reside in the heroku file structure, so i can provide the correct path on the GET request?
My file structure
After Bergur suggestion:
It prompts a 404 Not found. However, the path is now theoretically correct.
This is what I changed:
app.use(express.static(path.join(__dirname+'/public')));
app.get('/', function(req, res) {
res.sendFile('index.html',{root:__dirname+'/public'});
});
The 404 error comes from the 'app.get('/,function(req,res){});'. Without this handler, my heroku application shows a 'cannot GET' message on the template.
Have you tried to log out the full path just to see if there's something off?
I have several heroku projects with nodejs and react/vue/angular dist folder without problems.
I would change your code a little bit to:
use nodes __dirname
Use path.join instead of inserting the '/' yourself. It might cause some problems.
So final version might look like:
app.use(express.static(path.join(__dirname, 'public')));
This assumes the project structure is
-index.js
-public/index.html
There should be no need to use sendFile, serving the public folder is enough. Just make sure that the public folder is being deployed/pushed to heroku.
If you share with us your folder/project structure we might help you you better.

How to load bundles with angular-cli?

I must be missing something extremely simple here, because I don't understand how anyone can have a functioning angular-cli app without the ability to do the following...
Context
I have an Angular 2 app with an express.js backend acting as an API. I have switched from webpack to angular-cli to bundle my files as it offers easy Ahead-Of-Time compilation.
What I didn't expect was angular-cli is so opinionated, it even requires me to keep an index.html file inside the angular app directory in my repository (I had previously kept it in /views for express.js to send to clients).
Problem
I am struggling to see how I can load the outputted JS bundles from angular-cli if I have node.js server. Consider the following angular-cli.json snippet:
"apps": [
{
"root": "app",
"outDir": "public/dist",
],
Both my bundle.js files and my index.html will be outputted in public/dist. This means I have to update my node.js routes to change:
// Root
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname + '/../views/index.html'));
});
to:
// Root
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname + '/../public/dist/index.html'));
});
Now the problem is that my public/dist/index.html file has a <base href="/"> tag, and the following generated script tags:
<script type="text/javascript" src="inline.bundle.js"></script><script type="text/javascript" src="vendor.bundle.js"></script><script type="text/javascript" src="main.bundle.js"></script>
Well, obviously when I run my node.js server, those above bundles won't be found because they don't exist at the base href's location. There is no /inline.bundle.js, because it's located at /public/dist/inline.bundle.js. So, how can I ever load my frontend app?
I don't this will work, as it expect an absolute path, not relative.
res.sendFile(path.join(__dirname + '/../public/dist/index.html'));
You should point in a relative way all the dist server to / from the express folder, something like:
app.use('/', express.static('../public/dist'));
app.get('*', (req, res) => {
res.sendFile('index.html', { root: '../public/dist' });
});
I handle this kind of problems in a different way. I never send a file using sendFile, instead I only send JSON data.
Sending a file is suitable for traditional non-SPA applications. Sending JSON data is suitable for modern SPA applications.

Nodejs/apidocjs: How do I render the generated documentation at a specific url without a template

I am writing apidocs for a nodejs project someone else wrote.
I would like the documentation page to be displayed when someone visits "myurl.com/docs/api". My documentation directory is being placed under "app/public/app/docs/apidoc/" and I am trying to use routes to display it but gives me an error stating:
'Error: Failed to lookup view "/public/app/apidoc/index.html" in views directory "/Path/To/Project/app/views"'
Here is my routes.js entry:
app.get('/docs/api', function(req, res) {
res.render('/app/apidoc/index.html');
});
I believe the project uses jade and ejs as they are listed somewhere in the configuration files.
You can serve the documentation from the public folder by using this
app.use(express.static('public'));
And then generate the apidoc with this command
apidoc -e "(node_modules|public)" -o public/apidoc
Now you can access the documentation by navigating to http://{rooturl}/apidoc

Resources