Im fairly new to Nodejs and express, I was looking through some tutorials and examples and stumbled across
this inside app.js
var router = require('./router')(app);
What is the purpose of doing this?
This is whats inside the router file
module.exports = function (app) {
// The signup route
app.use('/signup', require('./routes/signup'));
}
You import your routers from another file.
This is a technique for scaffolding. Models, views, controllers and routers are kept in different files and then you import them into a main.js with require().
You create your project modular, it's more easy to scale and develop with team.
This is a popular modular pattern in javascript, often seen in node. Here's what you gain:
You can modularize your code into separate files so you don't end up with big monolith chunks of code.
By requiring the module as a function, you can pass some variable constants (such as the application config, or a datatbase entry point).
You can choose what to expose, and what to keep private by using module.exports which cleans up the global object for the application.
In the code snippet you provided, your passing the app config to the routes file, where you are creating a route that is reliant on the variable. If that route relied on interior logic, that logic could be scoped to the routes.js file rather than be exposed to the rest of the application.
Related
I'm confused by how we import [Publish] functions and [Meteor Methods] that reside under /imports/server to the Blaze client (either in /imports/client/ui or even just under app-name/client).
The classic way, is to just use the publish or meteor method, and everything is consumed by the client without imports. But if everything resides under the /imports directory (including the Blaze templates) how does that work? Are there real examples out there?
Illustration:
// imports/server/publishing/test.js
Meteor.publish('publish.test', function() {
if (this.userId) return TestCollection.find({});
return self.ready();
});
// imports/client/ui/test.js
import { Template } from "meteor/templating";
import { ReactiveDict } from "meteor/reactive-dict";
import { Mongo } from 'meteor/mongo';
import TestCollection from '../../imports/collections/test.js';
import "./test.html";
Template.Test.onCreated(function() {
this.state = new ReactiveDict();
this.autorun(() => {
const subscription = this.subscribe('publish.test');
...
}
});
});
How do server side only stuff make its way to the client in the new imports syle of developing?
UPDATE1:
Reponding to Answer1, would something like this work? Also, does the client look okay?
// app-name/imports/server/trades-pubs.js
// This code only runs on the server
Meteor.publish('trades', function tradesPublication() {
return Trades.find({},{sort: {timestamp: -1}, limit: 1000});
});
// app-name/imports/server/trades-methods.js
Meteor.methods({
// Only on server
'trades.importFromFiles'() {
fs = require('fs');
const path = "/home/daemmon/trades_data/";
var files = fs.readdirSync(path);
...
}
});
// app-name/server/main.js
import '../imports/server/trades-methods.js';
import '../imports/server/trades-pubs.js';
Is this all that's needed to get a publish methods to the client and server side meteor methods avaialbe to the client?
// imports/client/ui/test.js
import { Template } from "meteor/templating";
import { ReactiveDict } from "meteor/reactive-dict";
import { Mongo } from 'meteor/mongo';
import TestCollection from '../../imports/collections/test.js';
import "./test.html";
Template.Test.onCreated(function() {
this.state = new ReactiveDict();
this.autorun(() => {
const subscription = this.subscribe('trades');
...
}
});
});
UPDATE2:
you might want to consider importing app-name/imports/server/trades-methods.js somewhere in your client code as well, i.e. in a file like app-name/client/main.js
I thought we could not import server code on the client? If I wanted to import trades-methods.js for example, I'd have to move it to app-name/imports/api or something outside /imports/server.
UPDATE3:
Reading the Meteor Guide, I'm confused by this paragraph:
.
To fully use the module system and ensure that our code only runs when we ask it to, we recommend that all of your application code should be placed inside the imports/ directory. This means that the Meteor build system will only bundle and include that file if it is referenced from another file using an import (also called “lazy evaluation or loading”).
Meteor will load all files outside of any directory named imports/ in the application using the default file load order rules (also called “eager evaluation or loading”). It is recommended that you create exactly two eagerly loaded files, client/main.js and server/main.js, in order to define explicit entry points for both the client and the server. Meteor ensures that any file in any directory named server/ will only be available on the server, and likewise for files in any directory named client/. This also precludes trying to import a file to be used on the server from any directory named client/ even if it is nested in an imports/ directory and vice versa for importing client files from server/.
These main.js files won’t do anything themselves, but they should import some startup modules which will run immediately, on client and server respectively, when the app loads. These modules should do any configuration necessary for the packages you are using in your app, and import the rest of your app’s code.
.
Doesn't this mean for example that if there is a file inside the [/app-name/imports/server] directory, this file can NOT be imported in the client here [/app-name/client/main.js]?
.
For example I could NOT do the following:
Module inside the imports /server directory:
/app-name/imports/server/server-test.js
Module inside the imports /client directory:
/app-name/imports/client/client-test.js
.
Entry point in Meteor client:
/app-name/client/main.js
// => Would NOT work?
import { ServerTest } from "../../imports/server/server-test.js";
// => Would work?
import { ClientTest } from "../../imports/client/client-test.js";
UPDATE4:
Your wording here on your Update2:
Within the /imports folder, there are no special folder names - so you
can import a file from /imports/server in your client side code.
... is incorrect according to the author of this portion of the Meteor Guide.
First of all, since publications and methods are referenced only by their string name, they don't need to be imported in the code that subscribes to them or calls the functions. When doing Meteor.subscribe('publication') Meteor will try to find a publication named publication in the server, and subscribe to it. Same works with Meteor methods.
However, when using the /imports folder, your publications and methods need to be imported somewhere in server code so that Meteor loads them at all. The best practice to do this is to place a file somewhere in the imports folder, like /imports/startup/server/index.js (as recommended by the Meteor guide), where you simply import all files that declare publications and methods, and then importing this single file in some file outside the imports folder. For more about this, see the Meteor Guide and its example app.
Note also that for Meteor methods, you may want to include them also somewhere in your client code, so that the client can run simulations of them for optimistic UI before the server call returns. To do this, you can do the same as above but with a file like /imports/startup/client/index.js, that you include in the client code. I also recommend checking out the mdg:validated-method package, it makes using methods cleaner.
Update regarding the update in the question:
Yes, that seems like it would work, I think you got the point :)
As a minor detail, as I said, you might want to consider importing app-name/imports/server/trades-methods.js somewhere in your client code as well, i.e. in a file like app-name/client/main.js. This would enable the client to run a simulation of the method and update the UI immediately for better user experience. Don't do this if you don't want to expose some super-secret server code to the client though.
Update 2 in the question
Within the /imports folder, there are no special folder names - so you can import a file from /imports/server in your client side code. However, I do recommend placing code that is only meant for the server, like publications, in a folder named server, and not placing code that is meant to be used from both sides to a folder named server or client. Thus you might want to move your trades-methods.js file outside your /imports/server folder anyway. However this is only for clarity, Meteor does not care about folder names inside /server!
I really, really recommend you to read the Meteor guide, particularly the chapter on application structure and checking out the structure of the related example app. You'll save so much time in the long run!
I'm using Angular2 in my project and I have several modules.
I have base module which is called BaseModule
And have for example two (or more) extra modules - FirstModule and SecondModule.
Each module has his own routing. BaseModule has basic routes for system,
FirstModule and SecondModule has his own separated routes.
BUT
I want to create routes like
/user/10/profile
Where ProfileComponent for user contains into FirstModule
Another examples
/user/10/stories
Where StoriesComponent for user contains into FirstModule
/user/10/news
Where NewsComponent for user contains into SecondModule!!!!
But Angular Router allow only routes like:
/firstmodule/......
/secondmodule/......
So, they should be grouped by module.
I want to do it with modules because I want to have async(lazy) loaded parts of my application.
As I know Angular disallow variants when we async(lazy) load components.
Anybody have ideas how I can create what I want?
For routes in root module define your roots as RouterModule.forRoot(['']) and for routes in the other modules use RouterModule.forChild(['']). Since your child modules will be in the imports of the parent this will route properly.
I'm a beginner at using js modules.
I'm working on a fairly simple web application. It uses typescript and angular 2, which heavily relies on modules.
Most of my app ts files 'import' one or many js modules (usually mostly angular 2 modules).
As I understand, because my app ts files have a top level 'import', they are automatically considered a js module by typescript.
However, I want any of my app ts files to be accessible by any other of my app ts files, without having to 'import' each other. But because they are now modules themselves, ts requires me to do that...
Is it possible?
It seems crazy to me that for each of my app ts file, I should have to declare every other of my app ts files that are used in there (I like to have tiny files with a single class/interface). In addition, this relies on relative paths which breaks as soon as I restructure my folder structure.
Am I thinking about this the wrong way?
You must have a js file which is an entry point to your application right?.. So in that file just import all the modules which you want to access without importing and attach them to the window object. Since the window object is available globally, you can access your module from anywhere without importing the corresponding module. For example,
Consider this scenario:
You have a module in a file called module1.ts
The entry point of your application is a file called index.ts
And you have a module2 where you require something from module1
// module1.ts
function add(first: number, second: number): number {
return first + second
}
export {add}
in your index.ts
// index.ts
import {add} from '<path to module1>/module1';
window.add = add
Now in your module2
// module2.ts
window.add(1, 2)
Since the window object is available globally you can attach as many properties to it as you like.
As far as the type resolution is concerned you can declare a window module with the add function you require in a .d.ts file as follows:
declare module window {
add: (first: number, second: number) => number
}
Declaring dependencies (e.g modules) for each file is a double-edged sword.
The advantage is that there is no 'magic' - you know exactly where each function, variable, class etc. is coming from. This makes it much easier to know what libraries / frameworks are being used and where to look to troubleshoot issues. Compare it to opposite approach that Ruby on Rails uses with Ruby Gems, where nothing is declared and everything is auto-loaded. From personal experience I know it becomes an absolute pain to try to workout where some_random_method is coming from and also what methods / classes I have access to.
You're right that the disadvantage is that it can become quite verbose with multiple imports and moving relative files. Modern editors and IDEs like WebStorm and Visual Studio Code have tools to automatically update the relative paths when you move a file and also automatically add the imports when you reference code in another module.
One practical solution for multiple imports is to make your own 'group' import file. Say you have a whole bunch of utility functions that you use in all your files - you can import them all into a single file and then just reference that file everywhere else:
//File: helpers/string-helpers.ts
import {toUppercase} from "./uppercase-helper";
import {truncate} from "./truncate-helper";
export const toUppercase = toUppercase;
export const truncate = truncate;
Then in any other file:
import * as StringHelpers from "../path-to/helpers/string-helpers";
...
let shoutingMessage = StringHelpers.toUppercase(message);
The disadvantage of this is that it may break tree shaking, where tools such as webpack remove unused code.
Is it possible
Not in any easy way. The ts file is a module and uses e.g. module.exports (if commonjs) that will need to be shimmed out. And that is just the runtime story. The TypeScript story will be harder and one way would be to make a .d.ts file for the module stating the contents as global.
Like I said. Not worth doing. Modules are the way forward instead of making something hacky.
It's not crazy at all. You are definitively thinking in the wrong way.
Actually what you don't like it's a common feature in all modern programming languages and it makes the code and structure of the app a lot clearer and simple to understand.
Without imports and going to old school way looks very crazy to me :)
You can have only chaos with so many global variables.
I'm working in a project with angular and browserify, this is the first time for me to use this two tools together, so I would like some advice on which is the way to require files with browserify.
We may import those files in different ways, Until now I experimented this way:
Angular App:
app
_follow
- followController.js
- followDirective.js
- followService.js
- require.js
- app.js
For each folder with in the files for a plugin I created an require.js file and in it I require all the files of that folder. Like so:
var mnm = require('angular').module('mnm');
mnm.factory('FollowService', ['Restangular',require('./followService')]);
mnm.controller('FollowController',['$scope','FollowService',require('./followController')])
mnm.directive('mnmFollowers', ['FollowService',require('./followDirective')]);
and then require all require.js files in a unique file called app.js that will generate the bundle.js
Question:
This way to require the files can be a good structure, or it will have some problem when I need to test? I would like to see your way to achieve good structure with angular and browserify
AngularJS and browserify aren't, sadly, a great match. Certainly not like React and browserify, but I digress.
What has worked for me is having each file as an AngularJS module (because each file is already a CommonJS module) and having the files export their AngularJS module name.
So your example would look like this:
app/
app.js
follow/
controllers.js
directives.js
services.js
index.js
The app.js would look something like this:
var angular = require('angular');
var app = angular.module('mnm', [
require('./follow')
]);
// more code here
angular.bootstrap(document.body, ['mnm']);
The follow/index.js would look something like this:
var angular = require('angular');
var app = angular.module('mnm.follow', [
require('./controllers'),
require('./directives'),
require('./services')
]);
module.exports = app.name;
The follow/controllers.js would look something like this:
var angular = require('angular');
var app = angular.module('mnm.follow.controllers', [
require('./services'), // internal dependency
'ui.router' // external dependency from earlier require or <script/>
// more dependencies ...
]);
app.controller('FollowController', ['$scope', 'FollowService', function ...]);
// more code here
module.exports = app.name;
And so on.
The advantage of this approach is that you keep your dependencies as explicit as possible (i.e. inside the CommonJS module that actually needs them) and the one-to-one mapping between CommonJS module paths and AngularJS module names prevents nasty surprises.
The most obvious problem with your approach is that you're keeping the actual dependencies that will be injected separate from the function that expects them, so if a function's dependencies change, you have to touch two files instead of one. This is a code smell (i.e. a bad thing).
For testability either approach should work as Angular's module system is essentially a giant blob and importing two modules that both define the same name will override each other.
EDIT (two years later): Some other people (both here and elsewhere) have suggested alternative approaches so I should probably address them and what the trade-offs are:
Have one global AngularJS module for your entire app and just do requires for side-effects (i.e. don't have the sub-modules export anything but manipulate the global angular object).
This seems to be the most common solution but kind of flies in the face of having modules at all. This seems to be the most pragmatic approach however and if you're using AngularJS you're already polluting globals so I guess having purely side-effect based modules is the least of your architectural problems.
Concatenate your AngularJS app code before passing it to Browserify.
This is the most literal solution to "let's combine AngularJS and Browserify". It's a valid approach if you're starting from the traditional "just blindly concatenate your app files" position of AngularJS and want to add Browserify for third-party libs, so I guess that makes it valid.
As far as your app structure goes this doesn't really improve anything by adding Browserify, though.
Like 1 but with each index.js defining its own AngularJS sub-module.
This is the boilerplate approach suggested by Brian Ogden. This suffers from all the drawbacks of 1 but creates some semblance of hierarchy within AngularJS in that at least you have more than one AngularJS module and the AngularJS module names actually correspond to your directory structure.
However the major drawback is that you now have two sets of namespaces to worry about (your actual modules and your AngularJS modules) but nothing enforcing consistency between them. Not only do you have to remember to import the right modules (which again purely rely on side-effects) but you also have to remember to add them to all the right lists and add the same boilerplate to every new file. This makes refactoring incredibly unwieldy and makes this the worst option in my opinion.
If I had to chose today, I would go with 2 because it gives up all pretense of AngularJS and Browserify being able to be unified and just leaves both to do their own thing. Plus if you already have an AngularJS build system it literally just means adding an extra step for Browserify.
If you're not inheriting an AngularJS code base and want to know which approach works best for starting a new project instead: don't start a new project in AngularJS. Either pick Angular2 which supports a real module system out of the box, or switch to React or Ember which don't suffer from this problem.
I was trying to use browserify with Angular but found it got a bit messy. I didn't like the pattern of creating a named service / controller then requiring it from another location, e.g.
angular.module('myApp').controller('charts', require('./charts'));
The controller name / definition is in one file, but the function itself is in another. Also having lots of index.js files makes it really confusing if you lots of files open in an IDE.
So I put together this gulp plugin, gulp-require-angular which allows you write Angular using standard Angular syntax, all js files which contain angular modules and dependencies of angular modules which appear in your main module dependency tree are require()'d into a generated entry file, which you then use as your browserify entry file.
You can still use require() within your code base to pull in external libraries (e.g lodash) into services / filters / directives as needed.
Here's the latest Angular seed forked and updated to use gulp-require-angular.
I've used a hybrid approach much like pluma. I created ng-modules like so:
var name = 'app.core'
angular.module(name, [])
.service('srvc', ['$rootScope', '$http', require( './path/to/srvc' ))
.service('srvc2', ['$rootScope', '$http', require( './path/to/srvc2' ))
.config...
.etc
module.exports = name
I think the difference is that I don't define individual ng-modules as dependencies to the main ng-module, in this case I wouldn't define a Service as an ng-module and then list it as a dep of the app.core ng-module. I try to keep it as flat as possible:
//srvc.js - see below
module.exports = function( $rootScope, $http )
{
var api = {};
api.getAppData = function(){ ... }
api.doSomething = function(){ ... }
return api;
}
Regarding the comment of code-smell, I disagree. While it's an extra step, it allows for some great configurability in terms of testing against mock-services. For instance I use this quite a bit for testing agains services that might not have an existing server-API ready:
angular.module(name, [])
// .service('srvc', ['$rootScope', '$http', require( './path/to/srvc' ))
.service('srvc', ['$rootScope', '$http', require( './path/to/mockSrvc' ))
So any controller or object dependent on srvc doesn't know which it is getting. I could see this getting a bit convoluted in terms of services being dependent on other services, but that to me is bad design. I prefer to use ng's event system to communicate betw. services so that you keep their coupling down.
Alan Plum's answer is just not a great answer or at least not a great demonstration of CommonJS modules and Browserify with Angular. The claim that Browserify does not mix well with Angular, compared to React is just not true.
Browserify and a CommonJS module pattern work great with Angular, allowing you to organize by features instead of types, keep vars out of global scope and share Angular Modules across apps easily. Not to mention you do not need to ever add a single <script> to your HTML ever again thanks to Browserify finding all your dependencies.
What is particular flawed in Alan Plum's answer is not letting requires in each index.js for each folder dictate dependencies for Angular modules, controllers, services, configurations, routes etc. There is no need for a single require in the Angular.module instantiation, nor a single module.exports as in the context that Alan Plum's answer suggests.
See here for a better module pattern for Angular using Browserify: https://github.com/Sweetog/yet-another-angular-boilerplate
I come from a django background, and basically, the framework allows for a lot of modular code. I've created a simple blog engine in nodejs and express. However, all the routes end up being in my main app.js file, or rather app.coffee, since I used coffeescript for my nodejs applications, which complied to javascript.
So, say this is how my routes look:
app.get('/', index.index)
app.get('/users', user.list)
app.get('/blog', blog.blogList)
app.get('/blog/:id(\\d{5})', blog.blogEntry)
Now, the problem here is that if I want to sort these by categories, then this happens, then I would have to add another app.get function to the same file. Code:
app.get('/blog/categores/:cat(\w+), blog.someotherview)
If I wanted to add sorting according to time, for example:
app.get('/blog/time/:year(\\d{4}), blog.someYearView)
What I would like to do is delegate everything concerning /blog to be handled by blog.js for example. Ideally, how do I get all these routes out of the main app.js file?
You could easily do this by using the include() method in django.
Create an Express app in your app.js file, as you are used to. Then, do the same in the blog.js file. Import and use it within app.js as follows:
var blog = require('./blog');
var app = express();
app.use(blog);
Inside your blog.js file, all you need to do is to export your app:
var app = express();
app.get('/blog/...', ...);
module.exports = app;
To put it in other words: Any Express app can be used as middleware for any other Express app, hence you can create sub-apps.
Hope this helps.
PS: TJ Holowaychuk (the creator of Express) created a video on this, Modular web applications with Node.js and Express.