I use NodeJS and Angular/TS to create my Single Page Application (therefore browser/client side), and there I need to do modify some Url paths. I tried to use the path module, but this seems to only work on the server side (with express).
I also found the url module, but it doesn't have functions like normalize. One specific use case is to convert a path from A to B.
let A = "http://www.example.com/a/b/c"
let B = normalize(join(A, ".."));
console.log(B); // http://www.example.com/a/b/
https://github.com/browserify/path-browserify
This module is part of the https://github.com/webpack/node-libs-browser collection, which is deprecated (idk why). However it is reputable and stable, so feel free to use it.
Related
I followed the documentation to put the constants in the lib/constants.js file.
Question:
How to access these constants in my client side html and js files?
Variables in Meteor are file-scoped.
Normally a var myVar would go in the global Node context, however in Meteor it stays enclosed in the file (which makes it really useful to write more transparent code). What happens is that Meteor will wrap all files in an IIFE, scoping the variables in that function and thus effectively in the file.
To define a global variable, simply remove the var/let/const keyword and Meteor will take care to export it. You have to create functions through the same mechanism (myFunc = function myFunc() {} or myFunc = () => {}). This export will either be client-side if the code is in the client directory, or server-side if it is in the server directory, or both if it is in some other not-so-special directories.
Don't forget to follow these rules:
HTML template files are always loaded before everything else
Files beginning with main. are loaded last
Files inside any lib/ directory are loaded next
Files with deeper paths are loaded next
Files are then loaded in alphabetical order of the entire path
Now you may run into an issue server-side if you try to access this global variable immediately, but Meteor hasn't yet instantiated it because it hasn't run over the file defining the variable. So you have to fight with files and folder names, or maybe try to trick Meteor.startup() (good luck with that). This means less readable, fragile location-dependant code. One of your colleague moves a file and your application breaks.
Or maybe you just don't want to have to go back to the documentation each time you add a file to run a five-step process to know where to place this file and how to name it.
There is two solutions to this problem as of Meteor 1.3:
1. ES6 modules
Meteor 1.3 (currently in beta) allows you to use modules in your application by using the modules package (meteor add modules or api.use('modules')).
Modules go a long way, here is a simple example taken directly from the link above:
File: a.js (loaded first with traditional load order rules):
import {bThing} from './b.js';
// bThing is now usable here
File: b.js (loaded second with traditional load order rules):
export const bThing = 'my constant';
Meteor 1.3 will take care of loading the b.js file before a.js since it's been explicitly told so.
2. Packages
The last option to declare global variables is to create a package.
meteor create --package global_constants
Each variable declared without the var keyword is exported to the whole package. It means that you can create your variables in their own files, finely grain the load order with api.addFiles, control if they should go to the client, the server, or both. It also allows you to api.use these variables in other packages.
This means clear, reusable code. Do you want to add a constant? Either do it in one of the already created file or create one and api.addFiles it.
You can read more about package management in the doc.
Here's a quote from "Structuring your application":
This [using packages] is the ultimate in code separation, modularity, and reusability. If you put the code for each feature in a separate package, the code for one feature won't be able to access the code for the other feature except through exports, making every dependency explicit. This also allows for the easiest independent testing of features. You can also publish the packages and use them in multiple apps with meteor add.
It's amazing to combine the two approaches with Meteor 1.3. Modules are way easier and lighter to write than packages since using them is one export line and as many imports as needed rather than the whole package creation procedure, but not as dumb-error-proof (forgot to write the import line at top of file) as packages.
A good bet would be to use modules first, then switch to a package as soon as they're tiring to write or if an error happened because of it (miswritten the import, ...).
Just make sure to avoid relying on traditional load order if you're doing anything bigger than a POC.
You will need to make them global variables in order for other files to see them.
JavaScript
/lib/constants.js
THE_ANSWER = 42; // note the lack of var
/client/some-other-file.js
console.log(THE_ANSWER);
CoffeeScript
/lib/constants.coffee
#THE_ANSWER = 42
/client/some-other-file.coffee
console.log THE_ANSWER
Is there a way to substitute variables in javascript files, with a preprocessor during build process. I uses grunt, usemin, uglifyjs (part of yeoman stack).
I currently refer to url from a global javascript object. For example,
my.url = {
book: {
get : '/my/book/{id},
new: '/my/book'
}
}
in my program, I may refer the url as my.url.book.get, etc. The intention is
do not want the url string spread across the program, as any change during development make it hard to refactor.
url may generate based on the server API, and don't want to duplicate in client.
Now, once I am happy with the development, I like to preprocess all the javascript file to substitute all these references to actual url string. Intention is to avoid loading an extra file with all the url (may the user only need few of the url).
is there any tool, similar to html templating package, to process the javascript and replace all the variables. I prefer if it works with grunt/yeoman stack.
You can do that with grunt-replace It allows for all kinds of string substitutions in text files. I use it to sync version numbers in bower.json, package.json etc, but obviously you can use it for source file value substitutions as well.
That said, in your case I'd definitely opt for a more dynamic solution with env variables, with for instance grunt-env.
Try #Builder https://github.com/electricimp/Builder
Little example
in config.js:
#set apiEndpoint "https://somesite.com/api/v1"
then:
#include once "config.js"
let url = "#{apiEndpoint}"
I am learning the source code of hexo, a project based on node.js.
And there is a file init.js:
if (results.config){
require('./plugins/tag');
require('./plugins/deployer');
require('./plugins/processor');
require('./plugins/helper');
require('./plugins/filter');
require('./plugins/generator');
}
why these require statements have no reference? So I checked each index.js under these folder(e.g. tag), the index.js is looking like:
require('./init');
require('./config');
require('./generate');
require('./server');
require('./deploy');
require('./migrate');
require('./new');
require('./routes');
require('./version');
require('./render');
No exports found. I am wondering how these requires work.
I looked at the source you're talking about, and the basic answer to your question is that the code in those requires gets run. Normally, you're right that you need to have some kind of export to make use of objects inside those files, but hexo is being a bit nonstandard.
Instead of having each module be independent and fairly agnostic (except via requires), what they're doing is creating an object called 'extend' (look in extend.js) then each of those individual files (e.g. ./init, ./migrate, etc) require extend.js and hang new objects and functions on it in a sort of namespaced fashion.
If you look at the end of those files you'll see something calls to extend.tag.register and others. Modules are cached when required, so in practice it acts something like a singleton in other languages the way they're doing it.
As Paul points out, the requires you see should be considered as functional units themselves, rather than returning any useful values. Each of the files calls an function to modify an internal state.
I have a need where I need to execute node code/modules in a node app (in a sandbox) with vm.createScript / script.runInNewContext. The host node app runs on heroku, so there is no local filesystem to speak of. I am able to download and run code that has no outside dependencies just fine, however the requirement is to be able to include other node modules as well. (as a build/packaging step would be ideal)
There are many existing solutions (browserify is one I've spent the most time with) which get close... but they inevitably generate a single blob of code (yeah!), meant to execute in a browser (boo!). Browserify for example generates dependencies on window., etc.
Does anyone know of a tool that will either read a package.json dependencies{} (or look at all require()'s in the source) and generate a single monolithic blob suitable for node's runInNewContext?
I don't think the solution you're looking for is the right solution. Basically you want to grab a bunch of require('lib')'s, mush them together into a single Javascript context, serialize that context into source code, then pass that serialized form into the runInNewContext function to deserialize and rebuild into a Javascript context, then deserialize your custom, sandboxed code, and finally run the whole thing.
Wouldn't it make much more sense to just create a context Object that includes the needed require('lib')'s and pass that object directly into your VM? Based on code from the documentation:
var vm = require('vm'),
initSandbox = {
async: require('async'),
http: require('http')
},
context = vm.createContext(initSandbox);
vm.runInContext("async.forEach([0, 1, 2], function(element) { console.log(element); });", context);
Now you have the required libraries accessible via the context without going through a costly serialization/deserialization process.
I'm shipping socket.io as part of my code for 3rd party sites to use. I don't want it to pollute the global namespace (e.g. different versions of io will collide) but rather make it work only as part of my library, So it will be namespaced and called only from
MyLibrary.io
How do I go about this?
Since you have total control over the file, then the easiest thing to do would be to just modify the file to load socket.io at a new location.
The easiest way I would say to do that would be to wrap the contents of dist/socket.io.js with
(function() {
// All Standard SocketIO code
}).call(MyLibrary);
That will make the file load io onto MyLibrary instead. SocketIO, like many libraries, uses this to decide how to load things. In a browser circumstance, this is the object window, but by wrapping a function around everything, you can control this and change it to your own value by using the method call.
Many other libraries, though not socketIO, have a helper to avoid exactly this problem. Often they have a method called noConflict(). For example, if you wanted to avoid a problem like this for jQuery, you could do:
MyLibrary.$ = MyLibrary.jQuery = jQuery.noConflict(true);
That works because when jQuery loads, it saves a reference to the previously loaded version, so that if it needs to, it can set the global objects back to how they were.
It seems that the suggested way to do this (Issue #85) is to load it as per normal then run these two lines:
MyLibrary.io = window.io; // Assign it to your desired namespace
delete window.io; // Remove it from the window namespace
The code in socket.io.js only adds the io variable to the window.
You could modify the code in socket.io.js but that might make it hard to maintain in the future since you would have to track changes you make to that file and propagate them into newer versions of socket.io.js.
At first, I thought you could do something with module.exports since it had the CommonJS format, however, after reading the code, I realized it's just the way things were organized before building the socket.io.js file. See the file directory here for what I'm referring to.