I have a data.json file that I would like to load and that I have placed in the lib/ folder. What should I do in order to load that JSON into a variable in the server?
Thanks
There are three ways you can go about this, it depends what you're most comfortable with & your use case.
The first is to store it as a JS Object
if your json data is { "name":"bob" } you could use myjson = {"name":"bob"} in a .js file in the /lib folder and just call myjson when you need it.
Using an http call
You need the Meteor http package, installed via meteor add http.
Server Side code
myobject = HTTP.get(Meteor.absoluteUrl("/myfile.json")).data;
Client Side Code
HTTP.get(Meteor.absoluteUrl("/myfile.json"), function(err,result) }
console.log(result.data);
});
Another way to do it is to fetch the json file ajax style (you would have to put it in your /public folder though and use Meteor.http to call it.
Read the file directly
Lastly you could read the file directly, you store your myfile.json in a private directory in your project's root:
var myjson = {};
myjson = JSON.parse(Assets.getText("myfile.json"));
If you want to access this on the client side you would have to interface it with a Meteor.methods and Meteor.call
So whichever way you want, the first is the easiest but I'm not too sure how you want to use it or whether you want to pick the file or something
As I am new to all this I suspect this is not the correct way to do this, however this has worked for me...
Three coffee script files, two in the server directory:
server.coffee:
Meteor.startup ->
insertSample = (jsondata) ->
Fiber(->
Documents.insert
name: "Sample doc"
data: jsondata
).run()
if Documents.find().count() is 0
insertJSONfile("tests/test.json", insertSample)
and insertJSONfile.coffee:
fs = __meteor_bootstrap__.require("fs")
insertJSONfile = (file, insert) ->
jsondata = undefined
fs.readFile file, (err, data) ->
throw err if err
jsondata = JSON.stringify(JSON.parse(data))
insert(jsondata)
and model.coffee in the root dir:
#Documents = new Meteor.Collection("documents")
On startup this should load and insert the JSON file (in my case I've stored this in the tests directory) into a field in the documents collection.
I would love to hear from others on how this should be done properly.
I assume you want the json content to be represented as an object and not as a simple string.
I use js-yaml (https://github.com/nodeca/js-yaml), assuming you install the npm package. You can also just copy it manually.
yaml = __meteor_bootstrap__.require('js-yaml')
fs = __meteor_bootstrap__.require('fs')
content = fs.readFileSync(file, 'utf8')
object = yaml.load(content)
and that's it! I personally persist my json into meteor collections.
Related
I build a rest service in Deno (Oak) and also serve static files. However, when I run deno compile I would like to have those static files included into the single binary file that is ejected. Is this possible?
From what I can tell, neither Deno nor Oak have intentional support for this.
A downside of even doing this is that your binary file may become large. This isn't only an issue with distribution but may also slow loading and executing the binary.
Nevertheless, one way you can make "static" files available in a compiled binary is to encode the files as JavaScript modules (similar to using WebAssembly in Deno).
e.g. The following module encodes a static file, named example.txt, storing its file type, txt, and its contents, hello world\n. The contents are base64 encoded (thank you jsejcksn for the suggestion). You can encode and decode the contents other ways as well or even use different encodings depending on the file type if you like.
example.txt.ts:
export default {
type: "txt",
data: "aGVsbG8gd29ybGQK",
};
You can programmatically create modules like this from static files.
e.g. encode-as-module.ts:
import { extname } from "https://deno.land/std#0.155.0/path/mod.ts";
import { encode } from "https://deno.land/std#0.155.0/encoding/base64.ts";
const [inputPath, outputPath = `${inputPath}.ts`] = Deno.args;
const type = extname(inputPath).slice(1);
const bytes = await Deno.readFile(inputPath);
const script = /* JavaScript */ `export default {
type: "${type}",
data: "${encode(bytes)}",
};
`;
await Deno.writeTextFile(outputPath, script);
Usage:
deno run --allow-read --allow-write encode-as-module.ts example.txt
Once you have your static files encoded as modules you can then change your Oak app from serving them using send() to serving them using context.response (passing the type and body). More work will need to be done here to encode a list of all the static files, etc. but I think what's already provided here illustrates the idea sufficiently.
The following code works to load a local, static JSON file:
var stories = require('../stories/stories.json');
Now I want to load a file based on a variable, e.g. do something like this:
var storiesPath = '../stories/stories.json';
var stories = require(storiesPath);
But this triggers an error:
Error: Cannot find module '../stories/stories.json'
at require (packages/modules-runtime.js:123:19)
at meteorInstall.server.main.js (server/main.js:7:15)
Is there any way to get this working? I assume that I could load my file via the Meteor http package instead but I'd rather not add another package if I can avoid it.
Thanks for your hints
Like I said in the comment, you can easily use a variable in a require, e.g.,
> var x = 'fs';
> require(x).readFile
[Function]
So that's not the problem you are dealing with. Are you sure your first case indeed works? It would be surprising. I think you might be running into project file layout issues, due to the use of a relative path. I would stay away from that. And fortunately you can quite easily by using an asset! You can put your json file in private/ in your project folder and then use:
const stories = JSON.parse(Assets.getText('stories.json'));
Hi I need to use the NetSuite sFtp Capability to create a file from a saved search and ftp'it to another server. I am wondering after the data that is returned how can I create the file and pass it to the FTP object? It will be a form of csv, can I add it say to the file cabinet and then access from there to pass to the FTP to then send it? Any help is very much appreciated thanks ;
SPS, sorry that would be SS2
I created this tool to help quickstart your Suitescript 2.0 SFTP project. It makes getting the hostkey and passwordGUI a lot easier. I have the code and a tutorial video here.
Check it out here
Video Tutorial
NetSuites sFTP function requires a file.File in the file property of the options. The file could be a dynamic file like the NetSuite SuiteAnswers sample below (this is not my example, this is a SuiteAnswers Sample). Or the file could be a file loaded from the filing cabinet.
I really wish NetSuite would implement a native function to allow savedsearch results to be saved as CSV into the file cabinet as a file. This does not exist as of yet, so you will have to craft your own CSV file.
/**
*#NApiVersion 2.x
*/
require(['N/sftp', 'N/file'],
function(sftp, file) {
var myPwdGuid = "B34672495064525E5D65032D63B52301";
var myHostKey = "AAA1234567890Q=";
var connection = sftp.createConnection({
username: 'myuser',
passwordGuid: myPwdGuid,
url: 'host.somewhere.com',
directory: 'myuser/wheres/my/file',
hostKey: myHostKey
});
var myFileToUpload = file.create({
name: 'originalname.js',
fileType: file.fileType.PLAINTEXT,
contents: 'I am a test file. Hear me roar.'
});
connection.upload({
directory: 'relative/path/to/remote/dir',
filename: 'newFileNameOnServer.js',
file: myFileToUpload,
replaceExisting: true
});
var downloadedFile = connection.download({
directory: 'relative/path/to/file',
filename: 'downloadMe.js'
});
});
I thought this would be easy.
I want to create simple files the user can download by clicking a link.
Write what you want into the servers assets/app folder and then generate a simple link
Download> me!
Writing files into Meteor's server side asset folder is easy. And the download link above will always download a file with the name you specified.
You will get a yourNewFile.txt in the client's download folder. But, unfortunately its content will not be what you wrote on the server (new.txt).
Meteor has the strange behavior of downloading its startup html page as the content if the name of your content wasn't originally in the public folder. I think this is bug .... put the above anchor into a default Meteor project and click the link .. don't even create a public folder. You get a downloaded file with the name you asked for...
So, if you put stubs in the public folder (you know the names of the assets you are going to create) then you can create them dynamically.
I don't know the names before hand. Is there any way to get Meteor to 'update' its assets list with the new names I want to use?
I know there are packages that can do this. I'd like to just do it myself as above, really shouldn't be this hard.
The public/ folder intended use is specifically for static assets. Its content is served by the node http server.
If you want to dynamically generate assets on the server, you can rely on iron:router server side routes.
Here is a simple example :
lib/router.js
Router.route("/dynamic-asset/:filename",function(){
var filename = this.params.filename;
this.response.setHeader("Content-Disposition",
"attachment; filename=" + filename);
this.response.end("Hello World !");
},{
name: "dynamic-asset",
where: "server"
});
In server-side route controllers, you get access to this.response which is a standard node HTTP response instance to respond to the client with the correct server generated content. You can query your Mongo collections using the eventual parameters in the URL for example.
client/views/download/download.html
<template name="download">
{{#linkTo route="dynamic-asset" target="_blank" download=""}}
Download {{filename}}
{{/linkTo}}
</template>
client/views/parent/parent.html
<template name="parent">
{{> download filename="new.txt"}}
</template>
The linkTo block helper must be called in a context where the route parameters are accessible as template helpers. It will generate an anchor tag having an href set to Router.path(route, dataContext). It means that if our server-side route URL is /dynamic-asset/:filename, having a data context where filename is accessible and set to "new.txt" will generate this URL : /dynamic-asset/new.txt.
In this example we set the current data context of the download template to {filename: "new.txt"} thanks to the template invocation syntax.
Note that target="_blank" is necessary to avoid being redirected to the dynamic asset URL inside the current tab, and the download HTML attribute must be set to avoid considering the link as something the browser should open inside a new tab. The download attribute value is irrelevant as it's value will be overriden server-side.
Here is the raw Picker (meteorhacks:picker) route and method I used to get this running. I've kept it lean and its just what I got working and probably not the best way to do this ... the synchronous methods (like readFileSync) throw exceptions if things are not right, so they should be wrapped in try-catch blocks and the mkdirp is a npm package loaded through meteorhacks:npm package hence the Meteor.npmRequire. Thanks again to saimeunt for the directions.
Picker.route('/dynamic-asset/:filename', function(params, req, res, next) {
console.log('/dynamic-asset route!');
var fs = Npm.require('fs');
var path = Npm.require('path');
var theDir = path.resolve('./dynamic-asset');
var filename = params.filename;
var fileContent = fs.readFileSync(theDir + '/' + filename, {encoding:'utf8'});
res.end(fileContent);
});
The Meteor method that creates the file is
writeFile: function(fname, content) {
console.log('writeFile', fname);
var fs = Npm.require('fs');
var path = Npm.require('path');
var mkdirp = Meteor.npmRequire('mkdirp');
// verify/make directory
var theDir = path.resolve('./dynamic-asset');
mkdirp(theDir);
fs.writeFileSync(theDir + '/' + fname, content);
return 'aok';
}
and the hyper link I generate on the client if the file gets created looks like this:
Download lane file now
I incorrectly stated in my original question at the top that you could use stubs and write files into the assets folder. Its not so .. you will only get back the stub ... sorry.
As we all know, Meteor's initial payload sent to the client comprises (in production) a concatenated javascript file containing the Meteor platform, packages, and all templates parsed into Meteor's reactive templating system. Server-side rendering, where the templates are rendered to HTML and sent to the client in the initial payload, is on its way but doesn't have an expected release date yet.
I'm looking for a way to "hack" or approximate server-side rendering given the available functionality in Meteor 0.8.x. Specifically, I want to:
enable the page to render its initial contents without first waiting for the several hundred KB Meteor platform javascript file to be downloaded and parsed.
alternatively, modify Meteor so it only sends the templates it needs to render the initial request in the javascript payload, and fetches the remaining templates once render is complete.
The use case is http://q42.com. I recognise Meteor isn't the best fit for static websites like this one but I want to try and see how far I can get anyway. Right now the Meteor platform JS file is over 600 KB in size (±200 KB gzipped) and I'd like to reduce this size if possible.
Note: I'm aware of and already using Arunoda's fast-render package, which is intended to send data with the initial payload. In this case I want to cut down on time-to-first-render by also getting the templates themselves down faster.
This is a little bit tricky. But there are some things you could do. This may not be the beeest way to do it but it could help you get started somehow.
Meteor is build with many packages as 'default', sometimes some are not needed. You can remove the standard-app-packages and add the packages (that you need and use manually) listed here: https://github.com/meteor/meteor/blob/devel/packages/standard-app-packages/package.js
To cut down the templates you would have to include the bare templates that you use and include the other template's separately and perhaps send down the Template information via a Collection, using a live observer handle to initiate the templates
You would have to 'render' the templates on the server side or store them manually in your collection using Spacebars.compile from the spacebars-compiler package which is a little tricky but you could have it done decently:
This should give you a rough idea, not sure how to get passed the 'eval' bit of it though:
HTML file in /private/template.html
<template name="test">
Hello {{name}}
</template>
JS file in /private/template.js
Template.test.name = function() { return "Bob" }
Server side code
var collection = new Meteor.Collection("templates");
var templateData = Assets.getText("template.html");
var templateJs = Assets.getText("template.js");
var compiled = Spacebars.compile(templateData).toString();
var jsData = templateJs;
collection.insert({templateName:"test", data: templateData, js: templateJs});
Client Side code
collection.find().observeChanges({
added: function(id, fields) {
var template = fields.data,
name = fields.name,
js = fields.js;
Template["name"] = UI.Component.extend({
kind: "name",
render: eval(template),
});
eval(js);
}
});
Then just subscribe to the collection asking for your template and it should exist. If you use iron-router I think (not sure) you could make the subscription wait before the template is rendered so you could have it work.
Again this is just a 'hacky' solution, one thing I personally don't like about it is the use of eval, but javascript needs to run somehow...
You could loop through files in a particular folder using fs = Npm.require('fs') to render each template too.
One alternative would be to inject a 'script' tag calling the compiled js template and template helpers to let the template exist.