what's mean "!" in require.js - requirejs

What's mean "!" in require.js when I included module ?
What's syntax ?
I what includ dinamic stylesheet in my project and I found https://github.com/martinsb/require-css plugin
It's works fine .
require(['css!css/sample.css'], function() {
alert('Stylesheet has been loaded');
});
Why ['css!css/sample.css'] include css.js and css/sample.css ?
Edit:
I know alternative :
define(["controller", "RequireCSS","marionette"],
function (Controller, css, Marionette) {
css.load("default.css");
RequireCSS.js
define(function () {
return {
load: function (url) {
var link = document.createElement("link");
link.type = "text/css";
link.rel = "stylesheet";
link.href = url;
document.getElementsByTagName("head")[0].appendChild(link);
}
}
});

! means that css plugin will be used to parse sample.css.
Syntax is <plugin-name>!<file-path>.
css.js file contains css plugin's code.
css/sample.css is file, that should be loaded using that plugin.
See https://github.com/millermedeiros/requirejs-plugins

By default requirejs has support for downloading and loading javascript files only. Any other file which need to be downloaded and parsed accordingly is done by means of plugins. These plugins are separate javascript files which know how to download and parse the respected file.
To tell requirejs that any particular file need to be handled by separate plugin and not default loader. It's plugin is appended with ! between plugin name and file path.

Related

change requireJS from adding the .js file extension automatically on intern.js

Currently I am working in custom html reporter for intern.js. The Templating engine that i am using is marko.js.
marko.js have extension file with ".marko" for me to input my html syntax
The file is generated correctly in normal node.js (common.js)
The issue occurred when i integrate the same code to intern.js. The requirejs(AMD) that use by internjs is adding the .js file extension automatically to my marko extension when i do
var template = require('./hello-world.marko');
which make the file become hello-world.marko.js and this caused the code broke in markojs
the custom html reporter code is below
define(function (require) {
// require('intern/dojo/node!marko/node-require').install();
var fs = require('intern/dojo/node!fs');
var template = require('./hello-world.marko');
console.log(template);
function JsonReporter(config) {
config = config || {};
this.output = config.output;
}
JsonReporter.prototype = {
runEnd(executor) {
// console.log("toJson: " + JSON.stringify(executor.suites))
data = JSON.stringify(executor.suites);
template.renderToString(data,
function (err, output) {
console.log(output);
fs.writeFile('result.html', output, function (err) {
if (err) return console.log(err);
console.log('Save done');
});
});
},
}
return JsonReporter;
})
The require function isn't really meant for loading arbitrary text resources in either Node's loader or an AMD loader. In Node, whether you're running Intern or not, you can use fs.readFile or fs.readFileSync. In Intern's Dojo-based AMD environment you can also use the dojo/text loader plugin, like this:
var template = require('dojo/text!./hello-world.marko');

requirejs callback undefined

Project Structure
root
wwwroot <-- files under this location are static files public to the site
css
lib
bootstrap/js/bootstrap.js
jquery/js/jquery.js
knockout/knockout.js
requires/require.js
scripts
modules ┌───────────────┐
global.js <--│ Built modules │
dropdown.js └───────────────┘
modules
global.js ┌────────────────┐
dropdown <--│ Source modules │
dropdown.js └────────────────┘
gruntfile.js
global.cs Contents (pre-built version at ~/modules/global.js)
require.config({
baseUrl: "scripts/modules",
paths: {
jquery: "../../lib/jquery/js/jquery",
bootstrap: "../../lib/bootstrap/js/bootstrap",
knockout: "../../lib/knockout/knockout"
},
shims: {
bootstrap: {
deps: ['jquery']
}
},
});
define(function (require) {
var $ = require('jquery');
var ko = require('knockout');
var bootstrap = require('bootstrap');
});
dropdown.js Contents (pre-built version at ~/modules/dropdown.js)
define(function () {
console.log('dropdown initialized');
return 'foo';
});
HTML Page
Contains this script tag in the <head> of the page for loading requires config:
<script src="~/lib/requirejs/require.js" data-main="scripts/modules/global"></script>
In the body of the HTML page, I have the following:
<script>
require(['global'], function () {
require(['dropdown'], function (dropdown) {
console.log(dropdown);
});
});
</script>
Issue
The dropdown callback is undefined instead of the expected "foo" string that I'm returning from the defined module.
In fact, the console does not contain a log item for "dropdown initialized" either. This makes me believe the module is not being invoked somehow? However, it's strange the dropdown.js is present in F12 debugger as a script loaded into the page. Therefore, requires did make a call to load it, but did not run the contents of the define?
Noteworthy mentions
I'm using r.js to optimize and build. Both global.js and dropdown.js are processed over.
The name assigned to the dropdown module by r.js processing is "modules/dropdown/dropdown.js". I'm unsure if I should be using this somehow, or if I'm referring to the module correctly as just dropdown and relying on my baseUrl config having the correct path.
Edit #1
I have added the r.js build configuration used with grunt per commenter request. In conjunction, I updated the file structure to include the overall project structure, instead of just the runtime public wwwroot structure.
The r.js process will compile built forms of global.js + other modules in ~/wwwroot/scripts/modules from the source location ~/modules in summary.
function getRequireJsConfiguration() {
var baseUrl = './';
var paths = {
jquery: "wwwroot/lib/jquery/js/jquery",
bootstrap: "wwwroot/lib/bootstrap/js/bootstrap",
knockout: "wwwroot/lib/knockout/knockout"
};
var shims = {
bootstrap: {
deps: ['jquery']
}
};
var optimize = 'none';
var configuration = {};
var jsFilePaths = grunt.file.expand('modules/**/*.js');
jsFilePaths.forEach(function (jsFilePath) {
var fileName = jsFilePath.split('/').pop();
if (configuration[fileName]) {
throw 'Duplicate module name conflict: ' + fileName;
}
configuration[fileName] = {
options: {
baseUrl: './',
name: jsFilePath,
out: 'wwwroot/scripts/modules/' + fileName,
paths: paths,
shims: shims,
optimize: optimize,
exclude: ['jquery', 'knockout', 'bootstrap']
}
};
});
configuration['global'] = {
options: {
baseUrl: './',
name: 'modules/global.js',
out: 'wwwroot/scripts/modules/global.js',
paths: paths,
shims: shims,
optimize: optimize,
}
};
return configuration;
}
Edit #2
Thought it'd be a good idea to include the versions of requirejs packages I'm using:
requirejs: 2.1.15
grunt-contrib-requirejs: 0.4.4
Thanks.
The name assigned to the dropdown module by r.js processing is "modules/dropdown/dropdown.js". I'm unsure if I should be using this somehow, or if I'm referring to the module correctly as just dropdown and relying on my baseUrl config having the correct path.
In a sense, yes, you should be using that full path. That's what Require refers to as the module id - "modules/dropdown/dropdown" (if the .js in the above output was real, I suggest stripping that extension in the "name" config. .js is assumed by RequireJS, you don't want that string in your module ids). The basePath is used, when given IDs, to transform some unknown ID to a file path (e.g. 'bootstrap' id -> (applying path config) -> '../../lib/bootstrap/js/bootstrap' -> (applying base URL) -> 'scripts/modules/../../lib/bootstrap/js/bootstrap').
Really, though, just allowing r.js to concatenate everything into one file
is the preferred way to go. You could use the include option to include modules un-referenced by global.js in with the optimized bundle, too ( https://github.com/jrburke/r.js/blob/master/build/example.build.js#L438 )
As to your specific problem: your lazy require(['dropdown']) call is misleading you. By combining the requested module id with the basePath, RequireJS comes up with the URL you want - scripts/modules/dropdown - which defines a module with the module id scripts/module/dropdown - but since you requested the module id dropdown, you get nothing. (I would've guessed you'd get a RuntimeError instead of undefined, but I suppose that's how things go). One way or another you need to address the id/path mismatches.
Although I have resolved my issue with the hints wyantb's answer provided, I've since changed my approach to a single file concat due to the simplicity it brings. I still wanted to post the specifics of how I solved this question's issue for anyone else to happens along it.
In the grunt build configuration options, I added the onBuildWrite field to transform the content, so my assigned module IDs lined up with how I was lazily loading them.
onBuildWrite: function (moduleName, path, contents) {
return contents.replace(/modules\/global.js/, 'global');
}
This code is specifically for the global.js file. I implemented a similar onBuildWrite for the other module files (in the foreach loop). The transformation will essentially strip the path and extension from the module name that r.js assigns.
Here are some examples of before and after:
Before After
/modules/global.js global
/modules/dropdown/dropdown.js dropdown
/modules/loginButton/loginButton.js loginButton
Therefore, when I load the modules using the HTML script from my original question, requirejs resolves and finds a match.
Either require by path or define global and dropdown in global.cs
require(['./global'], function () {
require(['./dropdown'], function (dropdown) {
console.log(dropdown);
});
});

fs.readFile of a module, how do I know where it is?

I need the jquery source in my npm module that I built.
I originally did this:
fs.readFile("./node_modules/jrender/node_modules/jquery/dist/jquery.js", "utf-8", function(err, src){
});
However this doesn't work if you already installed jquery in your main project, it wont download and install it to this path.
How can I fix this?
Either I check if this file exists in either place, then use the one that exists.
Include a fixed version of jquery in the module
Does require() allow you to view the source of the included javascript file
You can find the location of the jquery file by looking in module.children
var s = require("jquery");
var jqfile = null;
for (var i = 0;i < module.children.length;i++) {
if (module.children[i].filename.match(/jquery.js$/))
jqfile = module.children[i].filename
}
fs.readFile(jqfile, "utf-8", function(err, src){
});

jQuery file upload and RequireJS configuration

I'm trying to use jQuery file upload, but I'm getting stuck with the RequireJS configuration. We install our dependencies in a /ext/ folder, e.g:
/src
/ext
/jquery-file-upload
In my main.js I use the following config:
require.config({
paths: {
"ext/jquery-file-upload": "../ext/jquery-file-upload/js/jquery.fileupload"
}
});
require([
"ext/jquery-file-upload"
]);
But then RequireJS tries to load jquery.ui.widget.js from the root instead of as a relative file. It is located in the jquery-file-upload directory..
Does anyone know what I'm doing wrong, or does anyone know of a working RequireJS config for jQuery file upload?
Thanks,
Martijn
If you look at the jquery.fileupload.js file, at the top it declares its own dependencies
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
define([
'jquery',
'jquery.ui.widget'
], factory);
You need to edit your require.config path for the jquery.ui.widget item.
require.config({
paths: {
'jquery.ui.widget': 'your_path_here/jquery.ui.widget'
}
});
If I don't mistake, your problem is that your plugin - jquery-file-upload - tries to load its dependencies by itself.
The problem is that filepaths in JS are relative to the page loading the script file, not to the file itself (Relative Paths in Javascript in an external file). This explains why your file seems to be loaded relatively to the root and not the given path.
In this case, you probably will have to manipulate a bit of the plugin code and take a look at the explanations given here concerning requireJS and dependencies loading:
How do I use requireJS and jQuery together? .
Try mapping jquery.widget.ui to the correct path...
require.config({
paths: {
"ext/jquery-file-upload": "../ext/jquery-file-upload/js/jquery.fileupload"
"jquery.ui.widget": "../ext/jquery-file-upload/js/vendor/jquery.ui.widget"
}
});
require([
"ext/jquery-file-upload"
]);
For anyone else having this problem...this is the config that worked for us.Hope it helps someone
The paths declaration
paths: {
'jquery.ui.widget': '../../Scripts/FileUpload/jqueryui/jquery.ui.widget',
'jquery_iframe_transport': '../../Scripts/FileUpload/jquery.iframe-transport',
'jquery.fileupload': '../../Scripts/FileUpload/jquery.fileupload'
}
The Define statement
define(['jquery.ui.widget','jquery_iframe_transport','jquery.fileupload'])
The above is dependent on jquery being loaded. We are using Durandal hence dont need a shim but you will need to ensure jquery is loaded before anything else
The initialisation in code
function uploadFile() {
var url = '/Backload/UploadHandler';
$('#fileupload').fileupload({
url: url,
dataType: 'json',
done: function (e, data) {
$.each(data.result.files, function (index, file) {
$('<p/>').text(file.name).appendTo('#files');
});
},
progressall: function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('#progress .bar').css(
'width',
progress + '%'
);
}
});
}
This is the basic upload example..

requiring optional javascript files with requirejs (e.g. require a locale specific file)

A few of the jquery plugins we rely on offer the ability to include locale/culture specific files to make non-en-us users feel more at home with their functionality (for example, jquery-globalize and bootstrap-datapicker).
The old school way of achieving this was as follows (where 'en-AU' is determined on the fly, sometimes resulting in a 404 for missing cultures):
<script type="text/javascript" src="/js/globalize/globalize.js"></script>
<script type="text/javascript" src="/js/globalize/cultures/globalize.culture.en-AU.js"></script>
Is there a recommended way of achieving this with requirejs (note that globalize is included as a shim)?
Here's my first attempt, not yet sure how the requirejs optomizer will handle it...
Globalize = require("globalize");
...
locale = module.config().locale;
if (locale != null) {
require(["globalize/globalize.culture." + locale], function() {
logger.debug("Loaded locale '" + locale + "'");
Globalize.culture(locale);
}, function() {
logger.debug("Unable to load locale '" + locale + "'");
});
}
edit: the optimizer handles it fine but but the solution doesn't really work because the culture file is loaded asynchronously it's possible that the app has used Globalize before the culture is set.
Kendo does something similar in their code.
This is a slight modification of their technique. This particular style allows the modules to load either through require or direct script inclusion.
I modified it slightly to set up the prereqs. On the downside, this code will no longer work through the r.js optimizer.
var myLocalPrereqs = ['file_english.min'];
("function" == typeof define && define.amd ? define : function (preReqs, func) {
return func()
})(myLocalPrereqs, function () {
(function () {
// Your module code goes here...
})()
});

Resources