Using require.js with a unique CDN - javascript

I am working on a require.js application to localize it. We have our nls files in a specific folder structure.
nls/
fr/
register.js
...
register.js
When we push the app to production our build system adds a build number to all files like so main.54b8801bf2c6e13b.js​​. This does work Locally on my machine because we do not add the unique number.
Require.js does not bring in any js files in the subfolders for example nls/fr/register.js will not get loaded in the main.js bundle (expected). When our app comes across this in staging, it goes to pull nls/fr/register.js from the CND but looks for nls/fr/register.js instead of nls/fr/register.54b8801bf2c6e13b.js​​ (yes the file exists in our CDN)
Does anyone know of a way to dynamically have require.js look for nls/fr/register.54b8801bf2c6e13b.js​​. I think we haven't run into this before because all JS files are loaded up into the main.js file (which I am not opposed to doing here as well if it is easier)
nls/register.js
define(['text!json/root/register.json', 'settings'], function(json, settings) {
return {
"fr": true
}
});
nls/fr/register.js
define(['text!json/fr/register.json'], function(json) {
return JSON.parse(json);
});
views/register.js
define([
'jquery',
'plugins/ui.1.11.0',
'underscore',
'backbone',
'views/base_view',
'settings',
'utils/gtm',
'utils/storage',
'text!templates/login_registration/registration_modal.html',
'i18n!nls/register'
], function($, jquery_ui_is_jquery_plugin, _,
Backbone,
BaseView,
Settings,
gtm,
Storage,
Template_Registration,
RegisterLocales) {
//code to get locales and set up view
}

I solved this by adding the NLS files to my require.js compiled file (main.js)via my grunt task (grunt-contrib-requirejs)
modules: [
{
name: 'main',
include: [
'nls/de/activity_types',
'nls/de/admin',
'nls/de/app_callout',
'nls/de/browser_support'
]
}]

Related

RequireJS - ASP.NET MVC Bundle Script

I have two questions.
I am trying to learn RequireJS and use it along with ASP.NET MVC bundling & minification. I am using a separate config file for RequireJS which holds the bundling information. My first problem is how do I pass on the bundle path generated by MVC to the require.config.js file. A clean way to do that will be as below:
index.cshtml
<script id="requirescript" type="text/javascript" src="~/Scripts/require.config.js"
data-baseurl="#Url.Content("~/Scripts")"
data-bundlepath="#System.Web.Optimization.Scripts.Url("~/bundles/scripts").ToString()"></script>
require.config.js
var reqScript = document.getElementById('requirescript');
var baseUrl = reqScript.getAttribute('data-baseurl');
var bundlePath = reqScript.getAttribute('data-bundlepath');
var require = {
baseUrl: baseUrl,
bundles: {
bundlePath : ['jquery','jqueryui','mymodule']
}
}
};
When I do the above, RequireJS tries to load a non-existing script named bundlePath.js, instead what I want is to load the bundled script which is '/bundles/scripts?v=GZ0QWPB4G0soItEmlsPC6Yp3zftCRVleVTcH3LseMWo1' which contains my modules. So first, my question is how do I pass the bundle URL, as generated by the server, to RequireJS in the require.config.js file without hard-coding the bundle path?
Secondly, the jqueryui module seems to be not loading. I have added the module name in the AMD code in jquery ui min file. How do I make jquery ui work with RequireJS and ASP.NET bundling?
There is a NuGet package RequireJs.NET https://www.nuget.org/packages/RequireJsNet/ which is an implementation of RequireJs for .NET MVC.
RequireJS is an implementation of Asynchronous Module Definition (AMD) that provides all the tools you need to write modular JavaScript. If you are working on a large project with a lot of JavaScript code, many external components and frameworks, RequireJS will help you manage the complexity of dependencies.
You will have access to a configuration file (json) which will look like this:
{
"paths": {
"jquery": "jquery-1.10.2",
"jquery-validate": "jquery.validate",
"jquery-validate-unobtrusive": "jquery.validate.unobtrusive",
"bootstrap": "bootstrap",
"respond": "respond",
"i18n": "Components/RequireJS/i18n",
"text": "Components/RequireJS/text",
"menu-module" : "Controllers/Common/menu-module"
},
"shim": {
"jquery-validate": {
"deps": [ "jquery" ]
},
"jquery-validate-unobtrusive": {
"deps": [ "jquery", "jquery-validate" ]
},
"bootstrap": {
"deps": ["jquery"]
}
},
"autoBundles": {
"main-app": {
"outputPath": "Scripts/Bundles/",
"include": [
{
"directory": "Controllers/Root"
}
]
},
"require-plugins": {
"outputPath": "Scripts/Bundles/",
"include": [
{
"file": "Components/RequireJS/i18n"
},
{
"file": "Components/RequireJS/text"
}
]
}
}
}
And after that you will render RequireJs config into your layout.
#using RequireJsNet
<!DOCTYPE html>
<html>
<head>
<!-- head content -->
</head>
<body>
<!-- body content -->
#Html.RenderRequireJsSetup(new RequireRendererConfiguration
{
// the url from where require.js will be loaded
RequireJsUrl = Url.Content("~/Scripts/Components/RequireJS/require.js"),
// baseUrl to be passed to require.js, will be used when composing urls for scripts
BaseUrl = Url.Content("~/Scripts/"),
// a list of all the configuration files you want to load
ConfigurationFiles = new[] { "~/RequireJS.json" },
// root folder for your js controllers, will be used for composing paths to entrypoint
EntryPointRoot = "~/Scripts/",
// whether we should load overrides or not, used for autoBundles, disabled on debug mode
LoadOverrides = !HttpContext.Current.IsDebuggingEnabled,
// compute the value you want locale to have, used for i18n
LocaleSelector = html => System.Threading.Thread.CurrentThread.CurrentUICulture.Name.Split('-')[0],
// instance of IRequireJsLogger
Logger = null,
// extensability point for the config object
ProcessConfig = config => { },
// extensability point for the options object
ProcessOptions = options => { },
// value for urlArgs to be passed to require.js, used for versioning
UrlArgs = RenderHelper.RenderAppVersion()
})
</body>
</html>
For further reading you can access the documentation page: http://requirejsnet.veritech.io/ .
Or the github project (for issues and questions) : https://github.com/vtfuture/RequireJSDotNet
In this package exists a compressor too for bundling and minification (based on YUI compressor).
Instead of bundlePath use the bundle path "/Scripts/bundles/scripts" . it'll work.
An old question but you can use #Scripts.RenderFormat() to get MVC to output the filename of the bundle on it's own. e.g.
Bundle
bundles.Add(new ScriptBundle("~/bundles/bundleName").Include(
"~/Scripts/filename1.js",
"~/Scripts/filename2.js",
"~/Scripts/filename3.js"
));
View
<script type="javascript">
var arrayOfFiles = [#Scripts.RenderFormat("\"{0}\",","~/bundles/bundlename")];
</script>
This sets arrayOfFiles to
["/Scripts/filename1.js","/Scripts/filename2.js","/Scripts/filename3.js"]
or if the bundling is enabled you just get
["/bundles/bundleName?v=13232424"]
You can then pass this array to other javascript libraries.

How to add JavaScript module to generator-meanjs app?

I want to add some JavaScript module to my application made by meanjs-generator for Yeoman, but the modules’ script tags aren't generated to index.html. I just added the modules through bower and I didn’t touch any other files because generated files by the generator seem to look for .js files and add them to index.html automatically.
What is the correct way to add JavaScript module?
After executed bower command, you have to add your .js or .css file paths to config/env/all.js like as follows:
module.exports = {
...
assets: {
lib: {
css: [
'public/lib/bootstrap/dist/css/bootstrap.css',
'public/lib/bootstrap/dist/css/bootstrap-theme.css',
],
js: [
'public/lib/ng-file-upload/angular-file-upload-shim.js',
'public/lib/angular/angular.js',
'public/lib/angular-resource/angular-resource.js',
'public/lib/angular-cookies/angular-cookies.js',
'public/lib/angular-animate/angular-animate.js',
'public/lib/angular-touch/angular-touch.js',
'public/lib/angular-sanitize/angular-sanitize.js',
'public/lib/angular-ui-router/release/angular-ui-router.js',
'public/lib/angular-ui-utils/ui-utils.js',
'public/lib/angular-bootstrap/ui-bootstrap-tpls.js',
'public/lib/ng-file-upload/angular-file-upload.js'
]
},
...
}

How to get the r.js build script working

I've read through the documentation and the example app.build.js file but just can't get my js files to concatenate and minify into one single file. I think I'm just not understanding exactly what settings I need in the build script and was hoping for some help.
My app is set up like this:
src >
js >
build.js
r.js
config.js
app >
main.js
lib >
module1.js
module2.js
module3.js
vendor >
require.js
jquery.js
jquery.validation.js
build >
// Where concat and minified file would go
config.js looks like this:
requirejs.config({
"baseUrl" : "src/js/lib", // Used because when setting dependencies in modules, this is used
"paths" : {
"app" : "../app",
"jquery" : [
"https://code.jquery.com/jquery-1.11.1.min",
"../vendor/jquery"
],
"validate" : "../vendor/jquery.validate.min"
},
"shim" : {
// Allow plugins with dependencies to load asynchronously
validate : ["jquery"]
}
});
// Load the main app module to start the app
requirejs(["app/main"]);
main.js looks like this:
require(["module1", "module2", "module3"], function(Module1, Module2, Module3) {
return [
Module1.init(),
Module2.init(),
Module3.init(),
Module4.init()
];
});
And then the build.js is where I'm lost. I thought I should load a mainConfigFile because I'm using the shim, but I'm not sure. If I do load that config file, it uses the baseUrl from that config file. I'm not sure what name: is supposed to refer to exactly and whether I'm missing some necessary configuration options.
({
//baseUrl: ".",
paths: {
jquery: "empty:",
//main: "../app/main",
//app: "app"
},
name: "app/main",
out: "../build/main.js",
//mainConfigFile: "config"
})
If I run that build file as it is (with those lines commented out) I get:
Error: ENOENT, no such file or directory
'/Users/davidpaul/Sites/require/src/js/module1.js' In module tree:
app/main
I'm not really sure what's being referred to when it says 'module tree'. I keep making changes to paths in the build file but not making progress so hoping for someone to explain this a bit to me.
The builder parses all paths relative to the build file location (unless changed via the baseUrl property). If you look relative to src/js/build.js, your main.js is in ./app/ and module1/2/3.js are in ./lib/. All paths inside modules have to be specified relatively to the common root, so to make your example work it's enough to change the signature of main.js to:
require(["lib/module1", "lib/module2", "lib/module3"], function(M1, M2, M3) {
// (...)
})
Note that config.js doesn't take part in the build process, you may need to change it as well to make your application work both "raw" and optimized.

Require JS files from bower_components by saying "require('library')" possible?

I'm new to RequireJS and it seems it might not actually be possible but I'll still go ahead and ask away in case I'm missing something.
In the docs it says..
This setup assumes you keep all your JavaScript files in a "scripts" directory in your project.
project-directory/
project.html
scripts/
main.js
helper/
util.js
But what if I have to require files from my bower installed files in bower_components:
project-directory/
bower_components/
jquery-mousewheel
jquery.mousewheel.js
lodash
dist
lodash.js
As you see, not all libraries have the same directory hierarchy and naming convention.
So I was wondering is there a simple way to require these bower libraries without actually knowing where their main files are, maybe by simply saying
require('jquery-mousewheel');
require('loadash');
?
setup your requirejs config to use paths
requirejs.config({
// ... config ...
paths: {
jquery-mousewheel: 'bower_components/jquery-mousewheel/jquery.mousewheel',
loadash: 'bower_components/lodash/dist/lodash'
}
// ... config ...
});
documentation for reference
I think this is a better solution...
requirejs.config({
baseUrl: 'bower_components/',
paths: { // path to your app
app: '../'
}
});
requirejs( [
'imagesloaded/imagesloaded',
'app/my-component.js'
], function( imagesLoaded, myComp ) {
imagesLoaded( '#container', function() { ... });
});

Loading Angular from CDN via RequireJS is not injected

In my project I want to use RequireJS and bootstrap my app as follows:
requirejs.config({
baseUrl: 'scripts/vendor',
paths: {
jquery: [
'https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min',
'jquery'
],
angular: [
'http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min',
'angular'
],
app: '../app'
}
});
require(['require', 'jquery', 'angular', 'app'], function(require, $, angular, app) {
console.log(require);
console.log($);
console.log(angular);
console.log(app);
});
On my index.html only RequireJS is loaded via script tag, where the RequireJS loads the above code.
What works:
- in my Network monitor I can see that RequireJS, jQuery, Angular and app are loaded
- The console.log messages print correct for require, jQuery and app
The angular object is somehow undefined. But if I don't load it from CDN and use my local load, it works! The local file is a RequireJS wrapper that looks like this:
define(['/components/angular/angular.min.js'], function () {
return angular;
});
How do I get this work with Angular'S CDN? Or does this depend on support from Angular?
First, you are confusing "paths" with "shim"
Path is good, don't go for "shim" behavior. But, you need to make your "paths" proper:
paths: {
jquery: 'https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min',
// NOTE: angular is "plain JS" file
angular: 'http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min',
app: '../app'
}
Then, you need to let go of the need to have something returned to you... Just "use the force, Luke" :) and expect the right globals to be there when you need them:
require(['jquery', 'app', 'angular'], function($, app, thisValueDoesNotMatter) {
// you don't need to wrap "require" Just use global
console.log(require);
console.log($);
console.log(app);
// note, angular is loaded as "plain JavaScript" - not an AMD module.
// it's ok. It returns "undefined" but we just don't care about its return value
// just use global version of angular, which will be loaded by this time.
// because you mentioned it in your dependencies list.
console.log(window.angular);
});

Categories