curious dependency loading behaviour in requirejs - requirejs

I've been having trouble loading dependencies in requirejs, so have tried to recreate the simplest possible structure that shows my problem. The html file contains a bootstrap typeahead box that I want to fill with data once the page loads. If my main.js script is:
requirejs.config({
paths: {
jquery: 'libs/jquery/jquery-min',
bootstrap: 'libs/bootstrap/bootstrap.min',
underscore: 'libs/underscore/underscore-min',
backbone: 'libs/backbone/backbone-optamd3-min',
cs: 'libs/require/cs',
'coffee-script': 'libs/coffeescript/coffee-script'
},
shim: {
bootstrap: {
deps: ['jquery']
}
});
require(['cs!router']);
and my backbone entry point is a very simple router:
define ['jquery','underscore','backbone','bootstrap'], ($, _, Backbone) ->
AppRouter = Backbone.Router.extend
initialize: () ->
#data = ['one','two','three']
routes: '': 'index'
index: () ->
$('.typeahead').typeahead({source:#data})
app_router = new AppRouter
Backbone.history.start()
then if the page loads from a cleaned webcache, I get the following errors on the console:
TypeError: a is not a function
TypeError: $(".typeahead").typeahead is not a function
Error: Load timeout for modules: cs!router
http://requirejs.org/docs/errors.html#timeout
If I simply reload the page, all the errors disappear and everything works ok. I'd be really grateful if someone could explain to me what is happening here, thanks.

Ok, fixed by using
<script data-main="js/main" src="js/libs/require/require-jquery.js"></script>
instead of
<script data-main="js/main" src="js/libs/require/require.js"></script>
in main html file.

Related

Unable to find Blockly Generator function in Angular application

I am trying to build a Blockly Application using Angular. I installed Blockly using npm . I also added the following scripts in angular.json
"scripts": [
"node_modules/blockly/blockly_compressed.js",
"node_modules/blockly/blocks_compressed.js",
"node_modules/blockly/python_compressed.js",
"node_modules/blockly/msg/en.js"
]
Though i can use import * as Blockly from 'blockly' to import blockly in the application and use other functions, I am not able to find Generator functions like Blockly.Python['text_indexOf']
I am using blockly: ^3.20200625.2 and #angular/cli: ~9.1.0 versions.
Am i missing something. Can anyone help me with this issue?
I've had the same problem with electron+angular app building, the next solution had helped me.
Blockly's reference says that Python's generator class should be included with file python_compressed.js right after blockly_compressed.js. So I need to include these files.
First I've used copy-webpack-plugin to copy needed files from Blockly's install directory node_modules/blockly to assets/js:
var CopyPlugin = require('copy-webpack-plugin');
module.exports = {
...
plugins: [
...
new CopyPlugin([
{
from: 'node_modules/blockly/blockly_compressed.js',
to: 'assets/js/[name].[ext]'
},
{
from: 'node_modules/blockly/blocks_compressed.js',
to: 'assets/js/[name].[ext]'
},
{
from: 'node_modules/blockly/python_compressed.js',
to: 'assets/js/[name].[ext]'
},
{
from: 'node_modules/blockly/msg/en.js',
to: 'assets/js/msg/[name].[ext]'
},
]),
...
]
...
}
After I've added scripts calling from js/assets directly from index.html's bottom:
<!DOCTYPE html>
<html>
<head>...</head>
<body><app-root>...</app-root></body>
<script src="assets/js/blockly_compressed.js"></script>
<script src="assets/js/blocks_compressed.js"></script>
<script src="assets/js/python_compressed.js"></script>
<script src="assets/js/msg/en.js"></script>
</html>
After webpack build check python's generator in console:
> typeof Blockly.Python
< "object"

Load "on the fly" code with requirejs

I'm trying to create an online interactive js programming test-bed. I have a code window and a target iframe where the code gets loaded to execute. I wrap the code in html and load it into the iframe. The problem is that the code I want to be testing is normally loaded via requirejs using a data-main parameter. It appears that the code needs to be loaded from a separate file so that I can't include it in the html itself.
What works but doesn't help me is creating a file on the server to use as the target of the data-main parameter and sending html to the iframe that requires requirejs and then loads my code.
html:
<html>
....
<script type="text/javascript" src="lib/requirejs/require.js" data-main="src/requireConfigTest"></script>
....
</html>
contents of requireConfigTest.js:
/*globals require*/
require.config({
shim: {
},
paths: {
famous: 'lib/famous',
requirejs: 'lib/requirejs/require',
almond: 'lib/almond/almond',
'famous-polyfills': 'lib/famous-polyfills/index'
}
});
// this is the injection point where the dynamic code starts
define(function (require,exports,module) {
var Engine = require("famous/core/Engine");
var Surface = require("famous/core/Surface");
var mainContext = Engine.createContext();
var surface = new Surface({
size: [100, 100],
content: "Hello World",
classes: ["red-bg"],
properties: {
textAlign: "center",
lineHeight: "20px"
}
});
alert('hi');
mainContext.add(surface);
});
//this is the end of the dynamic code
This requires writing the dynamic code back to the server, not a reasonable solution. I'm trying to implement something like this...
html:
<html>
....
<script type="text/javascript" src="lib/requirejs/require.js"</script>
<script type="text/javascript">
/*globals require*/
require.config({
shim: {
},
paths: {
famous: 'lib/famous',
requirejs: 'lib/requirejs/require',
almond: 'lib/almond/almond',
'famous-polyfills': 'lib/famous-polyfills/index'
}
});
// this is the injection point where the dynamic code starts
define(function (require,exports,module) {
var Engine = require("famous/core/Engine");
var Surface = require("famous/core/Surface");
var mainContext = Engine.createContext();
var surface = new Surface({
size: [100, 100],
content: "Hello World",
classes: ["red-bg"],
properties: {
textAlign: "center",
lineHeight: "20px"
}
});
alert('hi');
mainContext.add(surface);
});
//this is the end of the dynamic code
</script>
This fails with the message:
Uncaught Error: Mismatched anonymous define() module: function
(require, exports, module) {...
My hope is to either find a way to reformat the code above in the second script tag or find a way to pass the actual contents of requireConfigTest.js via data-main instead of passing the name of the file to load.
Any help here would be greatly appreciated.
Since you are not actually defining a module with your define call, you could just use require:
require(["famous/core/Engine", "famous/core/Surface"], function (Engine, Surface) {
var mainContext = Engine.createContext();
// Etc...
You can think of define as being a require call which additionally defines a module. The way you are using define it is defining a module that does not have a name because you did not give it a name (which is generally the right thing to do) but it is not loaded from a .js file. When you don't give a name to a module as the first argument of define, RequireJS assigns a name from the .js file it loads the module from.
Another thing to keep in mind is that require schedules its callback for execution right away. (The callback is not executed right away but it scheduled for execution right away.) Whereas define does not schedule anything. It just records the callback and then when a require call (or something equivalent) requires it, the callback is executed.

RequireJS: execute jQuery code domReady

My main.js file looks like this:
require.config({
paths: {
"jquery": "3rd_party/jquery-2.0.3.min",
"bootstrap": "3rd_party/bootstrap.min",
"handlebars":"3rd_party/handlebars",
"html5shiv":"3rd_party/html5shiv",
"modernizr":"3rd_party/modernizr",
"respond":"3rd_party/respond.min",
"jquery-ui":"3rd_party/jquery-ui-1.10.3.custom.min",
'fancybox':'3rd_party/jquery.fancybox.pack'
},
shim: {
"bootstrap": {
deps: ["jquery"]
},
"jquery-ui": {
deps: ["jquery"]
},
"fancybox": {
deps: ["jquery"]
}
}
})
requirejs(["jquery", "fancybox","controllers/" + controller,'modules/login','bootstrap','handlebars','html5shiv','modernizr','respond', 'jquery-ui'],function($,fancybox,controller,handleLogin) {
$(document).ready(function() {
if ($(window).width()>991) {
$(".sidebar").height($(".maincontent").height());
}
$(".searchresults .greencol").height($(".searchresults .article").first().height()-100);
$('.login').click(function() {
handleLogin();
return false;
})
$('.fancybox-inline').fancybox({
maxWidth : 800,
maxHeight : 600
});
$('.fancybox-document').fancybox({
width: 660,
height: 440
});
$('.fancybox-close-button').click(function() {
$.fancybox.close();
return false;
})
});
controller.init();
})
Now with everything happening, it actually takes some time to execute this bit:
if ($(window).width()>991) {
$(".sidebar").height($(".maincontent").height());
}
And the page results in a little flicker.
My only idea is to include jQuery separately in index.html and put this bit in <script>tags. But then my RequireJS setup broke.
Do you have any suggestions how to achieve this?
So you want the resizing to happen as early as possible. It's not completely clear to me how you tried to do it earlier but doing this is the way to make it happen as early as possible, and not break or bypass RequireJS:
Take the following out of your current requirejs callback:
if ($(window).width()>991) {
$(".sidebar").height($(".maincontent").height());
}
Add the following call to requirejs in front of your current call:
requirejs(["jquery"], function($) {
$(document).ready(function() {
if ($(window).width()>991) {
$(".sidebar").height($(".maincontent").height());
}
});
});
By the way, this does not need to be in a different <script> element. You can just put the new call to requirejs right in front of the one you already have. Done this way, the resizing will happen as soon as jQuery is loaded.

SVG.js plugins and RequireJS

I am trying to write an SVG.js plugin to create some dynamic graphics. The site I want to use it in uses requireJS via django-require.
I am struggling to get the plugins to augment the SVG object, exported by SVG.js, properly.
The plugin is modelled after svg.path.js, another SVG.js plugin, and looks something like this:
(function() {
SVG.extend(SVG.Path, {
myGraphicType: function(p){
return this;
}
});
}).call(this);
My plugin will depend on svg.path and svg. svg.path also depends on svg. The shim entry in the requireJS config looks like:
shim: {
'svg-0.32' : {
exports: 'SVG'
},
'svg.path': {
deps: ['svg-0.32']
},
'svg.myplugin': { //My plugin!
deps: ['svg-0.32', 'svg.path']
}
}
The main app is defined() to depend on both svg and svg.myplugin. However, when I come to use the plugin like this:
var myGraphic = SVG.path().myGraphicType()
I am told that SVG is not defined in the svg.myplugin.js file.
What is the right way to include plugins like this using requireJS?

How to write a lodash template loader for requirejs

I'm using a requirejs plugin to define "tmpl!" loader (not a jquery template, but a lodash template. The problem is that the text! loader is adding a ";" at the end of the template. This is being rendered and is breaking everything.
(function(global){
"use strict";
define({
load : function(name, require, load, config) {
var deps = [];
deps.push('text!' + name);
deps.push('underscore');
require(deps, function(source, _) {
var template = _.template(source);
load(template);
});
}
});
})(this);
How can I stop text! from adding a semi-colon? Or: is there a better way to do this?
Taking the questions in reverse order:
is there a better way to do this?
It seems there is an existing implementation of this, and you might want to consider using it rather than writing your own. Although the simple case is a small amount of code, there are a bunch of r.js optimizer-related things you might eventually need.
But regarding your implementation logic, I noticed that this similar project for Handlebars does not use the text! plugin but instead does its own XHR in the load() method. This is not explained, but he gives some guidance for adapting it to other templating languages. Note: the link came from this question where there is some other good discussion of the approach.
How can I stop text! from adding a semi-colon?
I tried your plug-in and did not get any added semicolons. Perhaps you could post more of the sample project and templates? Below is mine, with everything in one flat folder for simplicity:
require.js: latest from RequireJS site
domReady.js: latest from RequireJS site
text.js: latest from RequireJS site
lodash.js: latest from lodash site
tmpl.js: your example loader from the question
index.html:
<!DOCTYPE html>
<html>
<head>
<script src='require.js'></script>
<script>
requirejs.config({
map: {
'*': { 'underscore': 'lodash' }
}
});
require( [ 'underscore', 'tmpl!friend-template.htm', 'domReady!' ]
, function( _, friendTemplate ){
var friendsData = [{ name: 'Bob', age: 35 }, { name: 'Fred', age: 38 }];
document.body.innerHTML = friendTemplate( {friends: friendsData});
});
</script>
</head>
<body>
<!-- To be populated dynamically. -->
</body>
</html>
friend-template.htm:
<ul>
<% _.forEach(friends, function(friend) { %>
<li>
<span><%- friend.name %></span>
<span>( Age: <span class="value"><%- friend.age %></span> )</span>
</li>
<% }); %>
</ul>
I've created a loader specifically for Lo-Dash which you can see here:
https://gist.github.com/tbranyen/6821045
Note: I have no unit tests or assurances this free of bugs, but from my initial testing it appears to work fantastic.
This is better in a number of ways than requirejs-tpl which bakes in it's own implementation which is not exposed. It also requires a file extension and hardcoded path. Both of these are configurable in my code.
Edit: I've since released a project called lodash-template-loader which has tests. https://github.com/tbranyen/lodash-template-loader

Resources