Angular.js extend $inject so it can load files? - javascript

I'm starting a new angular project from a scratch and I want to avoid using require.js, browserify or webpack entirely. I'm gonna put all my code into separate files - no monolithic controllers.js or directives.js files...
Few options that are left are:
Use <script> tags and always put new files at the bottom (downside I might mess up order of the files at some point)
Use concatination mechanism, i.e. gulp-concat or grunt-concat
Both of them are ugly - first is maintenance nightmare and the second requires build step and file watcher setup...
The closest thing that I could use is require.js but I'm really disgusted with how the code looks after combining angular with require:
define([], function () {
angular.module('app').controller('BlaBlaController', function () { ... });
})
Since angular is handling all the DI for me require.js is used only for file loading which is kinda sad and makes require.js overkill for such a small task.
What I want to make is extend $inject service so that it would know how to load external files and that's how imagine it should look like:
Create di.config.js file where I specify paths for various "injectables" (much like require.conf.js
Create a simple script loader that would know how to recursively load modules
Now for DI mechanism
--
if (injectableIsLoaded) {
angular.module('app').controller('Controller', function (dep1) {});
} else if (injectableHasPath) {
diLoader.load(injectablePath).then(evalModule);
} else {
throw "No path for module";
}
Does anyone know if that would be possible at all?
What I win from this - I don't need to wrap my angular code in weird require.js calls, don't need a build step, can keep all files separete and load them separatly on demand...

Related

Webpack config with multiple entries and a global site wide entry

I'm moving from requirejs to webpack.
In my require js setup, I have a site-wide file site.js that does some global setup, and non-page-specific stuff, like ajax prefilters, some global ui component setup, etc.
Some pages have self contained js apps specifically for a given page, where I'd have window.appPaths = ['some/path/to/app.js'] set in the template, and site.js would load up the app once the initial site wide stuff was done.
However, moving to webpack, it's reading my require(window.appPaths) and then it converts it to some regex and attempts to bundle every single js file in my src directory.
So basically, I'm wondering if there's a way for me to set this up to have multiple entry points, one being something like site.js and another being something like somePageApp.js wherein site.js is actually a dependency of the latter, but the latter doesn't always exist.
Sigh, hopefully that's clear, i'll elaborate where necessary.
edit: This is how it was set up in require.js setup, my output was:
html for an app page:
<script src="site.js">
<script>
window.appPaths = ['someApp.js'];
</script>
site.js:
require([
// deps for sitewide stuff
], function () {
// doing global general stuff
someTask(function () {
if(window.appPaths) require(window.appPaths)
})
})
someApp.js:
require([
// app specific deps
], function () {
// application code that doesn't run because not `require`d until the site.js tasks are done.
})
My "ideal" setup isn't necessarily the exact same, but I would want someApp.js to not load and/or run until site.js loaded. In my requirejs setup, site.js was also essentially the commons chunk but I don't think that's necessary here... just having trouble finding a parallel style of organization in webpack...

RequireJS text plugin - minification of templates

I'm using text plugin to import my templates. Now, in production I don't want that there are many XHR requests for templates so I would like to get them in one go.
My idea was to have build task which would take template and create something like:
define("my-template.tpl", function() {
return '<div>my content</div>'
}
and I was able to do this and define statement has been run, but requirejs still does XHR request when I have
define("my function", ["my-template.tpl"], function() {
<body of function here>
});
Did someone do any minification of text! plugin templates? Am I doing something wrong here?
RequireJS always requests all your modules asynchronously.
If you want one single call, you can build your app using the optimizer.
You do not need this template wrapper (as you noticed by yourself, it won't change anything). The files required using the text plugin will be included in the built file too.

Using multiple pre-compiled templates with Handlebars .js (multiple HTTP requests)?

I think this question will give mine a little more context:
Using pre-compiled templates with Handlebars.js (jQuery Mobile environment)
Basically I'm trying to learn the precompiling stuff, so I can save load time and keep my html documents neat. I haven't started it yet, but based on the above link, every template needs to have it's own file. Isn't that going to be a lot of links to load? I don't want to be making multiple HTTP requests if I don't have to.
So if someone could shed some light, perhaps offer an alternative where I can get the templates out of my html, but not have to load up 100 different template files.
Tools like Grunt.js allow you to have your templates and consume them too. For example, this file compiles the templates and then concatenates them into a single file:
module.exports = function(grunt) {
grunt.loadNpmTasks("grunt-contrib-handlebars");
// Project configuration.
grunt.initConfig({
// Project metadata, used by the <banner> directive.
meta: {},
handlebars: {
dist: {
options: {
namespace: "JST",
wrapped: "true"
},
files: {
"templates.js": [
"./fileA.tmpl",
"./fileB.tmpl"
]
}
}
}
});
// Default task.
grunt.registerTask("default", "handlebars");
};
What I've yet to work out since I'm just getting started with pre-compiled templates is the workflow. I want to be able to have compiled templates when we're running a deployed version of the app but when doing development and debugging I'd much rather have my original individual files in uncompiled form so I can just edit them and reload the page.
Follow Up:
I wanted to come back to this after having worked out some of how to both have my pre-compiled templates when available and use individual templates which can be edited on the fly when people are doing development and debugging work and would like to have quick edit-reload-test cycles without doing Grunt builds.
The answer I came up with was to check for the existence of the JST[] data structure and then further to test and see whether a particular pre-compiled template is present in that structure. If it is then nothing further need be done. If it's not there then the template is loaded (we use RequireJS to do that) and compiled and put into the same JST[] array under the same name it would have if pre-compiled templates had been loaded.
That way when it comes time to actually use the template, the code only looks for it in one place and it's always the same.
In the near future I think we'll likely have RequireJS plugins to perform the test and load/compile code while keeping it simple for developers.

Approaches to modular client-side Javascript without namespace pollution

I'm writing client-side code and would like to write multiple, modular JS files that can interact while preventing global namespace pollution.
index.html
<script src="util.js"></script>
<script src="index.js"></script>
util.js
(function() {
var helper() {
// Performs some useful utility operation
}
});
index.js
(function () {
console.log("Loaded index.js script");
helper();
console.log("Done with execution.");
})
This code nicely keeps utility functions in a separate file and does not pollute the global namespace. However, the helper utility function will not be executed because 'helper' exists inside a separate anonymous function namespace.
One alternative approach involves placing all JS code inside one file or using a single variable in the global namespace like so:
var util_ns = {
helper: function() {
// Performs some useful utility operation.
},
etc.
}
Both these approaches have cons in terms of modularity and clean namespacing.
I'm used to working (server-side) in Node.js land where I can 'require' one Javascript file inside another, effectively injecting the util.js bindings into the index.js namespace.
I'd like to do something similar here (but client-side) that would allow code to be written in separate modular files while not creating any variables in the global namespace while allowing access to other modules (i.e. like a utility module).
Is this doable in a simple way (without libraries, etc)?
If not, in the realm of making client-side JS behave more like Node and npm, I'm aware of the existence of requireJS, browserify, AMD, and commonJS standardization attempts. However, I'm not sure of the pros and cons and actual usage of each.
I would strongly recommend you to go ahead with RequireJS.
The modules support approach (without requires/dependencies):
// moduleA.js
var MyApplication = (function(app) {
app.util = app.util || {};
app.util.hypotenuse = function(a, b) {
return Math.sqrt(a * a + b * b);
};
return app;
})(MyApplication || {});
// ----------
// moduleB.js
var MyApplication = (function(app) {
app.util = app.util || {};
app.util.area = function(a, b) {
return a * b / 2;
};
return app;
})(MyApplication || {});
// ----------
// index.js - here you have to include both moduleA and moduleB manually
// or write some loader
var a = 3,
b = 4;
console.log('Hypotenuse: ', MyApplication.util.hypotenuse(a, b));
console.log('Area: ', MyApplication.util.area(a, b));
Here you're creating only one global variable (namespace) MyApplication, all other stuff is "nested" into it.
Fiddle - http://jsfiddle.net/f0t0n/hmbb7/
**One more approach that I used earlier in my projects - https://gist.github.com/4133310
But anyway I threw out all that stuff when started to use RequireJS.*
You should check out browserify, which will process a modular JavaScript project into a single file. You can use require in it as you do in node.
It even gives a bunch of the node.js libs like url, http and crypto.
ADDITION: In my opinion, the pro of browserify is that it is simply to use and requires no own code - you can even use your already written node.js code with it. There's no boilerplate code or code change necessary at all, and it's as CommonJS-compliant as node.js is. It outputs a single .js that allows you to use require in your website code, too.
There are two cons to this, IMHO: First is that two files that were compiled by browserify can override their require functions if they are included in the same website code, so you have to be careful there. Another is of course you have to run browserify every time to make change to the code. And of course, the module system code is always part of your compiled file.
I strongly suggest you try a build tool.
Build tools will allow you to have different files (even in different folders) when developing, and concatenating them at the end for debugging, testing or production. Even better, you won't need to add a library to your project, the build tool resides in different files and are not included in your release version.
I use GruntJS, and basically it works like this. Suppose you have your util.js and index.js (which needs the helper object to be defined), both inside a js directory. You can develop both separately, and then concatenate both to an app.js file in the dist directory that will be loaded by your html. In Grunt you can specify something like:
concat: {
app: {
src: ['js/util.js', 'js/index.js'],
dest: 'dist/app.js'
}
}
Which will automatically create the concatenation of the files. Additionally, you can minify them, lint them, and make any process you want to them too. You can also have them in completely different directories and still end up with one file packaged with your code in the right order. You can even trigger the process every time you save a file to save time.
At the end, from HTML, you would only have to reference one file:
<script src="dist/app.js"></script>
Adding a file that resides in a different directory is very easy:
concat: {
app: {
src: ['js/util.js', 'js/index.js', 'js/helpers/date/whatever.js'],
dest: 'dist/app.js'
}
}
And your html will still only reference one file.
Some other available tools that do the same are Brunch and Yeoman.
-------- EDIT -----------
Require JS (and some alternatives, such as Head JS) is a very popular AMD (Asynchronous Module Definition) which allows to simply specify dependencies. A build tool (e.g., Grunt) on the other hand, allows managing files and adding more functionalities without relying on an external library. On some occasions you can even use both.
I think having the file dependencies / directory issues / build process separated from your code is the way to go. With build tools you have a clear view of your code and a completely separate place where you specify what to do with the files. It also provides a very scalable architecture, because it can work through structure changes or future needs (such as including LESS or CoffeeScript files).
One last point, having a single file in production also means less HTTP overhead. Remember that minimizing the number of calls to the server is important. Having multiple files is very inefficient.
Finally, this is a great article on AMD tools s build tools, worth a read.
So called "global namespace pollution" is greatly over rated as an issue. I don't know about node.js, but in a typical DOM, there are hundreds of global variables by default. Name duplication is rarely an issue where names are chosen judiciously. Adding a few using script will not make the slightest difference. Using a pattern like:
var mySpecialIdentifier = mySpecialIdentifier || {};
means adding a single variable that can be the root of all your code. You can then add modules to your heart's content, e.g.
mySpecialIdentifier.dom = {
/* add dom methods */
}
(function(global, undefined) {
if (!global.mySpecialIdentifier) global.mySpecialIdentifier = {};
/* add methods that require feature testing */
}(this));
And so on.
You can also use an "extend" function that does the testing and adding of base objects so you don't replicate that code and can add methods to base library objects easily from different files. Your library documentation should tell you if you are replicating names or functionality before it becomes an issue (and testing should tell you too).
Your entire library can use a single global variable and can be easily extended or trimmed as you see fit. Finally, you aren't dependent on any third party code to solve a fairly trivial issue.
You can do it like this:
-- main.js --
var my_ns = {};
-- util.js --
my_ns.util = {
map: function () {}
// .. etc
}
-- index.js --
my_ns.index = {
// ..
}
This way you occupy only one variable.
One way of solving this is to have your components talk to each other using a "message bus". A Message (or event) consists of a category and a payload. Components can subscribe to messages of a certain category and can publish messages. This is quite easy to implement, but there are also some out of the box-solutions out there. While this is a neat solution, it also has a great impact on the architecture of your application.
Here is an example implementation: http://pastebin.com/2KE25Par
http://brunch.io/ should be one of the simplest ways if you want to write node-like modular code in your browser without async AMD hell. With it, you’re also able to require() your templates etc, not just JS files.
There are a lot of skeletons (base applications) which you can use with it and it’s quite mature.
Check the example application https://github.com/paulmillr/ostio to see some structure. As you may notice, it’s written in coffeescript, but if you want to write in js, you can — brunch doesn’t care about langs.
I think what you want is https://github.com/component/component.
It's synchronous CommonJS just like Node.js,
it has much less overhead,
and it's written by visionmedia who wrote connect and express.

How to load a specific code regarding the current page?

I'm building a complex web app and to keep things simple, I made various modules (objects) in various files. Those modules can be required on some page, and not on others.
For that reason, I'd like to avoid loading all the modules for any pages, increasing the amount of useless requests.
So far, I work like this :
I include all needed libraries
After that, I instantiate these librairies in jQuery(function() {}); with specifics #ids or .classes arguments for that current page
Everything works fine, but since my app is growing beyond easy, I'd like to manage my JS with RequireJS.
And that's where things start to be a little confusing for me.
I know I can load my module when required, using require(['module1', 'module2', 'etc'], function (module1, module2, etc) {}), but how can I say :
"on this page, you load these modules, and instantiate them with those #ids and .classes"
and
"on this other page, you load only that module, with this #other-id"
?
module1 will, for example, load data from the api, and list them to a specific table given as parameter :
// in page 1
var mod1 = new Module1($('#content>table');
mod1.init(); // will load the data from the api with the url located at <table data-api-url="http://....">
// in page 2
var mod1 = new Module1($('#content .items>table'); // The table where we want the data to be populated is not at the same position!
mod1.init();
That means, depending on the page, I'll have to load my modules differently. That's how I don't know how to do using RequireJs :/
What you need is a javascript file for each page. That file will be responsible to execute your page-specific code.
I'll assume that you will use r.js to optmize and pack your code.
We can interpret Module1, Module2 etc. as libraries, because they will be used on multiple pages. To avoid browser do one request for each library module you can include this modules on your optimized main file:
Configure the "modules:" attribute of your build profile like this:
...
modules: [
{
name: "main" // this is your main file
includes: [
"module1",
"module2",
"etc..."
]
}
]
...
By doing this you tell to requirejs something like this: Optimize my "main.js" file and include in it all its dependencies, also includes the "module1", "module2" etc.
You have to do this because on your main file you do not include these modules on the require()/define() call, but you still want they available in case the page-specific module needs them. You don't have to do this for every library module you have, just for those that will be used by most of your pages.
Then, you create a javascript file for your page to use those modules:
define(function(require, exports, module) {
var $ = require("jquery"),
module1 = require("module1");
var mod1 = new Module1($('#content>table'));
mod1.init();
//other page specific-code.
});
And then on the html file:
<script data-main="main" data-start="home" src="require.js"></script>
So, when page loads, it will make a request for require.js, then another for main.js and then another for home.js and that's all.
I'll put the link for the another question so this answer get some context: How to use RequireJS build profile + r.js in a multi-page project
The creator of RequireJS actually made an example project that uses page-specific main files: https://github.com/requirejs/example-multipage

Categories

Resources