One Backbone.js app using require.js depends on another: how do I include the child? - backbone.js

I wrote a backbone.js app that uses require.js and is broken up with models/, collections/ and so forth. I then wrote another app that depends on the first app (and some other things. The files are laid out like so:
/scripts/appA/
models/
collections/
views/
/scripts/appNeedsA/
models/
collections/
views/
What do I put in the needsA to require appA? The below seems logical to me but doesn't work. If I use ../../appA, that finds appA but IT's dependencies can't be found because the root is wrong.
define(
['underscore', 'backbone', '../appA'],
function (_, Backbone, appA) {
...
}

It might not be the answer you were hoping for but, here's one approach:
https://github.com/busticated/RequireLoadingExample
The idea is that you define your module deps using the path the consuming application will use, then in the consumed app you alias the path appropriately.
In my example, I have a top-level main.js file which pulls in both app1.js and app2.js modules. Both of these modules depend on modules within their own sub-directories - e.g. app1.js uses one/mods/a.js and one/mods/b.js. I have another main (main-one.js) file that lives a level down inside the one/ directory. This file calls:
require.config({
paths: {
'jquery': 'libs/jquery',
'one': '.'
}
});
So now when app1.js loads, the one/mods/a.js path is translated to ./mods/a.js and is found / loaded without issue.
You should be able to fork my repo above and load index.html & one.html in a browser with js console open to see it all work.
Hope it helps!

The proper solution is to:
define(
['underscore', 'backbone', 'appA/views/whatever'],
function (_, Backbone, appAWhateverView) {
...
}
and to set your require.config paths to include:
require.config({
paths: {
appA: '../appA'
}
});

Related

Require.js can't recognize modules in concatenated JS file

I am integrating Require.js to AngularJS based web application for performance improvement.
I've imported require.conf in index.html:
<script src="bower_components/requirejs/require.js" data-main="require-conf.js">
Here is code snippet of require-conf.js:
require.config({
paths: {
'jquery': '...',
'Angular': '...',
....
'libs' : 'src/libs.js'
},
shim: {
'Angular': { exports: 'Angular'},
'libs' : ['Angular']
....
}
}
require(
[
'jquery',
'angular',
'app',
'libs',
], function (jquery, angular) {
angular.bootstrap(['app'])
}
);
Here, libs.js is the library I've built by webpack. Some plugins and libraries are concatenated in this file.
Here is webpack configuration code snippet to build libs.js.
In webpack.config.js
plugins: [
new ConcatPlugin({
fileName: 'libs.js',
filesToConcat: [
'./src/utils/bootstrap-plugins.min.js',
'./src/libs/angular-bootstrap-datetimepicker/datetimepicker.js',
'./src/libs/angular-bootstrap-datetimepicker/datetimepicker.templates.js',
'./src/libs/angular-fusioncharts/fusioncharts.js',
'./src/libs/angular-fusioncharts/angular-fusioncharts.min.js',
'./src/libs/angular-fusioncharts/types/fusioncharts.charts.js',
'./src/libs/angular-ui-tour/angular-ui-tour.js',
'./src/libs/JQ_CONFIG/flot/jquery.flot.js',
'./src/libs/JQ_CONFIG/flot/jquery.flot.pie.js',
'./src/libs/JQ_CONFIG/flot/jquery.flot.resize.js',
'./src/libs/JQ_CONFIG/flot-spline/js/jquery.flot.spline.min.js',
'./src/libs/JQ_CONFIG/flot.orderbars/js/jquery.flot.orderBars.js',
'./src/libs/JQ_CONFIG/flot.tooltip/js/jquery.flot.tooltip.min.js',
'./src/libs/JQ_CONFIG/footable/dist/footable.all.min.js',
'./src/libs/JQ_CONFIG/html5sortable/jquery.sortable.js',
'./src/libs/jquery-ui-draggable/jquery-ui-draggable.min.js',
'./src/libs/ng-table/ng-table.js',
'./src/libs/StickyTableHeaders/jquery.stickytableheaders.js',
'./src/libs/ng-quill/quill.js',
'./src/libs/ng-quill/ng-quill.js',
].map(function(fileName) {
return path.resolve(__dirname, fileName);
}),
But, App can't recognize the modules inside libs.js:
Module 'ngquill' is not available! you either misspelled the module
name or forgot it to load it. If registering a module ensure that you
specify the dependencies as the second argument.
Require.js can't recognize the modules concatenated by webpack? Is there any solutions to fix this problem?
You cannot combine AMD modules into a single file just by concatenating them into a single file. When you combine multiple modules into a single file, the modules must get hardcoded names. When you have a single module in a single file, the define for it can be:
define([ ... deps ... ], function (...) {
In this case, RequireJS infers the name of the module from the name under which it was requested.
When you combine multiple modules in a single file, the define calls must be of the form:
define("foo", [ ... deps ...], function (...) {
define("bar", [ ... deps ...], function (...) {
// etc.
The first argument to define is a string, which tells RequireJS which module is being defined. This is necessary because otherwise RequireJS won't know which module is which. This is why you cannot just concatenate.
You most likely could write a Webpack configuration that could both transform the files as I described above and concatenate them. However, that's rife with hurdles. For instance the runtime shim configuration require special handling at build time. In the end you may end up replicating the functionality of RequireJS' optimizer. I would suggest using RequireJS' optimizer instead of reinventing the wheel.

What does "packages" property of requireJs config mean ? And how it works?

I am trying to understand how requireJs works. There is a property "packages" which I came across while configuring requireJs. What my understanding is that 'packages' is used to mention a complete folder/module which contains "main.js" & main.js requires all other dependencies inside that module. But does mentioning "packages" in config file will automatically load main.js or do we need to do something to make it load main.js ?
Below is my folder structure & main.js snippet. 'main.js' is the data-main or entry point of application.
So after trying few stuff, what I understood is that packages lets you mention a directory or folder which has other modules (commonJs directory is what docs refer it to). So the way we define a package is :
packages: [
{name : 'controllers' , location :'../controllers' },
{name : 'directives' , location : '../directives'},
{name : 'services' , location : '../services'}
] ,
Where name is an alias for this entire directory or folder. location is the path of the folder relative to your main.js or requireJs's config file.
Now answering the 2) point - it does not load automatically. For it to load we need to require it somewhere. Once we require it, requireJs will first load the main.js inside that directory by default. And we need to define all the other modules inside that directory, in this main.js. For eg- I will require it in my app.js before bootstrapping my application-
require([
// Add additional dependencies
'angular',
'angular-ui-router',
'jquery',
'app',
'route',
"controllers",
"directives",
"services"] , function(){ console.log("All dependencies loaded"); });

how to require webpack bundles in js files

I want to require two bundle files from webpack in an app.js that also gets bundled. My folder looks like this:
MyApp
|-app
| -app.js <-this gets bundled
|-hero
| -hero.module <- this gets also bundled
| -some other stuff that will be bundled in hero.bundle.js
|-crisis
| -crisis.module <- gets bundled
| -more stuff that gets bundled in crisis.bundle.js
-
So far so good.
I want to require hero.bundle.js and crisis.bundle.js in the app.js, because I am lazy loading / routing with my COmponent Router in app.js.
But I get constantly the Error, that the modules couldn't be found.
Example Syntax of one of the requires:
path: '/heroes/...',
name: 'Heroes',
loader: function () {
// lazy load Heroes
return $ocLazyLoad.load([require('./dist/heroes.bundle.js')])
.then(function () {
return 'heroes';
});
}
Do I do something wrong?
Thanks in advance :)
I got the solution:
Webpack didn't find my files. The path searched
C:/someFolders/heroApp/app/dist/heroes.bundle.js
altough it was
C:/someFolders/heroApp/dist/heroes.bundles.js
setting two dots was the solution:
require('../dist/heroes.bundle.js')

How do I control the order files are loaded in karma config

I'm testing an Angular app with Karma. I've got everything working, but it seems like I'm doing something wrong.
https://gist.github.com/guyjacks/7bca850844deb612e681
Karma will throw the following error if I comment out 'app/notes/notes.main.js' :
Uncaught Error: [$injector:nomod] Module 'notes.main' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
http://errors.angularjs.org/1.4.3/$injector/nomod?p0=notes.main
at /Users/guyjacks/projects/adr-demo/node_modules/angular/angular.js:1958
I don't want to have to manually list each application file to control the order in which each file loads. Am I don't something wrong or do I just have to list each file in the order I want?
---- Solution based on the accepted answer ----
My app is organized into modules as recommended by the Angular Style Guide: https://github.com/johnpapa/angular-styleguide.
'app/app.module.js',
'app/**/*.module.js',
'app/**/*.service.js',
'app/**/*.controller.js',
'app/**/*.directive.js',
'app/**/*.js'
I don't think the following lines are necessary above
'app/**/*.service.js',
'app/**/*.controller.js',
'app/**/*.directive.js'
when each module has an angular module declared in the *.module.js file like my app does.
That said, if you did need to explicitly load services before controllers & controllers before directives then this would be the way to do it.
Update : I could not see your karma file, now Gist link is fixed.
The point in notes[.]main.js is causing the problem,
So, 'app/**/*.js' is not matching notes.main.js.
Try now like this : app/**/*. *.js
=============================================================
Before update :
You have to load the modules that you app depends on, in karma config. file :
module.exports = function(config) {
config.set({
.......
// list of files / patterns to load in the browser
files: [
'./client/app/vendors/angular/angular.js',
// =====> load Your modules here ...
'./client/app/app.js',
'./client/app/controllers/*.js',
'./client/app/directives/*.js',
'./client/app/services/*.js',
'./test/client/unit/**/*.js'
],
.....
}) }

Require.js build not concatenation scripts loaded with Jam

Following one of the chapters of "Developing Backbone.js Apllication" by Addy Osmani (O'Reilly) about Grunt-BBB (Backbone Boilerplate Buddy), I just couldn't manage to create a build profile.
Here is the filesystem tree used for this :
/builds
/closure
/rhino
/config
/build.js
build.sh
/development
/* Grunt-BBB files after init */
/app
/styles
index.css
app.js
config.js
main.js
router.js
/test
/* Not important files used for testing */
/vendor
/h5bp
/css
main.css
normalize.css
/jam
/backbone
backbone.js
package.json
/bakbone.layoutmanager
bakbone.layoutmanager.js
package.json
/jquery
jquery.js
package.json
/lodash
lodash.js
lodash.min.js
lodash.underscore.min.js
package.json
require.config.js
require.js
/js
/libs
almond.js
require.js
/distribution
/* Empty dist directory where the optimized / minified / concatenated files should go */
Here are the steps I followed in the /development directory :
1) Install Grunt-BBB (npm install -g bbb)
2) Download r.js, a part of the Require.js project (git clone https://github.com/backbone-boilerplate/grunt-bbb)
3) Initialize the files of the boilerplate (bbb init)
Here is the build.js file I used to configure the r.js AMD loader for the Google Closure compiler :
({
appDir: '../../development',
baseUrl: 'app',
dir: '../../distribution',
optimize: 'closure', // 'uglify2'
paths: {
backbone: '../vendor/jam/backbone/backbone',
'backbone.layoutmanager': '../vendor/jam/backbone.layoutmanager/backbone.layoutmanager',
jquery: '../vendor/jam/jquery/jquery',
lodash: '../vendor/jam/lodash/backbone.min'
},
modules: [
{
name: 'main'
}
],
onBuildRead: function(moduleNames, path, contents) {
return contents;
//return contents.replace(/console\.log\(([^\)]+)\);/g, '')
// .replace(/debugger;/, '');
}
})
and this is the build.sh file I use :
#!/usr/bin/env bash
# r.js directory
RJSDIR="r.js"
RJS="$RJSDIR/dist/r.js"
# Rhino directory
RHINODIR="rhino"
RHINO="$RHINODIR/js.jar"
# Google Closure Compiler directory
CLOSUREDIR="closure"
CLOSURE="$CLOSUREDIR/compiler.jar"
# Build config directory
CONFIGDIR="config"
CONFIG="$CONFIGDIR/build.js"
# Launch compillation
java -Xms256m -Xmx256m -classpath "$RHINO":"$CLOSURE" org.mozilla.javascript.tools.shell.Main "$RJS" -o "$CONFIG" $#
My goal is to optimize, minify, concatenate all the JavaScrit file including the libraries and templates (which I don't have yet, I am only using the boilerplate files) but also CSS files.
The result I get by running ./build.sh is that every files are correctly minimised (besides CSS rule inlining, but that is besides the point) and concatenated but resources that are loaded and managed by the Jam (package manager that combines NPM and Require.js) aren't concatenated.
The reason for that since they are already loaded / managed by Jam, they are not redeclared in the JavaScript files AMD style.
In conclusion, my questions are the following :
How can I rewrite my build.js configuration file so that resources that are loaded by Jam also get included and concatenated in the release / dist file ?
How can I make it so that the concatenated resources aren't copied in the realse / dist directory ? Is it possible to configure this in the build.js file or should this go in my build.sh file ?
Edit : New build.js file :
({
appDir: '../../development',
baseUrl: 'app',
dir: '../../distribution',
optimize: 'closure', // 'uglify2'
paths: {
requirejs : '../vendor/jam/require',
backbone: '../vendor/jam/backbone/backbone',
'backbone.layoutmanager': '../vendor/jam/backbone.layoutmanager/backbone.layoutmanager',
jquery: '../vendor/jam/jquery/jquery',
lodash: '../vendor/jam/lodash/backbone.min'
},
name: 'main',
include: ['requirejs'],
onBuildRead: function(moduleNames, path, contents) {
return contents;
//return contents.replace(/console\.log\(([^\)]+)\);/g, '')
// .replace(/debugger;/, '');
}
})
And here is the error :
file:///vendor/js/libs/require.jsFailed to load resource: The requested URL was not found on this server.
file:///app/styles/index.cssFailed to load resource: The requested URL was not found on this server.
require.js is never included by r.js unless you instruct it to do so. See this link:
http://requirejs.org/docs/optimization.html#onejs
The link refers to command-line options, but the build file options are broadly the same:
you need to define a dummy module for require.js in your paths:
paths: {
requireLib : '/path/to/require.js'
backbone: '../vendor/jam/backbone/backbone',
'backbone.layoutmanager': '../vendor/jam/backbone.layoutmanager/backbone.layoutmanager',
jquery: '../vendor/jam/jquery/jquery',
lodash: '../vendor/jam/lodash/backbone.min'
},
and include it:
name "main",
include: ["requireLib"],
You can ensure that allnested dependencies are resolved by setting:
findNestedDependencies: true,
You can configure an output path using 'out' in your build file
out: "path/to/my/builtfile-1.0.0.js",
Sorry I don't know enough about jam to say whether jam would override this setting
_Pez

Resources