While analyzing the performance of a JSF 2.1 + PrimeFaces 4.0 webapp with Google PageSpeed, it recommends among others to defer parsing of JavaScript files. On a test page with a <p:layout> and a form with <p:watermark> and <p:fileUpload> which looks like follows ...
<p:layout>
<p:layoutUnit position="west" size="100">Test</p:layoutUnit>
<p:layoutUnit position="center">
<h:form enctype="multipart/form-data">
<p:inputText id="input" />
<p:watermark for="input" value="watermark" />
<p:focus for="input" />
<p:fileUpload/>
<p:commandButton value="submit" />
</h:form>
</p:layoutUnit>
</p:layout>
... it lists the following JavaScript files which could be deferred:
primefaces.js (219.5KiB)
jquery-plugins.js (191.8KiB)
jquery.js (95.3KiB)
layout.js (76.4KiB)
fileupload.js (23.8KiB)
watermark.js (4.7KiB)
It links to this Google Developers article wherein deferred loading is explained as well as how to achieve it. You basically need to dynamically create the desired <script> during the onload event of the window. At its simplest form whereby old and buggy browsers are completely ignored, it looks like this:
<script>
window.addEventListener("load", function() {
var script = document.createElement("script");
script.src = "filename.js";
document.head.appendChild(script);
}, false);
</script>
Okay, this is doable if you have control over those scripts, but the listed scripts are all forcibly auto-included by JSF. Also, PrimeFaces renders a bunch of inline scripts to HTML output which are directly calling $(xxx) from jquery.js and PrimeFaces.xxx() from primefaces.js. This would mean that it would not easily be possible to really defer them to onload event as you would only end up with errors like $ is undefined and PrimeFaces is undefined.
But, it should be technically possible. Given that only jQuery doesn't need to be deferred as many of the site's custom scripts also rely on it, how could I block JSF from forcibly auto-including the PrimeFaces scripts so that I can defer them, and how could I deal with those inline PrimeFaces.xxx() calls?
Use <o:deferredScript>
Yes, it is possible with the <o:deferredScript> component which is new since OmniFaces 1.8.1. For the technically interested, here's the involved source code:
The UI component: DeferredScript
The HTML renderer: DeferredScriptRenderer
The JS helper: deferred.unminified.js
Basically, the component will during the postAddToView event (thus, during the view build time) via UIViewRoot#addComponentResource() add itself as a new script resource in end of <body> and via Hacks#setScriptResourceRendered() notify JSF that the script resource is already rendered (using Hacks class as there's no standard JSF API approach for that (yet?)), so that JSF won't forcibly auto-include/render the script resource anymore. In case of Mojarra and PrimeFaces, a context attribute with key of name+library and a value of true has to be set in order to disable auto-inclusion of the resource.
The renderer will write a <script> element with OmniFaces.DeferredScript.add() whereby the JSF-generated resource URL is passed. This JS helper will in turn collect the resource URLs and dynamically create new <script> elements for each of them during the onload event.
The usage is fairly simple, just use <o:deferredScript> the same way as <h:outputScript>, with a library and name. It doesn't matter where you place the component, but most self-documenting would be in the end of the <h:head> like this:
<h:head>
...
<o:deferredScript library="libraryname" name="resourcename.js" />
</h:head>
You can have multiple of them and they will ultimately be loaded in the same order as they're declared.
How to use <o:deferredScript> with PrimeFaces?
This is a little tricky, indeed because of all those inline scripts generated by PrimeFaces, but still doable with a helper script and accepting that jquery.js won't be deferred (it can however be served via a CDN, see later). In order to cover those inline PrimeFaces.xxx() calls to primefaces.js file which is almost 220KiB large, a helper script needs to be created which is less than 0.5KiB minified:
DeferredPrimeFaces = function() {
var deferredPrimeFaces = {};
var calls = [];
var settings = {};
var primeFacesLoaded = !!window.PrimeFaces;
function defer(name, args) {
calls.push({ name: name, args: args });
}
deferredPrimeFaces.begin = function() {
if (!primeFacesLoaded) {
settings = window.PrimeFaces.settings;
delete window.PrimeFaces;
}
};
deferredPrimeFaces.apply = function() {
if (window.PrimeFaces) {
for (var i = 0; i < calls.length; i++) {
window.PrimeFaces[calls[i].name].apply(window.PrimeFaces, calls[i].args);
}
window.PrimeFaces.settings = settings;
}
delete window.DeferredPrimeFaces;
};
if (!primeFacesLoaded) {
window.PrimeFaces = {
ab: function() { defer("ab", arguments); },
cw: function() { defer("cw", arguments); },
focus: function() { defer("focus", arguments); },
settings: {}
};
}
return deferredPrimeFaces;
}();
Save it as /resources/yourapp/scripts/primefaces.deferred.js. Basically, all what it does is capturing the PrimeFaces.ab(), cw() and focus() calls (as you can find in the bottom of the script) and deferring them to the DeferredPrimeFaces.apply() call (as you can find halfway the script). Note that there are possibly more PrimeFaces.xxx() functions which need to be deferred, if that is the case in your app, then you can add them yourself inside window.PrimeFaces = {} (no, it's in JavaScript not possible to have a "catch-all" method to cover the undetermined functions).
Before using this script and <o:deferredScript>, we first need to determine the auto-included scripts in the generated HTML output. For the test page as shown in the question, the following scripts are auto-included in generated HTML <head> (you can find this by rightclicking the page in webbrowser and choosing View Source):
<script type="text/javascript" src="/playground/javax.faces.resource/jquery/jquery.js.xhtml?ln=primefaces&v=4.0"></script>
<script type="text/javascript" src="/playground/javax.faces.resource/jquery/jquery-plugins.js.xhtml?ln=primefaces&v=4.0"></script>
<script type="text/javascript" src="/playground/javax.faces.resource/primefaces.js.xhtml?ln=primefaces&v=4.0"></script>
<script type="text/javascript" src="/playground/javax.faces.resource/layout/layout.js.xhtml?ln=primefaces&v=4.0"></script>
<script type="text/javascript" src="/playground/javax.faces.resource/watermark/watermark.js.xhtml?ln=primefaces&v=4.0"></script>
<script type="text/javascript" src="/playground/javax.faces.resource/fileupload/fileupload.js.xhtml?ln=primefaces&v=4.0"></script>
You need to skip the jquery.js file and create <o:deferredScripts> in exactly the same order for the remaining scripts. The resource name is the part after /javax.faces.resource/ excluding the JSF mapping (.xhtml in my case). The library name is represented by ln request parameter.
Thus, this should do:
<h:head>
...
<h:outputScript library="yourapp" name="scripts/primefaces.deferred.js" target="head" />
<o:deferredScript library="primefaces" name="jquery/jquery-plugins.js" />
<o:deferredScript library="primefaces" name="primefaces.js" onbegin="DeferredPrimeFaces.begin()" />
<o:deferredScript library="primefaces" name="layout/layout.js" />
<o:deferredScript library="primefaces" name="watermark/watermark.js" />
<o:deferredScript library="primefaces" name="fileupload/fileupload.js" onsuccess="DeferredPrimeFaces.apply()" />
</h:head>
Now all those scripts with a total size of about 516KiB are deferred to onload event. Note that DeferredPrimeFaces.begin() must be called in onbegin of <o:deferredScript name="primefaces.js"> and that DeferredPrimeFaces.apply() must be called in onsuccess of the last <o:deferredScript library="primefaces">.
In case you're using PrimeFaces 6.0 or newer, where the primefaces.js has been replaced by core.js and components.js, use the below instead:
<h:head>
...
<h:outputScript library="yourapp" name="scripts/primefaces.deferred.js" target="head" />
<o:deferredScript library="primefaces" name="jquery/jquery-plugins.js" />
<o:deferredScript library="primefaces" name="core.js" onbegin="DeferredPrimeFaces.begin()" />
<o:deferredScript library="primefaces" name="components.js" />
<o:deferredScript library="primefaces" name="layout/layout.js" />
<o:deferredScript library="primefaces" name="watermark/watermark.js" />
<o:deferredScript library="primefaces" name="fileupload/fileupload.js" onsuccess="DeferredPrimeFaces.apply()" />
</h:head>
As to performance improvement, important measuring point is the DOMContentLoaded time as you can find in bottom of Network tab of Chrome's developer tools. With the test page as shown in the question served by Tomcat on a 3 year old laptop, it decreased from ~500ms to ~270ms. This is relatively huge (almost the half!) and makes the most difference on mobiles/tablets as they render HTML relatively slow and touch events are fully blocked until the DOM content is loaded.
Noted should be that you're in case of (custom) component libraries dependent on whether they obey the JSF resource management rules/guidelines or not. RichFaces for example didn't and homebrewed another custom layer over it, making it impossible to use <o:deferredScript> on it. See also what is the resource library and how should it be used?
Warning: if you're adding new PrimeFaces components on the same view afterwards and are facing JavaScript undefined errors, then the chance is big that the new component also comes with its own JS file which should also be deferred, because it's depending on primefaces.js. A quick way to figure the right script would be to check the generated HTML <head> for the new script and then add another <o:deferredScript> for it based on the above instructions.
Bonus: CombinedResourceHandler recognizes <o:deferredScript>
If you happen to use OmniFaces CombinedResourceHandler, then it's good to know that it transparently recognizes <o:deferredScript> and combines all deferred scripts with the same group attribute into a single deferred resource. E.g. this ...
<o:deferredScript group="essential" ... />
<o:deferredScript group="essential" ... />
<o:deferredScript group="essential" ... />
...
<o:deferredScript group="non-essential" ... />
<o:deferredScript group="non-essential" ... />
... will end up in two combined deferred scripts which are loaded synchronously after each other. Note: the group attribute is optional. If you don't have any, then they will just all be combined into a single deferred resource.
As a live example, check the bottom of <body> of the ZEEF site. All essential PrimeFaces-related scripts and some site-specific scripts are combined in the first deferred script and all non-essential social media related scripts are combined in the second deferred script. As to performance improvement of ZEEF, on a test JBoss EAP server on modern hardware, the time to DOMContentLoaded went from ~3s to ~1s.
Bonus #2: delegate PrimeFaces jQuery to CDN
In any case, if you're already using OmniFaces, then you can always use CDNResourceHandler to delegate the PrimeFaces jQuery resource to a true CDN by the following context param in web.xml:
<context-param>
<param-name>org.omnifaces.CDN_RESOURCE_HANDLER_URLS</param-name>
<param-value>primefaces:jquery/jquery.js=http://code.jquery.com/jquery-1.11.0.min.js</param-value>
</context-param>
Note that jQuery 1.11 has some major performance improvements over 1.10 as internally used by PrimeFaces 4.0 and that it's fully backwards compatible. It saved a couple of hundred milliseconds when initializing drag'n'drop on ZEEF.
Initially posted as an answer to Defer primefaces.js loading
Adding another solution to this question for anyone else that encounters the same.
You will need to customize the primefaces HeadRenderer to achieve the ordering pagespeed recommends. While this is something that could have been implemented by PrimeFaces, I do not see it in v5.2.RC2. These are the lines in encodeBegin that need change:
96 //Registered Resources
97 UIViewRoot viewRoot = context.getViewRoot();
98 for (UIComponent resource : viewRoot.getComponentResources(context, "head")) {
99 resource.encodeAll(context);
100 }
Simply write a custom component for the head tag, then bind it to a renderer that overrides above behavior.
Now you wouldn't want to duplicate the entire method just for this change, it may be cleaner to add a facet called "last" and move script resources to its beginning in your renderer as new deferredScript components. Let me know if there's interest, and I'll create a fork to demonstrate how.
This approach is "future proof" in the sense that it doesn't break as new resource dependencies are added to components, or as new components are added to the view.
Related
According to the docs, all I need to do is to wrap the block I'd like to "talk to" via Javascript with this:
<amp-script layout="container" src="language-toggle.js">
// Some basic HTML
</amp-script>
The Javascript file is there, I tested with a simple console.log. Yet the amp-script tag has opacity: 0.7 (AMP default style). Apparently, it needs the class i-amphtml-hydrated to be fully visible. I've been trying to wrap my head around this for a few hours now, even Google could not help me with this.
There are a bunch of ServiceWorker errors in the console, which are also all generated by AMP. I have no idea why they appear or how to get rid of them. This whole AMP thing is a mess for me.
These are the AMP scripts I currently added:
<script async src="https://cdn.ampproject.org/v0.js"></script>
<script async custom-element="amp-script" src="https://cdn.ampproject.org/v0/amp-script-0.1.js"></script>
<script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>
<script async custom-element="amp-youtube" src="https://cdn.ampproject.org/v0/amp-youtube-0.1.js"></script>
Carousel and YouTube are working fine.
Could anybody please shed some light onto this?
I highly recommend to enable AMP development mode by adding #development=1 to the URL.
Relative URL's are not allowed in the src attribute of the amp-script tag (the development parameter would have told you that).
You can have something like this though:
<amp-script width="1" height="1" script="demo"></amp-script>
<script type="text/plain" target="amp-script" id="demo">
console.log('Foobar');
</script>
But you will need a matching hash in a meta tag in your head:
<head>
...
<meta
name="amp-script-src"
content="sha384-hash"
/>
</head>
Again, the development parameter will tell you the hash you should use, although you could also disable hash checks during development.
All of the above will still not hydrate your amp-script element. In order for your element to be hydrated, the script has to actually to something to the DOM, like for example adding a div on a button click:
<amp-script layout="container" script="demo">
<button id="hello">Add headline</button>
</amp-script>
<script type="text/plain" target="amp-script" id="demo">
console.log('Foobar');
const button = document.getElementById('hello');
button.addEventListener('click', () => {
const h1 = document.createElement('h1');
h1.textContent = 'Hello World!';
document.body.appendChild(h1);
});
</script>
Be aware that you are quite limited with what you are allowed to do. For example, the above snippet will not work without the event listener, so you can not simply add an element without user interaction.
The messages regarding the references can safely be ignored - the AMP examples do exaclty the same, the AMP still passes the validation.
I have been digging in the this site and others for several days and the answer to my problem still escapes me.
I have read all of these pages:
http://pastebin.com/cbagkw8h
but none of them exactly answers this question:
I am trying to get a Rally Dashboard (custom board) to appear in HTML/Javascript in a confluence wiki. I have gotten a simple Standard Report working using a read-only account and AppSDK1.32 with loginKey by embedding the following HTML/Javascript into the Confluence wiki page:
{html}
<meta name="Name" content="App Example: Rally Application" />
<meta name="Version" content="2011.04" />
<meta name="Vendor" content="Rally Software" />
<script type="text/javascript"
src="https://rally1.rallydev.com/apps/1.32/sdk.js?loginKey=loginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkey">
</script>
<script type="text/javascript">
function onLoad() {
var rallyDataSource = new rally.sdk.data.RallyDataSource(
'__WORKSPACE_OID__',
'__PROJECT_OID__',
'__PROJECT_SCOPING_UP__',
'__PROJECT_SCOPING_DOWN__');
rally.sdk.ui.AppHeader.destroy();
var reportConfig = {report: rally.sdk.ui.StandardReport.IterationBurndown,
width : 400, height: 300};
var report = new rally.sdk.ui.StandardReport(reportConfig);
report.display("reportDiv");
}
rally.addOnLoad(onLoad);
</script>
<div id="reportDiv" style="width: 400px; margin-left:20px"></div>
<br/>
{html}
I am trying to expand this success to an entire dashboard with App SDK2.x using the new apiKey - by using the following code:
{html}
<meta name="Name" content="App Example: Rally Application" />
<meta name="Version" content="2015.04" />
<meta name="Vendor" content="eBay Enterprise" />
<script type="text/javascript"
src="https://loginapirally1.rallydev.com/apps/1.32/sdk.js?loginKey=loginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkeyloginkey">
</script>
<script type="text/javascript">
function onLoad() {
rally.sdk.ui.AppHeader.destroy();
document.getElementById("iframeA").width = screen.width - 60 ;
document.getElementById("iframeA").height = (screen.width - 60 ) * 3;
}
rally.addOnLoad(onLoad);
</script>
<iframe id="iframeA" src="https://loginapirally1.rallydev.com/#/111111111d/custom/222222222?expandApp=333333333&apiKey=_apikeyapikeyapikeyapikeyapikeyapikeyapikey" width="1024" height="1024">
</iframe>
<br/>
{html}
I am noticing a few things:
1) it almost works - I get the dashboard/report title but not the cards
2) the apiKey seems to have no affect at all - I still get prompted for a login and password (which I could stand if I could see the cards).
3) it doesn't seem to matter if I put the apiKey before or after the hash symbol
Citation A suggested using the "full screen" dashboard/report but didn't cover the apiKey.
Citaton B says that the AppSDK2 uses the apiKey as of Apr 14 2014 but doesn't say how to use it exactly with AppSDK2.
I have gotten the apiKey to work with the Ruby API but it is unclear how to access the dashboard/reports from there.
Citation C says that the AppSDK1 is based on the Javascript dojo framework and the AppSDK2 is based on the Javascript Sencha's ExtJS but avoids giving any kind of rosetta stone from one to the other.
The only other options I can think of is to 1) copy the entire HTML page-source from the "Custom Board" and then start debugging the Javascript with ExtJS (but I cannot find an example of where to put the apiKey for ExtJS) or 2) bypass all of the APIs and use Ruby Watir-Webdriver (which uses
Selenium) and VNCServer to clip an image of the "Custom Board" page and show THAT in confluence.
Citations: http://pastebin.com/YMUEPjSF
The issue seems to be specific to the canned Custom Board that cannot be loaded externally. It should work if you write a js source code to build a similar Board and compile that into a deployment html. That is similar to option (1) you mentioned in the end of your post if I understand it correctly.
Here is my test where I compared Custom Board and Custom HTML side by side.
Below is a screenshot from Rally. This custom dashboard has Custom Board on the left and Custom HTML on the right. The Custom HTML is using a code example of filterable board from AppSDK2 documentation.
Next I use this code:
<html>
<head>
<title>Custom Grid</title>
<meta name="Name" content="App: Custom Dashboard"/>
<meta name="Version" content="2011.08.31"/>
<meta name="Vendor" content="Rally Labs, NickM"/>
<script type="text/javascript" src="https://rally1.rallydev.com/apps/1.32/sdk.js?loginKey=c33e83...."></script>
<script type="text/javascript">
rally.addOnLoad(function() {
var iframe = document.createElement("iframe");
iframe.src = "https://loginapirally1.rallydev.com/#/14018981229/custom/34207853894"
iframe.width = 2000;
iframe.height = 1000;
document.getElementById("storyboard").appendChild(iframe);
});
</script>
</head>
<body>
<div id="storyboard"></div>
</body>
</html>
Here is the dashboard loaded externally on localhost:3000. The left column of the dashboard where Custom Board is expected to load is empty, but the right column with a custom html code of a board loads successfully:
It looks like the canned Custom Board cannot be loaded externally but a custom html code written in AppSDK2 can be displayed externally.
A couple of observations:
There is really no upgrade path from AppSDK1 to AppSDK2. The underlying frameworks and the class structures are very different and the code cannot be simply refactored. There is no translation from one to the other.
LoginKey is intended to work with AppSDK1. Both are legacy. Both predate AppSDK2 and ApiKey. To use ApiKey with custom html apps written with AppSDK2 see "Use API Key with AppSDK2" article.
AppSDK2 does not support LoginKey usage for authentication. The reason it seems to work in this example is that we load the entire page. Loading the entire page using iframe's src property is possible with LoginKey. In this example there is no reason to use ApiKey and LoginKey together. You are right that ApiKey makes no difference in this use case.
The way LoginKey works is that it "tricks" the browser into thinking that there is this different server, loginapirally1.rallydev.com. If you look in Network tab of your browser and see that request comes from there it means that LoginKey is working. ApiKey works differently. There is no equivalent to loginapirally1 server with ApiKey.
If you are being prompted to supply login credentials when using LoginKey it means that LoginKey is not working. See "LoginKey Troublshooting" article.
Embedding custom AppSDK2 apps in 3rd party portals (running custom apps externally) is possible with ApiKey, and the supported scenario described in this guide is similar to the option (1) you mentioned in the end of your post. Loading entire Rally page or entire Rallynavigation is not a supported use case even though it is possible with LoginKey.
Using the Grails asset-pipeline plugin, I'm trying to figure out the best way to include assets (javascript) on a page versus having them compiled into the application.js file. Currently, this is what I'm doing...
At the bottom of my layout file:
<g:set var="workflow" value="${pageProperty(name: 'meta.workflow')}"/>
<asset:javascript src="application.js"/>
<g:if test="${workflow == 'storeAdmin'}">
<asset:javascript src="store/script.js"/>
</g:if>
In views/store/index.gsp header:
<meta name="workflow" content="storeAdmin" />
While this works, it feels like a hack. The reason I have to do it like this is because if I simply try and include the asset in the view itself, instead of the layout, it always gets rendered before the application.js, which means anything in that script that depends on global code will fail; code that requires jQuery for example.
I typically use a convention for naming page specific javascript assets that reflects the name of the controller and action. Using these and the <asset:assetPathExists> tag I can just add the following into my layout:
<asset:assetPathExists src="${params?.controller ?: 'home'}_${params?.action ?: 'index'}.js">
<asset:javascript src="${params?.controller ?: 'home'}_${params?.action ?: 'index'}.js" />
</asset:assetPathExists>
I have an issue with Javascript reloading due to Tiles.
Tiles-definition.xml
<tiles-definitions>
<definition name="template-main" template="/WEB-INF/jsp/home.jsp">
<put-attribute name="header-main-content" value="/WEB-INF/jsp/header_main.jsp"/>
<put-attribute name="header-quote-content" value="/WEB-INF/jsp/header_quote.jsp" />
<put-attribute name="menu-content" value="/WEB-INF/jsp/menu.jsp" />
<put-attribute name="body-content" value="/WEB-INF/jsp/slides.jsp" />
<put-attribute name="footer-content" value="/WEB-INF/jsp/footer.jsp" />
</definition>
<definition name="template-main-login" extends="template-main">
<put-attribute name="header-main-content" value="/WEB-INF/jsp/header_main.jsp" />
</definition>
</tiles-definitions>
home.jsp
<body style="background-color: #5F9EA0">
<head>
<script src="<c:url value="/resources/js/jquery-1.11.1.js" />"></script>
<script src="<c:url value="/resources/js/example.js" />"></script>
bla bla ..
example.js
$(document).ready(function() {
setTimeout(function () {
popUp('show');
}, 1000);
});
I am using Spring-MVC:
When the application is loaded I am returning the view as template-main. So the first template definition is called and the application is opened with a login popup as I am calling the popup on document load.
Problem:
Now when I give the login credentials and submit I am calling template-main-login which in turn is extending the template-main. Now the problem is, the Javascript which I have included in the home.jsp is loading again (may be since I am extending the template-main layout) such that I am getting the popup opened for the second time which I want to stop.
So please let me know how to stop the popup opening again.
i would suggest rather than making home.jsp as your template make a separate jsp only for your template and basetemplate will have generic things like loading external js and css files and keep specific js code in specific jsp
You need to ensure that your JS files have the proper cache control/expires headers (either set a long date or use ETags). If you use ETags, the static files will still query the server implementation to check if the file hash has changed or not. You can avoid that by using expires headers on all your static files so that the browser can cache them and load them from the local computing device as opposed to sending in a HTTP request to your server.
I want to use RequireJs in my project, but I found that I can't write the following code
<html>
<head>
</head>
<body>
<input type="button" />
<script>
// Use the jQuery
$(function() {
//some code
}
)
</script>
<input />
<input />
// I had added the jQuery in required shim and jQuery is working in RequireJs.
<script data-main="scripts/main" src="/scripts/require.js"></script>
</body>
</html>
There was an error $ is undefined, when the page was loaded.
I looked up a lot articles, but I can't solve it. How can I handle this? I don't want to move the sample js function to .js file.
As you wrote in your question:
All js functions need in .js file if I use the requirejs?
And with the definition of RequireJS:
RequireJS is a JavaScript file and module loader.
Using a modular script loader like RequireJS will improve the speed and quality of your code.
So doing such inserting inline <script> tags in your page is not a good idea.
However, in answer to your question, because RequireJS load the scripts asynchronously, so you don't know when jQuery will load, and you can not use inline scripts as old schools, you need to use define or require methods as George Reith wrote in the answer.
First things first $ means nothing in JavaScript but is used by the popular jQuery library. JavaScript !== jQuery.
Secondly assuming you have loaded jQuery via require.js you need to put your initial script tag after
<script data-main="scripts/main" src="/scripts/require.js"></script> as it is being called before require.js.
Thirdly require.js asynchronously loads files so you must wrap your code in the require() or define() tag with a list of dependancies so it only calls them once they have been loaded.
e.g.
<html>
<head>
<script data-main="scripts/main" src="/scripts/require.js"></script>
</head>
<body>
<input type="button" />
<script>
/*
RequireJS is asynchronous so you must wrap your code
in "require(["jQuery"], ...)" so it only calls it once
jQuery has been loaded. Each included script is available
to you as a parameter in the callback function.
*/
require(["jQuery"], function($) {
$(function() {
});
});
</script>
<input />
<input />
</body>
</html>
Your settings should look like this:
requirejs.config({
paths: {
'jQuery': 'path/to/jquery'
},
shim: {
'jQuery': {
exports: '$'
}
}
});
You also have to include jQuery. There is a whole manual page devoted to this on requirejs.org which should help you out.
Maybe what you want is also explained here. Taken from there:
require(["helper/util"], function(util) {
//This function is called when scripts/helper/util.js is loaded.
//If util.js calls define(), then this function is not fired until
//util's dependencies have loaded, and the util argument will hold
//the module value for "helper/util".
});
Require.js doesn't even implement $. Why are you even wrapping you function in $(..)?
Try moving your sample script tag after the requirejs script tag. Currently your sample function is executed before requirejs gets a chance to load jQuery.