I have my code
app.set('views', path..);
originally placed in server.js and I tried to segregate/factor it into a config.server.js (see link), there I implemented underscoreJS each to loop through the modules by their folders' names in my modules/ directory. ['core', 'xt_syncs']. Problem with this trick I try playing is that, app.set('views',..) can't be a Singleton (which loads many things at once). The app.set('views',..) can only have 1 URI for 'views' (module specific, my app contains several modules: core, xt_syncs as you see in the structure), and the app.set appear to fail, and be overwritten by the static uri to modules/second_module.
I write the app myself, picking the middlewares/components I want. I'm trying to reuse some of the assets from MEANjs, mean-stack-relational (MVC, I prefer modules architecture to MVC, that's why my attempt is to build mine), and SEANjs (quite too complex, the stack requires Redis and MySQL5.7, I try building mine so I can get a good understanding of things flow on the fly and exclude Redis and MySQL upgrade).
Now back to the question, obviously, you see in MEANjs and SEANjs , they do in their default.js file:
views: ['modules/*/client/views/**/*.html'],
routes: ['modules/!(core)/server/routes/**/*.js', 'modules/core/server/routes/**/*.js']
QUESTIONS:
1/ How can I implement similar pattern in my app? Notice in the MEANjs and SEANjs, there is * as in modules/*/client and ! as in modules/!(core)/server. app design advices and coding help, please. (this part of the question is not yet addressed)
2/ How related the default.js is to the config.js (initGlobalConfigFolders,initGlobalConfigFiles,...)? I try to wrap my head around to understand config.js and find clues of the glueing. Maybe, my modules[module] as in
modules[module] = {
client: {},
server: {}
};
is one step closer to what they built in the initGlobalConfigFolders method.
3/ Is using build tool (Grunt, Gulp, or Webpack) a must here to achieve that? If so, Can you show me how? (build tool incorporation is in my planning). How can you
Thank you very much.
This patch hinted at implementing app.set('views', view_paths); // where view_paths can be an array of views folders.
2 & 3. Awaiting help and answers.
Related
Hi I am structuring my Node.js project based on this, like so:
Root
product name
index.js: (contains requires for the product and the main export)
productName.js: contains application logic
test
test1.js
test2.js
...
Now I have two questions
What should logically go in index.js? At the moment I have this (would this be a good way to do things and what else might I include in index.js?):
// index.js
var myServer = require('./myServer.js'); // "product name" = "myServer"
module.exports = {
run: myServer.listen
}
Does it matter what I call the object key in module.exports (currently "run")? Why does the server always run when I execute index.js with $ node index.js how does it automatically know to run myServer.listen?
P.S.: I am aware of web structure auto-generation tools, I just wish to understand the logical reason for this suggested structure (the idea of not having any logic in index.js)
As you mentioned this is a Express service, if it is only handling backend of some application or more specifically this is only backend application, I would suggest you change name of your index.js to server.js(Thus explicitly stating that it'll process all service requests).
But if not then even index.js is fine.
Now for
1
What you've put is absolutely fine, apart from this you could require all modules, routes(or controllers whatever you name them) in a way that it serves as entry point to your application. Try not to put any logic in here.
2
Actually the server runs because it executes the script in the file called index.js, the script says myServer.listen, now if you had written console.log("Hello World") and used $ node index.js it would've printed Hello World instead.
Node just expects and executes script that is there in index.js, in your case it is to start the server.
About the logic that why not put anything else in index.js, for me the reasoning I consider good enough is it provides abstraction as it is the entry point I don't want index.js to worry about things like what to do with this data and all. I believe it should provide a base to setup server. Thus following single responsibility to some extent. Also I won't have to touch it ever in projects lifetime unless some major change occurs e.g. I decide to shift from express to something else.
EDIT
Why have a key called run
You seem to have answered it yourself(in comments), you are giving or more proper description would be you're attaching an object to module.exports as it is a object similar to JSON it was supposed to have a key(which could be anything not necessarily run it could've been hii). Now if you don't want to pass a key and export only one thing that is server.listen then you could write same as module.exports = myServer.listen; instead of
module.exports = {
hii: myServer.listen
}
Note that you could export more modules using the way you did. For more details about module.exports refer this or better google about it as this link might expire anytime and does not seem an ideal thing to put on SO.
I'm in the progress of internationalizing an node expressjs-app. The idea is to serve the whole website within a language-subfolder (www.domain.com/en/). I'm kinda struggling wrapping my head around how to organize the app and it seems kinda hard to find some useful resources on this issue on stacko or the web in general.
I feel what makes it challenging here, is the fact that you have to achieve the best in three areas: Usability, SEO, and Performance.
There are a couple of questions:
Where are the response/selected languages to be stored? In the Session?
What is ideally the single source of throuth of the current language setting?
How is the language path affecting the language? (Changing the language to current path? Redirect to active/stored language?)
How are the routes to be organized? What Middleware strategies make sense for detecting and changing languages? Is it necessary to add to all internal links the language subpath, or can this be done by clever routing?
I would love to get some hints, resources, blog articles, repos where I can learn about best practices on this topic.
Cheers
I can highly recommend i18n for node.js. I have used it in 2 node Projects so far and it always worked like a charm. I then always had one json-File for each language I wanted to serve. You need to implement it once in your templates and then it hsould just work.
Regarding configuration an easy example:
// Configuration
app.configure(function() {
[...]
// default: using 'accept-language' header to guess language settings
app.use(i18n.init);
[...]
});
So than i18n will guess the language based on the users browser agent.
What I am always doing is not using an extra route rather I am using a parameter lang and than it is possible to change the language all the time per hrefs. E.g. https://example.com/?lang=de will change to german language. Of course you need in every get of express a helper function to detect if another language is set and then you can handle that. For me that was the easiest way but regarding SEO that is not the best I think.
Of course you can also handle it e.g. with different domains/subdomains as airbnb is doing that. https://nl.airbnb.com vs. https://www.airbnb.com vs. https://www.airbnb.de or as you mentioned with routes does also work very well. But I think that is related with a little more work.
For pros and cons regarding SEO and other you can just google a little bit and have a look at this quora question which also highly recommends the Google Best Practices at this topic.
You don't even need to use a library for a simple localization. I'll show you a simple example:
Let's say you have your language strings in a json at global scope (can be in a file or db too) :
var languageData = {
'en': {
'LOGIN_BTN': 'Login now',
'REGISTER_BTN': 'Register'
},
'tr': {
'LOGIN_BTN': 'Giris',
'REGISTER_BTN': 'Kayit'
}
}
Let's create simple middleware:
function getLanguageStrings(req, res, next) {
var lang = req.acceptsLanguages('en', 'tr', 'fr')
var selectedLang = lang ? lang : 'en' // default to english
req.languageStrings = languageData[selectedLang]
next()
}
Above, I used acceptsLanguages() method to get the preferred language of browser, but you can set cookie from client side and read it in our middleware if you want to.
With the req.languageStrings = languageData[selectedLang] line, I've attached strings to current request so that next middleware can use it.
Let's use our middleware:
app.use(getLanguageStrings)
And in the route, render them to view:
app.get("/info", function (req, res) {
res.render("info.html", {
languageStrings: req.languageStrings
})
})
In view, you now use it with your preferred template engine:
<button class="btn">{{languageStrings.LOGIN_BTN}}</button>
<button class="btn">{{languageStrings.REGISTER_BTN}}</button>
For this purpose I used i18n module (pretty much the same procedure with other localization modules). You keep your translations in simple json files and by default i18n checks for a language depending on a cookie sent by client.
That is pretty much it, I think there is a few other ways to get the language instead of using cookies, for example by request params (as you've mentioned) or by value sent within request body.
It really depends on your needs. This is only available if you use i18n-node-2 module, for the first one you have to use cookies (correct me if I'm wrong).
Example I've created to show how to set it up on your server side.
Localization with Express and i18n
Update:
For i18n-node-2
Like the README.md file says, there is a few functions which you can choose to detect / set needed language:
setLocale(locale)
setLocaleFromQuery([request])
setLocaleFromCookie([request])
setLocaleFromSessionVar([request])
setLocaleFromEnvironmentVariable()
Documentation: i18n-node-2
I'm building an isomorphic React/React-Router/Redux/Webpack application and I'm attempting to implement server side rendering.
My directory looks like:
/client
/actions
/components
/containers
/server
/server.js
In my webpack config, I have aliases set up for all the folders inside client:
var path_base = path.resolve(__dirname, '..');
const resolve = path.resolve;
const base = function() {
var args = [path_base];
args.push.apply(args, arguments);
return resolve.apply(resolve,args);
};
const resolve_alias = base.bind(null, 'src/client');
const aliases = [
'actions',
'components',
'constants',
'containers',
'middleware',
'reducers',
'routes',
'store',
'styles',
'utils',
'validation'
];
so that inside the code that gets bundled by webpack, I can do:
import { Widget } from 'components';
and that import gets resolved by webpack.
Now in my server code, in order to do the rendering, I have to import some of my client files, like routes/index.js. The problem I'm running into when I import my routes file, it's using a webpack alias to another file, say components or containers so naturally, the node js require system can't resolve it.
How do I fix something like that? I looked at this question and it talks about essentially setting up the same aliases that exist in webpack with mock-require. But then the issue becomes that my routes file imports all my components which then all import things like stylesheets, images, etc. Should I then be using something like webpack-isomorphic-tools?
The guides I've been looking at (this for example) are all great at showing how server side rendering is accomplished but none of them really talk about how to resolve all the requires and whatnot.
After battling with this issue for 2 days I settled on babel-plugin-webpack-alias.
What you need to do to resolve paths with that is:
$ npm install --save-dev babel-plugin-webpack-alias
Add the plugin to your .babelrc
Add the aliases to your webpack.config (make sure you use path.join())
Refer to this post if you have problems loading styles
The other option I tried was universal-webpack but I found it to be a bit verbose. If you want to see roughly how the whole server-side loading works, you can check out this video.
If you really want them, run your server side code through babel and use this plugin: https://www.npmjs.com/package/babel-plugin-module-alias which will let you do the same thing as webpack.
Edit: This one works a lot better: https://github.com/jagrem/babel-resolve-relative-module it allows multiple paths
Try to use NODE_PATH. Node will always look for a module in this path during require calls. It allows to short cut your relative paths as you want.
// turn this
import {Widget} from '../../components';
// into this
import {Widget} from 'components';
See Node.js docs for more information.
P.S. this thing is very sensitive, so use it carefully. Now your code tightly depends from the environment and may break somewhere.
If you use webpack-isomorphic-tools then it'll take your webpack config into account for your server side which will make all your aliases work.
https://www.npmjs.com/package/webpack-isomorphic-tools
I am picking apart the demo code for this node.js game framework http://pomelo.netease.com/index.html.
all of the client js files in this folder,
https://github.com/NetEase/lordofpomelo/tree/master/web-server/public/js ,
start with a line similar to this
"__resources__["/app.js"] = {meta: {mimetype: "application/javascript"}, data: function(exports, require, module,__filename, __dirname) { ... " .
Many of them (maybe even all of them) have an "exports." or "module.exports" at the end of the "data" method. I found that "__resources__" is defined in the .jshintrc files in an array as the "predef" property. Does it have something to do with jshint? Can't seem to search out anything specific about this. Just pointing me in the right direction would be a great help.
For anyone wandering through here in the future.
I heard back from the Pomelo devs and they said this "This is our inner framework named colorbox ... it is a node.js style browser side module system derived from cocos2d-javascript"
I'm designing an app with node.js and Express, and I was wondering if it was possible to move certain routing logic out of the app.js file. For exapmle, my app.js currently contains:
app.get('/groups',routes.groups);
app.get('/',routes.index);
Is there a way to move this logic out of the app.js file, and only have something like:
app.get('/:url',routes.get);
app.post('/:url",routes.post);
such that all GET requests would be processed by routes.get and all POST requests processed with routes.post?
You could pass a regular expression as the route definition:
app.get(/.+/, someFunction);
This would match anything. However, if you simply want to move your route definitions outside of your main app.js file, it is much clearer to do something like this:
app.js
var app = require('express').createServer();
...
require('routes').addRoutes(app);
routes.js
exports.addRoutes = function(app) {
app.get('/groups', function(req, res) {
...
});
};
This way, you're still using Express' built-in routing, rather than re-rolling your own (as you'd have to do in your example).
FULL DISCLOSURE: I am the developer of the node module mentioned below.
There is a node module that does kind of what you're asking for (and will, eventually, do more). It offers automatic routing based on convention over configuration for express. The module name is honey-express, but is currently in alpha development and not yet available on NPM (but you can get it from the source at https://github.com/jaylach/honey-express.
A short example of how it works: (Please note that this coffeescript)
# Inside your testController.coffee file. Should live inside /app/controllers
honey = require 'honey-express'
TestController = new honey.Controller
index: ->
# #view() is a helper method to automatically render the view for the action you're executing.
# As long as a view (with an extension that matches your setup view engine) lives at /app/views/controller/actionName (without method, so index and not getIndex), it will be rendered.
#view()
postTest: (data) ->
# Do something with data
Now, inside your app.js file you just have to setup some simple configuration:
# in your app.configure callback...
honey.config 'app root', __dirname + '/app'
app.use honey.router()
Now anytime a request comes in, honey will automatically look for a controller with the specified route, and then look for a matching action.. for example -
/test will automatically route to the index/getIndex() method of
testController
/ will automatically route to the index/getIndex() method of the homeController (the default controller is home), if it exists
/test/test will automatically route to the postTest() method of testController if the http method is POST.
As I mentioned, the module is currently in it's alpha state but the automatic routing works wonderfully and has been tested on two different projects now :) But since it's in alpha development, the documentation is missing. Should you decide to go this route, you can look at the sample I have up on the github, look through the code, or reach out to me and I'd be happy to help :)
EDIT: I should also note that honey-express does require the latest (BETA) version of express as it uses features that are not present in 2.x of express.