When a meteor app gets compiled (meteor build app), the public directory becomes \programs\web.browser\app All files which were in the development public directory \public are now accessible with http://domain.tld/file-in-public-directory.jpg
When I put a new file into the compiled public directory and try to view it in the browser, I get an error, which says that Meteor does not have a route for that url. When I do this in the development public directory it works flawless, but not in the compiled (meteor build app).
I need this, because I want to upload new files in that directory.
Any help?
So, you'll have to tweak it a little bit, but there's a way you can access pretty much any folder you want, especially for static files, by using the low level connectHandlers object.
Here is an example where you have a folder named .images (hidden from the Meteor auto-refresh), which serves images whenever a request is made to http://[yoursiteURL]/images/...
var fs = Npm.require('fs');
WebApp.connectHandlers.use(function(req, res, next) {
var re = /^\/images\/(.*)$/.exec(req.url);
if (re !== null) {
var filePath = process.env.PWD
+ '/.images/'
+ re[1];
var data = fs.readFileSync(filePath, data);
res.writeHead(200, {
'Content-Type': 'image'
});
res.write(data);
res.end();
} else {
next();
}
});
You're using a regular expression to find out if the incoming request is trying to access /images/. If it is, we're going to send the image with the appropriate headers, using res.write()
Two things of note:
1- you don't have to use anything special (no packages, etc) to use the Npm.require('fs') because it's built in and usable.
2- using fs.readFileSync is a bit of a hack, and is blocking. You'll want to tweak that for a performant, production app.
Hope this helps! A bit more information on connectHandlers can be found here.
Nice to see folks out there trying meteor. It's great stuff - but at the same time, it does seem complicated. What really helped me so much is using this app: metoer-kitchen. I now use it alongside when working on my projects.
Related
Sorry for the wording in the question. Probably my biggest issue with this is not knowing how to phrase it correctly, as I've not been able to gleam a single hint of an answer from google.
Using api routes in Next.js I want to serve a data.json file. This works no problem, however I also want to be able to edit this file afterwards and for the api to reflect the updated content. As it stands after building and running if I edit the file the api still returns the old one, hell I can even delete it. I assume this is because Next.js makes a copy of the file at build time, and puts it somewhere in the .next directory(?), haven't been able to find it there though.
Below is a boiled down version of what I'm doing:
/pages
/api
/info.js
/data
/data.json <- file I want to use with the api
pages/api/info.js
export default function (req, res) {
const data = require('../../data/data.json')
// Do stuff
res.status(200).json(data.something)
}
Any guidance on this is very appreciated
Using require to include a file in any Node app will definitely tie the json file to the apps run time or build time.
The feature you describe sounds like static file serving but next caches those files as well.
Try reading the file in the API instead
const fsp = require('fs').promises
export default async function (req, res) {
try {
const file_data = await fsp.readFile('../../data/data.json')
const json_data = JSON.parse(file_data)
// Do stuff
res.status(200).json(data.something)
}
catch (error) {
console.log(error)
res.status(500).json({ error: 'Error reading data' })
}
}
Actual Static files
In development you can probably work around this by triggering rebuilds when static files update.
If you want update the data files independently of a built app, they will probably need to be hosted separately to the Next build. If you are next exporting a completely static site, you might have a place to put the static files already. If not you can serve the data files with another node process, or a web server, or something like S3.
I am currently building a gallery app using Angular 11 + Electron + Java, but I came across this issue that I have not managed to solve.
Using the backend, I get all the files within a folder the user chooses, but then, when i use the paths as src for , Angular adds http://localhost:4200 before the path.
I can't use the asset folder because the source path of the folder containing the images is chosen by the user and may vary across different PCs.
What is the proper way to deal with this?
I have found a solution.
First thing is to set
webSecurity: false
in electron's main.ts file.
Then, in the same file, register the following protocol:
app.on('ready', () => {
setTimeout(createWindow, 400);
protocol.registerFileProtocol('file', (request, callback) => {
const pathname = decodeURIComponent(request.url.replace('file:///', ''));
callback(pathname);
});
});
Finally, when using the image path, add file:// before the absolute path of the image.
This carries potential security issues, so carefully evaluate how your app is going to be used!
I have already added the codes for serving an image on my node server but it seems to not serve images in the HTML when connecting to Node. I have also external CSS and JS that are being served correctly. Here is the fragment of my code in Node (See below). Thank you in advance!
var server = http.createServer(function(req, res) {
var pathname = url.parse(req.url).pathname;
var ext = path.extname(pathname);
var handler = handlers[req.url];
if(ext) {
if(ext === ".css"){
res.writeHead(200, { "Content-Type" : "text/css" });
}
else if(ext === ".js") {
res.writeHead(200, { "Content-Type" : "text/javascript" });
}
else if(ext === ".jpg") {
res.writeHead(200, { "Content-Type" : "image/jpg" });
}
res.write(fs.readFileSync(__dirname + pathname, "utf8"));
res.end();
}
else if(handler) {
handler(req, res);
}
else {
res.writeHead(404, { "Content-type" : "text/plain" });
res.end();
}
});
server.listen(80);
I've seen a lot of questions like this on Stack Overflow when someone tries to implement their own static file server instead of using Express or something that works, and fails to make it work. If you can implement your own static file server then do it. If you can't, then it should be a sign that maybe it's not a good idea. Update: See below for solutions without Express.
Problems
Just by glancing at your code code I already see several serious problems with it, including:
Your code is insecure - it allows anyone to get any file on your system.
Your code is blocking - it will grind to a halt as soon as you get any concurrent connections.
Your code doesn't work for binary files - only for text files, and only those with UTF-8 encoding
Your code doesn't work for uppercase filenames, .jpeg extension etc.
Your code doesn't serve HTML files correctly
Your code crashes when files don't exist instead of responding with proper code
Solution
Anyone who answers a question like this has two options: either put a lot of effort and time into fixing every one of the problems mentioned above (which rarely happens because it is not a trivial task and that's why all you see are comments mentioning one or two of those problems instead of answers) or you can explain how the task should be done properly instead of adding countless fixes to something that was not a good idea in the first place.
That having been said, what you can do to achieve your goal here in a secure and performant way is to put your static files (HTML, CSS, images etc.) into a directory, e.g. called html and use Express (or some other frameworks, see below) with a simple code like this:
var path = require('path');
var express = require('express');
var app = express();
var htmlPath = path.join(__dirname, 'html');
app.use(express.static(htmlPath));
var server = app.listen(80, function () {
console.log('listening on port', server.address().port);
});
See the full example with explanation on GitHub:
https://github.com/rsp/node-express-static-example
I put this example on GitHub because there are a lot of questions on Stack Overflow related to problems that people have with serving static files in Node. It's open-source, you can adapt it to your own needs and use in your code.
For more info on Express, see:
http://expressjs.com/en/4x/api.html
Other options
Other frameworks that you can use to serve static files include:
koa, Restify, Hapi, Sails, LoopBack and more.
Without a framework
If you still think that you don't want to use a high-level framework that does the job correctly and you want to roll your own solution, maybe for educational purposes, then see this answer:
How to serve an image using nodejs
It explains how to serve static images with:
express.static (express built-in middleware, like in this answer)
express (express but without express.static)
connect (one level below than express)
http (using Node's http module)
net (not even using http module)
All of the examples posted are tested and work on Node versions 4, 5, 6 and 7.
Other related answers:
How to serve an image using nodejs
Failed to load resource from same directory when redirecting Javascript
onload js call not working with node
Sending whole folder content to client with express
Loading partials fails on the server JS
I am new to node.js/express.js and I am reading some tutorials. I am confused because I am used to the simple apache logic, node.js/express.js logic confuses me. Please help me.
This tutorial uses the default express routes to add/get data from a db. But, at the begging , at the part named "PART 2 – OK, FINE, LET'S DO "HELLO, WORLD!" edits the ...\ROUTES\INDEX.JS file to add just a simple html page. Why is that?
Can I just use the public folder to serve my files and access the by using the same URL?
If I have like 50 files, I have to add 50 similar functions to my ...\ROUTES\INDEX.JS so I can serve them ? Even the simplest static files ?
Can I just put all my files in the public folder and then edit app.js and ...\ROUTES\INDEX.JS ?
Also I was reading the first chapter of the book Jump Start Node.js by Don Nguyen. It does not edit routes, just adds methods to the app.js and implements new modules (named db and user) for adding users to the db. This also adds a new get function to app.js for a simple form.html file.
Again, why can I use the public folder and then edit the app.js and create my own modules?
Again, If I have like 50 files, I have to add 50 similar functions to my app.js so I can serve them ? Even the simplest static files ?
Finally,
What is the difference between the two methods ? In which case I use them ?
Which one is the best practice ?
Thank you very much
To serve the folder named "public" as static files:
app.use(express.static(__dirname + '/public'));
The reason the tutorial did not put their 'simple' index page into public, is that their 'simple' page is not static. They pass in the data { title: 'Express' } to the dynamic page.
If the title 'Express' is always going to be static, then yes you can serve it from public. However for the sake of the tutorial, we assume they might dynamically change the title from 'Express' to something else.
I am using jquery templates on both the server-side and client-side. I'm using the jqtpl and express modules on Node.js for the server, and I have jquery and its template plugin for the client.
Wherever possible the client recieves JSON instead of html, and builds the template itself, using the HTML5 history api to change url and allow session navigation. If this isn't possible, the server does the templating instead and sends html.
Both the server and the client have the exact same templates, but the server has them in the form of 12 .html files, and the client has them in the form of an object in a .js file.
Each time I change or add a template, I have to alter the client .js file to be the same, which is a bit of a pain.
What I would like to do is have the .js file dynamically take all of the .html files in my templates folder and compile them into an object. Once I had finished development, this file would be cached, as it no longer needs to look for changes.
Not sure if this answers your question, but if you're interested in having the same templating code on both client and server, you should take a look at weld which would allow you to use the same code on both client and server.
Could you be a bit more clear about what you're doing with regards to the 12 html files vs 1 object on the client?
Code samples would rock, if possible.
What I was looking for was Node's file system module:
http://nodejs.org/docs/v0.4.8/api/fs.html
I used fs.readdir to find all of the template files in the folder, then iterated through the array that produced to read all of its containing files.
var templates = {};
fs.readdir("./templates", function(err, files) {
for(var i = 0, len = files.length; i<len; i++) {
fs.readFile("./templates/" + files[i], function (err, data) {
if (err) {
throw err
}
templates[files[i]] = data;
});
}
}
And then in express:
app.get("/templates.js", function(req, res){
res.header("Content-Type", "text/javascript");
res.end("var templates = { " + JSON.stringify(templates) + " }; ");
});
However, I found that server-side templating was better suited to my needs, and where appropriate, I now send rendered HTML in my JSON responses instead of just data.