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.
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);
});
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
}))
...
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"]
}
});
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: