I've been trying to modularize my server and web apps. i've read about exports and module.exports in Node here and here.
http://www.sitepoint.com/understanding-module-exports-exports-node-js/
http://liangzan.net/blog/blog/2012/06/04/how-to-use-exports-in-nodejs/
I get how it makes the functions available to other files / scripts, but what happens to the modules required within the exported file? If I require websockets in some file, export it and require it within another file, does the other file inherit the websockets from the exported file? Is it similar to a header file in C and just pastes that module into your file?
When you require() a module in node, it gets executed inside a closure and the value exported by the module is cached. So any additional require()s for the same module (located at the same absolute path) will always get the same object/value/whatever.
So in your websockets example, the require('websockets') that you do in your module is not automagically available to anyone requiring your module. Everything in a module is done within a separate, local scope (you can read/write the global scope accessible by all modules, but you really should not do that). This is why you need to explicitly export values for them to be seen by outsiders.
Related
I'm going through a project where in app.js the AWS module is required and its config is set via AWS.config.update. In a later file, AWS is required again but this time it uses the credentials set in the app.js file earlier. How does this work? I would have thought that we need to set the credentials again since the module is being re-imported in a different file.
It would help to see the project structure or files but here is what I am thinking:
app.js is run first (as I am guessing this is your index) and thats where the credentials are configured originally.
Then later, when you require the module again in a different point of the application, since app.js already executed at the start there is no need to reconfigure the AWS module as it already holds its present configuration.
Current code in /config/index.js
const options = (require('js-yaml')).safeLoad(
(require('fs')).readFileSync(`./config/default-config.yaml`, "utf8"));
module.exports = options;
Works fine. Until I publish and use it in my other project. Then it's unable to find the file (naturally) as ./config/default-config.yaml doesn't exist in that project.
The only option I can think of involves checking to see if the file exists at that path, then trying to load it from node_modules/#company/alpha-gamma/config/default-config.yaml. This seems really hacky.
The config object is large, 200+ keys. I don't think it belongs in the code.
What's the best solution for loading a file that exists inside your module? I need to be able to load it for unit tests before publishing and load it at runtime when the library is required by another module.
Maybe the best alternative is to use json since I can then use the require module to load it in, instead of fs.
While I originally suggested utilizing __dirname as a valid option, I was wrong. Calling process.cwd() to fetch the application root and building the path off of that is the best approach.
As documented here:
Proper way to reference files relative to application root in Node.JS
So, currently I am working on a project in Reactjs that displays a customised modal.
The configuration of the modal is fetched through a configurationLoader.js file.
Since, it is developed in React, my components are divided across different files.
Currently, what I am doing is, loading the full configuration file and extracting the relevant information when required.
What I find redundant is, I have to require the configuration file at the start of every .js file.
Is there a way, where I export my module once, and its valid globally? .i.e. I don't have to require it again and again?
Globals are registered in the window object for the browser and in the global object in node. So you could do:
window.myConfiguration = require('configurationLoader')
or
global.myConfiguration = require('configurationLoader')
depending on where your code will run. Then you should be able to access myConfiguration anywhere in your code without needing to require it.
I have a Node.js project written in TypeScript. In my project, I have a folder named "public" which contains the client side code & HTML and also a file named classes.ts which is supposed to be shared to the server side.
The problem is that I need to add "export" before the classes declaration in order to make them accessible in the server, but then in the browser I get this Error:
Uncaught ReferenceError: exports is not defined
I found these questions:
https://github.com/Microsoft/TypeScript/issues/5094,
Setup a Typescript project with classes shared between client and server apps?,
Share module between client and server with TypeScript,
which suggests using commonjs in the server but amd in the client. The problem with this solution is that they have 3 different projects (server, client and shared) whereas I only have one project in which I use commonjs.
Another suggestion is:
the other option, which is more convoluted and will require a post
build step to massage the code; if you can not use module loaders in
your client code, is to isolate all module dependencies in your server
code, then in the shared, they are just classes. Build the shared
files without --module, and no exports or imports, but all inside a
single namespace, say namespace MyApp { ... }; in your client code,
you include them directly, and emit using --out. in your server code,
you first emit the shared code to a single file, shared.js, and a
single .d.ts shared.d.ts, augment these with some code to export them
as a module, e.g. append exports = MyApp at the end of your shared.js
and shared.d.ts, then import them from your server code.
But I don't want to deal with updating .d.ts files all the time, and I'm also not sure it will work in one project.
Any suggestion how to make a TypeScript class accessible both in browser and server?
Any help will be profoundly appreciated!
This is absolutely possible.
I have a project containing both SPA client application that runs in browser and server running in node.js that both share common typescript classes. For all of this I have just one tsconfig.json file (I am still not sure that this is the best approach but for now it works just fine)
Here are parts of my setup:
Use modules (previously called external modules). No need for namespaces and d.ts files for your own modules.
module = "commonjs" in tsconfig.
On client side use System.js as module loader (this will solve your 'Uncaught ReferenceError: exports is not defined'). You can use angular2 5 min quickstart as reference how to setup system.js.
It works like a charm.
1) In node on the backend to link one javascript file to another we use the require statement and module.exports.
This allows us to create modules of code and link them together.
How do the same thing in Meteor?
2) On the front end, in Meteor is I want to access a code from another front end javascript file, I have to use globals. Is there a better way to do this, so I can require one javascript file in another file? I think something like browserify does this but I am not sure how to integrate this with Meteor.
Basically if on the client I have one file
browserifyTest.coffee
test = () ->
alert 'Hello'
I want to be able to access this test function in another file
test.coffee
Template.profileEdit.rendered = ->
$ ->
setPaddingIfMenuOpen()
test()
How can I do this in Meteor without using globals?
Meteor wraps all the code in a module (function(){...your code...})() for every file we create. If you want to export something out of your js file (module), make it a global. i.e don't use var with the variable name you want to export and it'll be accessible in all files which get included after this module. Keep in mind the order in which meteor includes js files http://docs.meteor.com/#structuringyourapp
I don't think you can do this without using globals. Meteor wraps code in js files in SEF (self executing function) expressions, and exports api is available for packages only. What problem do you exactly have with globals? I've worked with fairly large Meteor projects and while using a global object to keep my global helpers namespaces, I never had any issues with this approach of accessing functions/data from one file in other files.
You can use a local package, which is just like a normal Meteor package but used only in your app.
If the package proves to be useful in other apps, you may even publish it on atmosphere.
I suggest you read the WIP section "Writing Packages" of the Meteor docs, but expect breaking changes in coming weeks as Meteor 0.9 will include the final Package API, which is going to be slightly different.
http://docs.meteor.com/#writingpackages
Basically, you need to create a package directory (my-package) and put it under /packages.
Then you need a package description file which needs to be named package.js at the root of your package.
/packages/my-package/package.js
Package.describe({
summary:"Provides test"
});
Package.on_use(function(api){
api.use(["underscore","jquery"],"client");
api.add_files("client/lib/test.js","client");
// api.export is what you've been looking for all along !
api.export("Test","client");
});
Usually I try to mimic the Meteor application structure in my package so that's why I'd put test.js under my-package/client/lib/test.js : it's a utility function residing in the client.
/packages/my-package/client/lib/test.js
Test={
test:function(){
alert("Hello !");
}
};
Another package convention is to declare a package-global object containing everything public and then exporting this single object so the app can access it.
The variables you export NEED to be package-global so don't forget to remove the var keyword when declaring them : package scope is just like regular meteor app scope.
Last but not least, don't forget to meteor add your package :
meteor add my-package
And you will be able to use Test.test in the client without polluting the global namespace.
EDIT due to second question posted in the comments.
Suppose now you want to use NPM modules in your package.
I'll use momentjs as an example because it's simple yet interesting enough.
First you need to call Npm.depends in package.js, we'll depend on the latest version of momentjs :
/packages/my-moment-package/package.js
Package.describe({
summary:"Yet another moment packaged for Meteor"
});
Npm.depends({
"moment":"2.7.0"
});
Package.on_use(function(api){
api.add_files("server/lib/moment.js");
api.export("moment","server");
});
Then you can use Npm.require in your server side code just like this :
/packages/my-moment-package/server/moment.js
moment=Npm.require("moment");
A real moment package would also export moment in the client by loading the client side version of momentjs.
You can use the atmosphere npm package http://atmospherejs.com/package/npm which lets you use directly NPM packages in your server code without the need of wrapping them in a Meteor package first.
Of course if a specific NPM package has been converted to Meteor and is well supported on atmosphere you should use it.