Fetch requirejs.config from Gruntfile - javascript

Is there any way to import a requirejs config in to my grunt config file? Right now I have to keep two identical versions, one in app/main.js and one in my Gruntfile.js:
module.exports = function(grunt) {
// can I import app/main.js requireConfig here?
var requireConfig = {
paths: {
jquery: 'lib/jquery'
// etc...
}
};
});
My main.js looks something like this:
requirejs.config({
paths: {
jquery: 'lib/jquery'
// etc...
}
});
define(['app'], function(app){
app.start();
});

You can use standard module pattern which supports different type of module system like following.
Your requirejs config file like this
amd-config.js
(function(factory) {
if (typeof define === 'function' && define.amd) {
// Register as an AMD module if available...
define('amd-config', [], factory());
} else if (typeof exports === 'object') {
// Next for Node.js, CommonJS, browserify...
module.exports = factory();
} else {
// setting browser global when none of the above are available
window.amdConfig = factory();
}
}
(function() {
var amdConfig = {
baseUrl: 'scripts',
paths: {
//Paths here
}
};
return amdConfig;
}));
In gruntfile you can just require like any other module.
var requireConfig = require('amd-config');
Include it normally like you do in index.html with script tag before app.js
and then in app.js use it like following.
requirejs.config(window.amdConfig);
define(['app'], function(app){
app.start();
});
PS: There are cleaner way of including it in app.js.
More cleaner than second, create global variable require and include the script before requirejs script. requirejs checks if there is global variable with name require containing object. If its there, it is used as a config object. So you dont have to call requirejs.config yourself.
You can require the file like you require other files. In that case it will be treated as a require module and you will receive the object in require callback. call your requirejs.config like following.
```
require(['amd-config'], function(amdConfig){
requirejs.config(amdConfig);
require(['app'], function(app){
app.start();
});
});
```

A simpler approach you could use, if you are using grunt to build the project. You can simply use:
options:{
mainConfigFile: "path/to/Config.js"
}
granted you need to use:
https://github.com/gruntjs/grunt-contrib-requirejs

You can try something like this:
function getRequireConfig(requireFilePath) {
var config;
var configFileContent,
_require;
_require = require;
require = {
data: {},
config : function (configParam) {
this.data = configParam;
},
get : function () {
return this.data;
}
};
configFileContent = readFileSync(requireFilePath);
eval(configFileContent);
config = require.get();
require = _require;
return config;
}
What it is doing is:
Override require definition to a custom implementation
Load require config file
Eval it so that the config function of custom implementation will be
called Get the config object from data

Related

Use rollup.js with jQuery adaptor in same file

I have the main function to export and the jQuery adaptor in the same file. And I would like to keep them this way.
Is there a way with rollup.js to create the bundle file compatible with AMD, CommonJS and Browsers?
Right now I have this test file:
//src/foo.js
export default function(){
function initialise() {
var TEST = {};
TEST.version = '1.0.0';
TEST.hello = function(){
console.log("hello man!!");
};
return TEST;
}
//jQuery adapter
(function($){
$.fn.demo = function(options) {
$.fn.demo.test = 'test';
};
})(jQuery);
return initialise;
};
And I tried using this rollup config:
// rollup.config.js
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'umd',
globals: {
$: '$'
}
}
};
However I can't seem to have access to $.fn.demo:
// src/main.js
import jQuery from 'jQuery';
import pepe from './foo.js';
console.log(jQuery); //<--- undefined
console.log($); //<--- undefined
console.log("-- JS--");
console.log(pepe); //<---- working fine
console.log("-- $.fn.demo --");
console.log($.fn.demo); //<--- undefined
Note that in your main.js file pepe is a function (one which you exported from foo) and you didn't call it hence $.fn.demo is undefined. You must call pepe(); in order for you adapter to be executed.
See also how to tell Rollup that jquery is external and the jquery module ID equates to the global $ variable.

RequireJS pass config to module always returns undefined

I've tried the solution in other SO post, e.g. this, but it didn't seem to work. I always got undefined as a result.
My configuration in my HTML.
<script type="text/javascript">
var require = {
config: {
'config': { --> if I change this to app, I could read the value in app.js
userId: 1
}
}
};
</script>
<script src="lib/require.min.js" data-main="app"></script>
My config module:
define(['module'], function (module)
{
return {
userId: module.config().userId,
userName: "Test"
}
});
I use the config module in my app.
require(['modules/config', 'modules/A'], function (config, a)
{
var userId = config.userId; --> undefined
var userName = config.userName; --> Test
});
Any idea? Did I miss something? I use JQuery 1.12.3 and RequireJS 2.2.0.
Solution
Edit the config you pass to RequireJS to:
var require = {
config: {
'modules/config': {
userId: 1
}
}
};
Explanation
Your modules ids are not matching. When you require your module, you use require(['modules/config', .... So the module name is modules/config. However, in your RequireJS configuration you provide a configuration for the module named config. So when you use module.config() inside modules/config, RequireJS searches for a module named modules/config in the configuration and does not find it. So you get undefined. Performing the fix I mentioned earlier will allow RequireJS to find the configuration.
Alternatively you could use paths to have the module be loaded under the name config:
var require = {
paths: {
config: 'modules/config'
},
config: {
config: {
userId: 1
}
}
};
And use require(['config', ....
I followed the below technique to get it working. The files included in HTML. They can defined in config paths.
Directory structure:
-index.html
-modules
- myModule.js
-app.js
HTML (index.html)
<script type="text/javascript">
// require would refer to the require.js global. So i am using requireVar
var requireVar = {
config: {
userId: 1
}
};
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.2.0/require.min.js"></script>
<script src="modules/myModule.js"></script>
<script src="app.js"></script>
file myModule.js
define("modules/myModule",function ()
{
return function(){
return requireVar.config.userId;
}
});
and finally my app.js
require(['modules/myModule'], function (myModule)
{
alert("");
var userId = myModule();
console.log(userId);
});

require not defined with gulp-browserify

I'm trying to load modules in browser but I'm getting this error:
Uncaught ReferenceError: require is not defined
What I'm doing is creating the js in main.js and sending it over into the build as app.js
Here's my gulpfile.js
var browserify = require('gulp-browserify');
...
gulp.task('scripts', function() {
gulp.src('src/scripts/main.js')
.pipe(browserify({
insertGlobals : true,
debug : !gulp.env.production
}))
.pipe(gulp.dest('build/js'))
});
...
gulp.task('default', ['clean', 'concat', 'uglify', 'scripts']);
And my main.js
var fs = require('fs');
function getIt() {
var items = fs.readFileSync("../../data/data.json");
var jsonItems = JSON.parse(items);
console.log(jsonItems);
}
getIt();
How can I make this work in my template?
If you need external requires, you'll have to set the require property with the name of the file on the options object you pass to browserify. This will make browserify create the require function for you, so you can use later on use it outside the produced script.
...
.pipe(browserify({
insertGlobals : true,
require : ['src/scripts/main.js'],
debug : !gulp.env.production
}))
...

failing to fetch method requireJS

I am experiencing some strange issue. I have this
require({
paths: {
'template': 'tmpl.min',
'videoupload.widget': 'jquery.ui.videoupload'
}
}, ['js/main_video.js'], function(App) {
App.initial_video_upload();
});
and this
define(['template','videoupload.widget'],function() {
function initial_video_upload(){
'use strict';
$('#videoupload').videoupload({
//...some code
});
}
return{
initial_video_upload: initial_video_upload
}
}
);
in the file jquery.ui.videoupload.js, I have some call to a tmpl method which is defined in tmpl.min.js, but I get the message
Uncaught TypeError: Object [object Object] has no method 'tmpl'
There are two issues here:
Your first snippet is passing configuration options to a require function. require, is a way to load dependencies and execute some code using them. If you want to pass configuration options to require.js, requirejs.config is what you want:
// configurations to be used in your module definitions
requirejs.config({
paths: {
'template': 'tmpl.min',
'videoupload.widget': 'jquery.ui.videoupload'
}
});
// load your main module and kick things off
require(['js/main_video.js'], function(App) {
App.initial_video_upload();
});)
Your second snippet is declaring dependencies, but not passing them into the callback:
define(['template','videoupload.widget'],
// these are now accessible within the function's scope:
function(template, videoupload.widget) {
function initial_video_upload(){
'use strict';
$('#videoupload').videoupload({
//...some code
});
}
return{
initial_video_upload: initial_video_upload
}
}
);
Additionally, I'm assuming jQuery is a dependency of your videoupload.widget. How are you loading that? You may need to add an additional "shim" configuration to your requirejs.config:
requirejs.config({
paths: {
'template': 'tmpl.min',
'videoupload.widget': 'jquery.ui.videoupload'
},
shim: {
"videoupload.widdget": ["jquery"]
}
});

How to load bootstrapped models in Backbone.js while using AMD (require.js)

Backbone.js documentation suggest loading bootstrapped models this way:
<script>
var Accounts = new Backbone.Collection;
Accounts.reset(<%= #accounts.to_json %>);
var Projects = new Backbone.Collection;
Projects.reset(<%= #projects.to_json(:collaborators => true) %>);
</script>
But this is a pattern that can't be used in AMD approach (using require.js)
The only possible solution is to declare global variable storing JSON data and use this variable later in relevant initialize methods.
Is there a better way to do this (without globals)?
This is how we bootstrap data in a way that it doesn't pollute the global namespace. Instead it uses require.js exclusively. It also helps you provide the initial app configuration based on variables within the template.
Within your rendered page
<script src="require.js"></script>
<script>
define('config', function() {
return {
bootstrappedAccounts: <%= #accounts.to_json %>,
bootstrappedProjects: <%= #projects.to_json(:collaborators => true) %>
};
});
</script>
<script src="app.js"></script>
globals.js
This file checks for config and extends itself using any of the data returned
define([
'config',
'underscore'
], function(config) {
var globals = {
};
_.extend(globals, config);
return globals;
});
config.js
This file is needed if you want be able to load the app regardless of if you have defined config in the page.
define(function() {
// empty array for cases where `config` is not defined in-page
return {};
});
app.js
require([
'globals',
'underscore',
'backbone'
], function(globals) {
if (globals.bootstrappedAccounts) {
var accounts = new Backbone.Collection(globals.bootstrappedAccounts);
}
if (globals.bootstrappedProjects) {
var projects = new Backbone.Collection(globals.bootstrappedProjects);
}
});
Looks like you can use the require.config() function or the "require" global with the "config" option in order to pass data to a module through the special dependency "module". See http://requirejs.org/docs/api.html#config-moduleconfig:
There is a common need to pass configuration info to a module. That
configuration info is usually known as part of the application, and
there needs to be a way to pass that down to a module. In RequireJS,
that is done with the config option for requirejs.config(). Modules
can then read that info by asking for the special dependency "module"
and calling module.config().
So, for bootstrapping models we have, in the top level HTML page:
<script>
var require = {
config: {
'app': {
bootstrappedAccounts: <%= #accounts.to_json %>
bootstrappedProjects: <%= #projects.to_json(:collaborators => true) %>
}
}
};
</script>
<script src="scripts/require.js"></script>
Then in the app module (app.js), we have:
define(['module'], function (module) {
var accounts = new Backbone.Collection( module.config().bootstrappedAccounts );
var bootstrappedProjects = new Backbone.Collection( module.config().bootstrappedProjects );
});
Here "module" is a special dependency supplied for these types of cases.
This is untested but looks pretty sure from the documentation.
In RequireJS this is done with the config option for requirejs.config(). Modules can then read that info by asking for the special dependency "module" and calling module.config(). Example:
index.html
<script>
var require = {
config: {
'app': {
'api_key': '0123456789-abc'
}
}
};
</script>
<script src="js/libs/require.js" data-main="js/main"></script>
main.js
require( ['app'], function(App) {
new App();
});
app.js
define( ['module'], function(module) {
var App = function() {
console.log( 'API Key:', module.config().api_key );
};
return App;
});
Just note that the name of the configuration-object must match the name of the module. In my example the name of the module was app, so the name of the configuration-object needed to be named app as well. In the module, you will need to include ['module'] as a dependency and call module.config()[property name] to retrieve the configuration-data.
Read the documentation about this: http://requirejs.org/docs/api.html#config-moduleconfig
Some of the answers here got me close to my similar problem but nothing nailed it. In particular the top ranked and accepted answer gave seemed to give me a nasty race condition where sometimes the dummy object would load first. This also happened 100% of the time when used with the optimiser. It also uses explicit string names for the module which the require documentation specifically advises you not to do.
Here's how I worked it. Similar to Brave Dave, I use the config object to capture parameters (in my case from a jsp page) like so
<script type="text/javascript">
var require = {
config: {
options : {
bootstrappedModels : ${models}
}
}
}
</script>
In particular note that my parameters are in an object called options. This name is not optional! Though the documentation makes no mention of this, the following is how require will load your config (line 564 in requirejs 2.1.1) :
config: function () {
return (config.config && config.config[mod.map.id]) || {};
},
The key point is that there has to be property on the config object with the key mod.map.id which resolves to 'options'.
From here you can now access the models like so
define(['module'], function(module){
console.log(module.config().bootstrappedModels);
//...
});
You could add a loopy function at the end of your AMD module to check for when the init method is defined (so that it can be populated after body, or loaded from an include). that way the module is guaranteed available and initialization can happen when it's ready.
require(...,function (...) {
//define models collections, etc..
var initme = function () {
if(document.initThisModule)
document.initThisModule();
else
setTimeout(initme, 10);
}();
});
I'm not (too) familiar with the AMD approach, but instead of using a global variable, why don't you add the JSON to the dom.
for example:
var json = ...,
$jsonContainer = $(json).wrap("<script id='json-container' type='text/javascript'>").appendTo($("body"));
Then, instead of an embedded script tag as suggested by the backbone documentation, inside the document ready:
$(function(){
MyCollection.reset($("#json-container").html());
...
});
How about doing something like this:
<script>
define('Models', ['backbone'], function(Backbone) {
var Models = {
Accounts: new Backbone.Collection,
Projects: new Backbone.Collection
};
Models.Accounts.reset(<%= #accounts.to_json %>);
Models.Projects.reset(<%= #projects.to_json(:collaborators => true) %>);
return Models;
});
</script>
Then you'll be able to use Models in other modules like this:
var models = require(['Models']);
models.Accounts.doWhatYouNeed();
or this:
define(['any', 'dependencies', 'and', 'Models'], function(a, b, c, Models) {
// Models will be available here
});
Like described above, the 'data module' (or config, or whatever you want to call it) could be included in a file that is already generated anyway (e.g. index.html) but I think this is rather ugly.
Another way would be to declare it in its own module file but this would require an extra roundtrip to the server in production environments. As soon as you want to build and optimize your requirejs dependencies, the data module cannot be included because it is dynamically generated upon page load.
A third option might be to append it to one of the files that you serve (for example, the optimized requirejs file), but I have no idea of how/if that could be done.
Ansewr by #dlrust work but it not able extend param and pass more than from one place in code. If you try do something like this in your render template:
<script>
define('config', function() {
return {
bootstrappedAccounts: <%= #accounts.to_json %>,
bootstrappedProjects: <%= #projects.to_json(:collaborators => true) %>
};
});
</script>
and in another file add some data
<script>
define('config', function() {
return {
goods: <%= some data %>,
showcaseList: <%= some json or array %>
};
});
</script>
it was overwrite (NOT EXTEND!!!). In config will be only last declared data.
My solution: used Backbone model with set/get data.
app.js
define("App", [], function() {
window.App = {
// модели
Model: {},
// коллекции
Collection: {},
// виды
View: {},
// роутеры
Router: {},
// модальные окна
Modal: {},
// UI компоненты
UI: {}
};
return window.App;
});
global.js
define(["App", "underscore", "backbone"], function(App, _, Backbone) {
"use strict";
// модель глобальных данных
App.Model.Global = Backbone.Model.extend({
defaults: {}
});
return new App.Model.Global;
});
index.php
<!DOCTYPE html>
<html>
<head>
<!--HEAD_START-->
<script type="text/javascript" data-main="/app/init" src="/app/require/require.js"></script>
<!--HEAD_END-->
</head>
<body>
<div id="tm-inner-wrap">
<div id="loader"><i class="uk-icon-refresh uk-icon-spin"></i></div>
<!--HEADER_START-->
<?= $this->includeTpl('header_view'); ?>
<!--HEADER_END-->
<!--CONTENT_START-->
<div>your html content data</div>
<!--CONTENT_END-->
<!--FOOTER_START-->
<?= $this->includeTpl('footer_view');?>
<!--FOOTER_END-->
<script>
require(["global"], function(Global) {
Global.set("notifyList", <?=json_encode($this->notifyList);?>);
});
</script>
</div>
</body>
</html>
another template
someTemplate.php
<div class="tm-inner-body">
<div class="uk-container uk-container-center">
// content data
</div>
</div>
<script>
require(["global", "module/index"], function(Global) {
Global.set("goodList", <?=json_encode($this->goodList);?>);
});
</script>
index.js
require(["App", "core", "jquery", "uikit!uikit-addons-min", "underscore", "backbone", "global", "module/good/goodView"], function(App, Core, $, UIkit, _, Backbone, Global, goodView) {
"use strict";
// Global.get("notifyList"); its too able
App.Collection.Good = new Backbone.Collection(Global.get("showcaseList")["items"]);
// вид списка товаров
App.View.GoodList = Backbone.View.extend({
// елемент
el: ".tm-good-list",
// init
initialize: function() {
this.collection = App.Collection.Good;
// список товаров
this.drawList();
},
// отрисовка списка
drawList: function() {
this.$el.empty();
this.collection.each(function(item, index) {
this.$el.append(this.drawItem(item));
}, this);
},
// отрисовка елемента
drawItem: function(data) {
var good = new goodView({model: data});
return good.render().el;
}
});
App.View.Index = Backbone.View.extend({
el: "body",
// пользовательские события
events: {
//
},
// init
initialize: function() {
var $this = this;
if(Global.get("showcaseList")) new App.View.GoodList();
}
});
new App.View.Index();
});
File structure:

Categories