I use requireJs to load my javascript files.
I import the lib pixi.js and pixi_extends.js, but pixi_extends generate an error because PIXI is undefined... I don't understand because pixi_extends should wait that pixi.js is uploaded before run.
It's the same with the Bundle, same error about pixi.
I don't understant, I did the "deps" correctly I assume!
loader-index.ts: (I use TypeScript!)
/// <reference path="../def/require.d.ts" />
/// <reference path="Init.class.ts" />
/**
* paths List of the files to load. (Cannot contains references TS classes)
* key: New reference name of the file.
* path: Relative path to /public/js/ of the file.
*
* shim Config about the libraries (dependencies and more).
* See http://requirejs.org/docs/api.html#config-shim
*/
require.config({
//urlArgs: "t=" + (new Date()).getTime(),
//baseUrl: "../",
paths: {
/*
******** Load libraries ********
*/
// Lib - jQuery
'jquery': '../generated/lib/jquery-1.10.2.min',
'jqueryUiCore': '../generated/lib/jquery.ui.core.min',
'jqueryUiEffect': '../generated/lib/jquery.ui.effect.min',
// Lib - Javascript extends
'class': '../generated/lib/class.min',
// Lib - Pixi
'pixi': '../generated/lib/pixi.min',
'pixiExtends': '../generated/lib/pixi_extends.min',
// Lib - Socket
'socketIo': '../generated/lib/socket.io.min',
// Lib - Pomelo
'pomeloclient': '../generated/lib/pomeloclient.min',
// Lib - Path finder
'aStar': '../generated/lib/AStar.min',
/*
******** Load shared source code ********
*/
'Message': '../generated/shared/Message.min',
'ValidatorMessage': '../generated/shared/ValidatorMessage.min',
/*
******** Load other scripts ********
*/
'bundle': '../generated/bundle.min'
},
shim: {
'jquery': {
exports: '$'
},
'jqueryUiCore': {
deps: ["jquery"],
exports: '$'
},
'jqueryUiEffect': {
deps: ["jquery"],
exports: "$"
},
'pixiExtends': {
deps: ["jquery", "pixi"]
},
'pomeloclient': {
deps: ["socketIo"]
},
'ValidatorMessage': {
deps: ["Message"]
},
'bundle': {
deps: ["pixi", "pixiExtends", "pomeloclient"]
}
}
});
/**
* [] Array of name that should be the same than those defined in the config.paths. Exception for the TS classes with reference in this file.
*/
require(
[
'Init.class',
'jquery', 'jqueryUiCore', 'jqueryUiEffect',
'class',
'pixi', 'pixiExtends',
'socketIo', 'pomeloclient',
'aStar',
'Message', 'ValidatorMessage',
'bundle'
],
(
_init,
$, jqueryUiCore, jqueryUiEffect,
_class,
_pixi, pixiExtends,
_socketIo, _pomeloclient,
_aStar,
_message, _validatorMessage,
_bundle
)
=> {
// Initialization.
var init = new _init.Init();
// Make shared source classes public, to help.
_exports([
_message.Message,
_validatorMessage.ValidatorMessage
]);
/**
* Export an array of object to made them public on the browser.
* #param objects - Array of objects. Class of function basically.
* #private
*/
function _exports(objects){
for(var i in objects){
_export(objects[i]);
}
}
/**
*Export an object to the browser to make it public.
* #param o Object to export.
* #param name Customise the name. Optional.
* #private
*/
function _export(o: any, name: any = ''){
if(!name){
name = o.name;
}
window[name] = o;
}
}
);
It should be enough to add the following entry to the shim section:
'pixi': {
exports: 'PIXI'
}
This turns this library into an AMD-compatibile module which can be used as a standalone dependency, also in the deps section of other shims.
Edit:
Reading your comments seems that this "pixi_extends" module is your own code; you're not supposed to shim your own modules, it's only meant to be used for legacy non-AMD libraries. If you want to augment Pixi with your customisations, do something like this:
define(['pixi'], function (ThePixiObject) {
ThePixiObject.customFunction = function () {
console.log('Pixi now has customFunction()');
}
// no need to return anything - we're only interested in the side-effect above
});
Recommended: official documentation regarding shim
NB. Also, there's no need to configure shim for jQuery, it's already AMD compatibile.
I fixed it with using the require() function in the pixi_extends and removing my changes from the official pixi.js lib. Now that works.
But the exports with requirejs doesn't have any effect, I don't get it. That should export in global the PIXI value, it's what that should do and that doesn't work.
I can export it manually once everything is loaded, it's a solution if I wanted to have PIXI as global. But I don't absolutely need it so I'll keep in this way.
But I would like to understand why the "shim exports" doesn't works.
Related
I've started a new project with the Angular CLI tool. After that I follow this official guide to import Underscore and I do exactly as it says.
But still my project crashes in the browser when I try to use Underscore in my app.component with the error message:
ORIGINAL EXCEPTION: ReferenceError: _ is not defined
Underscore is added to the dist/vendor folder so my guess would be that the problem is in the Systemjs configuration.
Here is my angular-cli-build:
var Angular2App = require('angular-cli/lib/broccoli/angular2-app');
module.exports = function(defaults) {
return new Angular2App(defaults, {
sassCompiler: {
includePaths: [
'src/styles'
]
},
vendorNpmFiles: [
'systemjs/dist/system-polyfills.js',
'systemjs/dist/system.src.js',
'zone.js/dist/**/*.+(js|js.map)',
'es6-shim/es6-shim.js',
'reflect-metadata/**/*.+(ts|js|js.map)',
'rxjs/**/*.+(js|js.map)',
'underscore/underscore.js',
'#angular/**/*.+(js|js.map)'
]
});
};
Here is my system-config:
"use strict";
// SystemJS configuration file, see links for more information
// https://github.com/systemjs/systemjs
// https://github.com/systemjs/systemjs/blob/master/docs/config-api.md
/***********************************************************************************************
* User Configuration.
**********************************************************************************************/
/** Map relative paths to URLs. */
const map: any = {
'underscore': 'vendor/underscore/',
};
/** User packages configuration. */
const packages: any = {
'underscore': { main: 'underscore.js', format: 'cjs' },
};
////////////////////////////////////////////////////////////////////////////////////////////////
/***********************************************************************************************
* Everything underneath this line is managed by the CLI.
**********************************************************************************************/
const barrels: string[] = [
// Angular specific barrels.
'#angular/core',
'#angular/common',
'#angular/compiler',
'#angular/forms',
'#angular/http',
'#angular/router',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
// Thirdparty barrels.
'rxjs',
// App specific barrels.
'app',
'app/shared',
/** #cli-barrel */
];
const cliSystemConfigPackages: any = {};
barrels.forEach((barrelName: string) => {
cliSystemConfigPackages[barrelName] = { main: 'index' };
});
/** Type declaration for ambient System. */
declare var System: any;
// Apply the CLI SystemJS configuration.
System.config({
map: {
'#angular': 'vendor/#angular',
'rxjs': 'vendor/rxjs',
'main': 'main.js'
},
packages: cliSystemConfigPackages
});
// Apply the user's configuration.
System.config({ map, packages });
My app.component:
/// <reference path="../../typings/globals/underscore/index.d.ts" />
import { Component } from '#angular/core';
declare var _;
#Component({
moduleId: module.id,
selector: 'app-root',
template: `<h1>{{title}}</h1>`
})
export class AppComponent {
title = _.version;
}
Where do I go wrong?
And WHY is this so complicated? Will the community accept it being this cumbersome to just add a simple third party library?
Your configuration basically sets up underscore so SystemJS can find it when needed.
When you changed system-config.ts, you told SystemJS: if anyone asks for underscore, it is a file underscore.js that can be found at the vendor/underscore/ folder -- and its module format is CommonJS (cjs).
The changes at angular-cli-build.js are for telling angular-cli what files it should pick and throw into the vendor folder. (So, if you told SystemJS it'd find underscore there, this is what makes it be there.)
But that alone does not import/add underscore into the global scope of your app.
You have to import it at each .ts file so SystemJS adds it to the transpiled .js of that module.
Instead of these two lines:
/// <reference path="../../typings/globals/underscore/index.d.ts" />
declare var _;
Add this to your file:
import * as _ from 'underscore';
If you have problems, try to inspect the generated .js source being executed at the browser. In your case, you'll probably find that there is no require() method importing the underscore.
The doco adding 3rd party lib is misleading.
I have been banging my head for over an hour!
declare var _; // this won't work.
What you need is
/// <reference path="../../../typings/globals/underscore/index.d.ts" />
import * as _ from 'underscore';
I'm new to working with RequireJS, and am trying to figure out shimming 3rd-party, interdependent scripts. Specifically, I'm trying to get the Stanford Crypto scripts imported.
Basically, the suite is comprised of the core (jsbn.js, jsbn2.js, base64.js, rng.js, and prng4.js), a basic RSA script (rsa.js), and an extended RSA script (rsa2.js).
rsa.js defines the global variable-object RSAKey, and rsa2.js references it.
function RSAKey() {
this.n = null;
this.e = 0;
this.d = null;
this.p = null;
this.q = null;
this.dmp1 = null;
this.dmq1 = null;
this.coeff = null;
}
I've set up my shim in a way that I thought was correct, but I get the error "RSAKey is not defined" in rsa2.js. The following is my shim:
require.config({
paths: {
'jsbn': "../StanfordRSA/jsbn.js",
'jsbn2': "../StanfordRSA/jsbn2.js",
'base64': "../StanfordRSA/base64.js",
'rng': "../StanfordRSA/rng.js",
'prng4': "../StanfordRSA/prng4.js",
'rsa': "../StanfordRSA/rsa.js",
'rsa2': "../StanfordRSA/rsa2.js"
},
shim: {
'rsa': {
deps: ['jsbn', 'jsbn2', 'base64', 'rng', 'prng4'],
exports: "RSAKey"
},
'rsa2': {
deps: ['rsa']
}
}
});
My understanding, then, is that if I set 'rsa2' as a requirement in one of my RequireJS modules, it would look at the shim and see that rsa2 is dependent on rsa, which is dependent on the core and exports RSAKey...But that's not what's happening, and it seems like either rsa isn't loading, or it isn't loading correctly. (Please note that all of this works using raw script tags. I'm trying to convert an already existing, already functioning webapp to RequireJS)
Thoughts?
Your basic setup is correct, except for 2 things:
(really important!) You have to omit the .js extensions!!!
You probably have missed the exact dependencies between the scripts.
After some experimentation and reading the comments at the top of the scripts, the working configuration is:
require.config({
paths: {
'jsbn': "../StanfordRSA/jsbn",
'jsbn2': "../StanfordRSA/jsbn2",
'base64': "../StanfordRSA/base64",
'rng': "../StanfordRSA/rng",
'prng4': "../StanfordRSA/prng4",
'rsa': "../StanfordRSA/rsa",
'rsa2': "../StanfordRSA/rsa2"
},
shim: {
'rng': {
deps: ['prng4']
},
'jsbn2': {
deps: ['jsbn']
},
'rsa': {
deps: ['jsbn', 'rng'],
exports: 'RSAKey'
},
'rsa2': {
deps: ['rsa', 'jsbn2'],
exports: 'RSAKey'
}
}
});
Check out a plunk here.
In the RequireJS example, it shows that you can reference a app.js (or whatever you want to call the starter file) from the script tag like so:
<script data-main="js/app.js" src="js/require.js"></script>
For reasons beyond my control, I can't do this. There are several dynamic variables generated in the template layer that need to be preserved. So, I created an inline 'config' module that other modules can read.
<script type="text/javascript">
define('config', function() {
return {
markup_id: {
"content": "search",
"page": "index",
"media": "mobile"
},
page_context: {
"siteconfig": {
"mobile_video_player_id": /* */,
"mobile_video_player_key": /* */,
"mobile_ad_site": /* */,
"omniture_mobile_env": /* */,
"searchserver": /* */,
},
"omniture": {
"gn": /* */,
}
}
}
});
</script>
What I have done is for each template, I placed an inline require.config. As an example (specific path information removed):
<script type="text/javascript">
/* This code is on a template page inside a script tag. */
require.config({
baseUrl: /* */,
paths: {
'jquery': /* */,
'jquery-mobilead': /* */,
'jquery-photogalleryswipe': /* */
},
/* Enforce ordering of jQuery plugins - which require jquery */
shim: {
'jquery-mobilead': {
deps: ['jquery'],
exports: 'jQuery.fn.mobileAd'
},
'jquery-photogalleryswipe': {
deps: ['jquery'],
exports: 'jQuery.fn.photoGallerySwipe'
},
'gallery': {
deps: ['jquery-photogalleryswipe', 'jquery-mobilead']
}
},
urlArgs: 'buildlife=#buildlife#'
});
require( ['jquery', 'site', 'gallery', 'jquery-photogalleryswipe', 'jquery-mobilead'], function($, site, gallery) {
//This function will be called when all the dependencies
//listed above are loaded. Note that this function could
//be called before the page is loaded.
//This callback is optional.
/* Initialize code */
$(document).ready(function() {
/* sitewide code - call the constructor to initialize */
site.init();
/* homepage contains a reference to a function - execute the function */
gallery.initGallery();
});
}
);
</script>
I presume the Optimizer has no way of optimizing code inside a template.
However I do have module JS files in accordance to the RequireJS API documentation.
/modules/gallery.js
/modules/channel.js
/modules/site.js
/* etc. */
These modules do have dependencies to other modules, but these modules are dependent on the 'config' module, which is defined inline with the template. If I ran the Optimizer against these files, will the optimizer work properly, since one of the modules, config, in is the template?
I think I solved my own problem based on reading
How to load bootstrapped models in Backbone.js while using AMD (require.js)
I've restructured the template variables into a require global object and declared it before require.js. Now, the template can still generate those values, but since the require.config and require code can be put into an external JS file, the optimizer should be able to see those files now. I haven't tried running the optimizer yet.
<script>
/* This script block is in the template */
var require = {
config: {
markup_id: {
"content": "search",
"page": "index",
"media": "mobile"
},
page_context: {
"siteconfig": {
"mobile_video_player_id": /* */,
"mobile_video_player_key": /* */,
"mobile_ad_site": /* */,
"omniture_mobile_env": /* */,
"searchserver": /* */,
},
"omniture": {
"gn": /* */,
}
}
};
</script>
<script data-main="/m/j/main-search" src="/m/j/require.js"></script>
Apologies if I have missed this in the docs. Basically I want to use the RequireJS module configuration feature. I would like to centrally manage the config values given to modules in a package.
This is an example from the docs:
requirejs.config({
config: {
'bar': {
size: 'large'
},
'baz': {
color: 'blue'
}
}
});
//bar.js, which uses simplified CJS wrapping:
define(function (require, exports, module) {
//Will be the value 'large'
var size = module.config().size;
});
//baz.js which uses a dependency array,
define(['module'], function (module) {
//Will be the value 'blue'
var color = module.config().color;
});
My problem is that my configuration info will be a little more complex, and will itself have dependencies. I would like to do:
requirejs.config({
config: {
'bar': {
path: path.dirname(module.uri)
key: crypto.randomBytes(64)
},
}
});
Where variables in my config need to use requireJS to evaluate.
To me it would make sense for there to be a logical separation between the RequireJS configuration - the config necessary to load modules - and the user's module configuration. But I am currently struggling to find this :(
For this sort of solution, I would have the module depend on a "config" module that you can swap for a different one using paths config. So if "bar" needed some config, "bar.js" would look like:
define(['barConfig'], function (config) {
});
Then barConfig.js could have your other dependencies:
define(['crypto'], function (crypto) {
return {
key: crypto.randomBytes(64)
}
});
Then, if you needed different configs for say, production vs. dev, use paths config to map barConfig to other values:
requirejs.config({
paths: {
barConfig: 'barConfig-prod'
}
});
I think the proper way to do this is to make a config module...
// config.js
define(['module', 'path', 'crypto'], function(module, path, crypto) {
return {
path: path.dirname(module.uri)
key: crypto.randomBytes(64)
};
});
Then use it in other modules...
// bar.js
define(['config'], function (config) {
var key = config.key;
});
You can then make it as complicated as you like!
EDIT: You could pollute the global namespace for this special class...
define(['module', 'path', 'crypto'], function(module, path, crypto) {
window.config = {
path: path.dirname(module.uri)
key: crypto.randomBytes(64)
};
});
Add it to the top level require call:
require(['config', 'main']);
Then you can use it without always adding it to your define:
// bar.js
define([], function() {
var key = config.key;
});
Having thought about this a little more I have come up with a workaround. It is not particularly pretty but it does seem to work.
I simply do requireJS(...) twice, first to create the config, and second to load the application modules with the config..
requireJSConfig =
baseUrl: __dirname
nodeRequire: require
# Create the require function with basic config
requireJS = require('requirejs').config(requireJSConfig)
requireJS ['module', 'node.extend', 'crypto', 'path'], (module, extend, crypto, path) ->
# Application configuration
appConfig =
'bar':
path: path.dirname(module.uri)
key: crypto.randomBytes(64) # for doing cookie encryption
# get a new requireJS function with CONFIG data
requireJS = require('requirejs').config(extend(requireJSConfig, config: appConfig))
requireJS ['bar'], (app) ->
###
Load and start the server
###
appServer = new app()
# And start the app on that interface (and port).
appServer.start()
And in bar.coffee
# bar.coffee
define ['module'], (module) ->
# config is now available in this module
console.log(module.config().key)
Riffing on what #jrburke is saying, I found the following pattern to be quite useful: define a config module and it's dependencies in the main.js just before the invocation of require.config().
main.js
define('config', ['crypto'], function (crypto) {
return {
'bar': {
key: crypto.randomBytes(64)
},
};
});
requirejs.config({
deps: ['app'],
});
app.js
require(['config'], function (config){
// outputs value of: crypto.bar.key
console.log(config.bar.key);
});
Plnkr Demo: http://plnkr.co/edit/I35bEgaazEAMD0u4cNuj
Is there a way to set the templateSettings for lodash when using RequireJS?
Right now in my main startup I have,
require(['lodash', 'question/view'], function(_, QuestionView) {
var questionView;
_.templateSettings = {
interpolate: /\{\{(.+?)\}\}/g,
evaluate: /\{\%(.+?)\%\}/g
};
questionView = new QuestionView();
return questionView.render();
});
but it doesn't seem to want to set the templateSettings globally because when I use _.template(...) in a module it wants to use the default templateSettings. The problem is that I don't want to change this setting in every module that uses _.template(...).
Based onĀ #Tyson Phalp suggestion, that means this SO question.
I adapted it to your question and I tested it using RequireJS 2.1.2 and SHIM configuration.
This is the main.js file, that is where the requireJS config is:
require.config({
/* The shim config allows us to configure dependencies for
scripts that do not call define() to register a module */
shim: {
underscoreBase: {
exports: '_'
},
underscore: {
deps: ['underscoreBase'],
exports: '_'
}
},
paths: {
underscoreBase: '../lib/underscore-min',
underscore: '../lib/underscoreTplSettings',
}
});
require(['app'],function(app){
app.start();
});
Then you should create the underscoreTplSettings.js file with your templateSettings like so:
define(['underscoreBase'], function(_) {
_.templateSettings = {
evaluate: /\{\{(.+?)\}\}/g,
interpolate: /\{\{=(.+?)\}\}/g,
escape: /\{\{-(.+?)\}\}/g
};
return _;
});
So your module underscore will contain the underscore library and your template settings.
From your application modules just require the underscore module, in this way:
define(['underscore','otherModule1', 'otherModule2'],
function( _, module1, module2,) {
//Your code in here
}
);
The only doubt I have is that I'm exporting the same symbol _ two times, even tough this work I'm not sure if this is considered a good practice.
=========================
ALTERNATIVE SOLUTION:
This also works fine and I guess it's a little bit more clean avoiding to create and requiring an extra module as the solution above. I've changed the 'export' in the Shim configuration using an initialization function. For further understanding see the Shim config reference.
//shim config in main.js file
shim: {
underscore: {
exports: '_',
init: function () {
this._.templateSettings = {
evaluate:/\{\{(.+?)\}\}/g,
interpolate:/\{\{=(.+?)\}\}/g,
escape:/\{\{-(.+?)\}\}/g
};
return _; //this is what will be actually exported!
}
}
}
You should pass your _ variable with template settings as function argument or as property in global object (window for browsers or proccess for nodejs).
_.templateSettings = {
interpolate: /\{\{(.+?)\}\}/g,
evaluate: /\{\%(.+?)\%\}/g
};
questionView = new QuestionView(_);
Or
_.templateSettings = {
interpolate: /\{\{(.+?)\}\}/g,
evaluate: /\{\%(.+?)\%\}/g
};
window._ = _
First option is better.
Bear in mind that if you're using underscore >=1.6.0 or lodash-amd the solution is pretty simple:
"main.js" configuration file
require.config({
baseUrl: './', // Your base URL
paths: {
// Path to a module you create that will require the underscore module.
// You cannot use the "underscore" name since underscore.js registers "underscore" as its module name.
// That's why I use "_".
_: 'underscore',
// Path to underscore module
underscore: '../../bower_components/underscore/underscore',
}
});
Your "_.js" file:
define(['underscore'], function(_) {
// Here you can manipulate/customize underscore.js to your taste.
// For example: I usually add the "variable" setting for templates
// here so that it's applied to all templates automatically.
// Add "variable" property so templates are able to render faster!
// #see http://underscorejs.org/#template
_.templateSettings.variable = 'data';
return _;
});
A module file. It requires our "_" module which requires "underscore" and patches it.
define(['_'], function(_){
// You can see the "variable" property is there
console.log(_.templateSettings);
});