generating and serving static files with Meteor
In version 0.6.6.3 0.7.x - 1.3.x you can do the following:
To write
var fs = Npm.require('fs');var filePath = process.env.PWD + '/.uploads_dir_on_server/' + fileName;fs.writeFileSync(filePath, data, 'binary');
To serve
In vanilla meteor app
var fs = Npm.require('fs');WebApp.connectHandlers.use(function(req, res, next) { var re = /^\/uploads_url_prefix\/(.*)$/.exec(req.url); if (re !== null) { // Only handle URLs that start with /uploads_url_prefix/* var filePath = process.env.PWD + '/.uploads_dir_on_server/' + re[1]; var data = fs.readFileSync(filePath); res.writeHead(200, { 'Content-Type': 'image' }); res.write(data); res.end(); } else { // Other urls will have default behaviors next(); }});
When using iron:router
This should be a server side route (ex: defined in a file in /server/
folder)
Edit (2016-May-9)
var fs = Npm.require('fs');Router.route('uploads', { name: 'uploads', path: /^\/uploads_url_prefix\/(.*)$/, where: 'server', action: function() { var filePath = process.env.PWD + '/.uploads_dir_on_server/' + this.params[0]; var data = fs.readFileSync(filePath); this.response.writeHead(200, { 'Content-Type': 'image' }); this.response.write(data); this.response.end(); } });
Outdated format:
Router.map(function() { this.route('serverFile', { ...// same as object above }});
Notes
process.env.PWD
will give you the project rootif you plan to put files inside your project
- don't use the
public
orprivate
meteor folders - use dot folders (eg. hidden folders ex:
.uploads
)
Not respecting these two will cause local meteor to restart on every upload, unless you run your meteor app with:
meteor run --production
- don't use the
- I've used this approach for a simple image upload & serve (based on dario's version)
- Should you wish for more complex file management please consider CollectionFS
The symlink hack will no longer work in Meteor (from 0.6.5). Instead I suggest creating a package with similar code to the following:
packge.js
Package.describe({ summary: "Application file server."});Npm.depends({ connect: "2.7.10"});Package.on_use(function(api) { api.use(['webapp', 'routepolicy'], 'server'); api.add_files([ 'app-file-server.js', ], 'server'); });
app-file-server.js
var connect = Npm.require('connect');RoutePolicy.declare('/my-uploaded-content', 'network');// Listen to incoming http requestsWebApp.connectHandlers .use('/my-uploaded-content', connect.static(process.env['APP_DYN_CONTENT_DIR']));
I was stuck at the exact same problem, where i need the users to upload files in contrast to your server generated files. I solved it sort of by creating an "uploads" folder as sibling to the "client public server" on the same folder level. and then i created a simbolic link to the '.meteor/local/build/static' folder like
ln -s ../../../../uploads .meteor/local/build/static/
but with nodejs filesystem api at server start time
Meteor.startup(function () { var fs = Npm.require('fs'); fs.symlinkSync('../../../../uploads', '.meteor/local/build/static/uploads'); };
in your case you may have a folder like "generatedFiles" instead of my "uploads" folderyou need to do this every time the server starts up cuz these folders are generated every time the server starts up e.g. a file changes in your implementation.