How to properly configure requireJS - javascript

Hi I'm trying to make starting template for SPA project mainly using:
RequireJS, KnockoutJS, TypeScript, etc.
I'm having hard time figuring out how to configure paths and folder structure for RequireJS to work properly...
here is my folder structure:
Scripts
app
components
main.js
lib
knockout.js
jquery.js
here is my RequireJS config file:
var config = {
waitSeconds: 15,
paths: {
app: '../app',
'knockout': '/lib/knockout-3.4.2.',
sammy: '/lib/sammy-0.7.5.',
jquery: '../scripts/lib/jquery-1.10.2.'
}
};
This is my attempt for main.js:
define(['jquery', 'PageOne', 'PageTwo'], function ($, pageOne, pageTwo) {
$(document).ready(function () {
var app = Sammy('#main', function () {
this.get('#/pageOne', function () {
pageOne.activate();
});
this.get('#/pageTwo', function () {
pageTwo.activate();
});
});
app.run();
});
});
Here is my Index.cshtml script tag:
<script src="~/Scripts/lib/require.js" data-main="scripts/app/components/main"></script>
I saw in different project that config is called in header so this is in html header:
<script src="~/Scripts/app/config/require.config.js"></script>
My problem is that in main.js it looks for jquery under path defined in data-main (scripts/app/components/), but my jquery is in scripts/lib folder.
I'm trying to figure out by reading online the whole day but it's too much time for me I need someone to give me some hints how is this supposed to work?
Seriously having hard time figuring this out and RequireJS website just isn't helping me atm.
Note: I am beginner in JavaScript based projects, first SPA attempt,
never used RequireJS...

Your configuration file does not do anything. I'm assuming from your description that the script element that loads it is located before the script element that loads RequireJS. That's one valid way to configure RequireJS, but if you want RequireJS to pick up the configuration, you need to set the global variable require before you load RequireJS, and RequireJS will use the value of require as its configuration. Right now you are setting config, which is ignored by RequireJS. So:
var require = {
waitSeconds: 15,
// etc...
And once the configuration is in effect, you should be able to reduce your data-main to data-main="components/main".
I see some of your paths in the paths configuration end with a dot. That's most likely a mistake on your part, or you have some very strange file names.

Related

Importing JS files outside Webpack

So, i have a script that creates a global object
(function() {
window.GlobalThing = {}
})();
This script will also fill this object attributes
if (!GlobalThing .Resource) { GlobalThing .Resource = require('./Resource'); }
Then, some other scripts that are not bundled with webpack need to use this GlobalThing. I`ve tryed to make it global using ProvidePlugin for example:
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery",
'GlobalThing': path.join(__dirname,"Path/GlobalThing.js")
})
],
I've tryed adding an Alias as well
resolve: {
alias: {
'GlobalThing': path.join(__dirname,"Path/GlobalThing.js")
}
}
I have tryed doing something like this in the end of my GlobalThing.js file as well:
(function(){
window.GlobalThing = GlobalThing;
})();
Then i had to import to run the script, so i got a random js file inside the webpack to test it:
import GlobalThing from "GlobalThing ";
Still, it seems some scripts cannot seethe GlobalThing. If i bundle everything up with webpack, it works, but i didnt want to as our app is very old and have some very old stuff. Is there a way i can expose GlobalThing to those older scripts ?
ProvidePlugin takes a module name (i.e. string) and internally uses require to load it. So that wont help you in loading your own script.
That said, following should work:
Keep the GlobalThing script out of webpack bundling
Make sure the script itself is copied to the output folder
Make sure the index.html (or whatever html page you are using) has the scripts in the order GlobalThingScript.js followed by webpack bundle.js
To give you more insight:
When webpack bundles the scripts other than GlobalThingScript.js, it doesnt even know there is something called GlobalThing. It just bundles the other files.
That would mean it is upto you to make sure the GlobalThingScript.js is also made it to the final output folder. Also, the html source should use <script> tags to include the GlobalThingScript.js before webpack bundle.js.
In case problem persists, please do edit the OP to include the html source.
Hope that helps.

Requirejs uses wrong path for asset in library

In a website I'm creating RequireJS is used as module loader. There is a "3d photo viewer" on this website and I'm using the Photo Sphere Viewer lib for these. One of the dependencies for this library is D.js. This is required in the library code as such:
... define(["three","D.js","uevent","doT"],b) ...
In my RequireJS configuration I defined a baseUrl and paths for the libs required by Photo Sphere Viewer libraries:
requirejs.config({
baseUrl: '/scripts',
paths: {
'vendor': 'lib/vendor',
'three': 'lib/vendor/three',
'uevent': 'lib/vendor/uEvent',
'doT': 'lib/vendor/dOT',
'D.js': 'lib/vendor/D'
}
});
photo-sphere-viewer is required by the website after a user requests to get a 3d photo. Code works a little like this:
requirejs(['main', 'deps', 'for', 'app'], function(a, b, c, d){
var showSphere = function(){
// loading logic and such
require('vendor/photos-sphere-viewer', function(PSV){
// do your 3d photo thing
});
};
var button = document.getElementById('button');
button.addEventListener('click', showSphere);
});
D.js is located at /scripts/lib/vendor/D.js. However when I test this, I get a 404 for /D.js. As if it is completely ignoring the baseUrl and path, but these aren't ignored for the other libraries, these get loaded normally.
I've added console.log(require.urlTo('D.js')) to the top of the Photo Sphere Viewer js file and somehow this logs the correct path: "/scripts/lib/vendor/D.js". However, one line further when D.js is actually required it seems to have 'changed its mind'. I've working on this for some time without result and I'm kinda considering just putting D.js in the website root, but of course that's not my preferred solution.
I think that the .js is throwing things off.
Change the config
requirejs.config({
baseUrl: '/scripts',
paths: {
'vendor': 'lib/vendor',
'three': 'lib/vendor/three',
'uevent': 'lib/vendor/uEvent',
'doT': 'lib/vendor/dOT',
'D_js': 'lib/vendor/D'
}
});
And call the define this way.
define(["three","D_js","uevent","doT"],b) ...
I suspect your problem is because of asynchronous loading of requireJs dependencies.
Since requireJs loads the dependencies asynchronously, the D.js file might not have been loaded yet when you are trying to use it.
If thats the problem, solution is to load the dependencies in a separate file before your require.js
<script type="text/javascript" src="/js/config.js"></script>
<script type="text/javascript" src="/js/require.js"></script>
See
Require JS is ignoring my config
and http://requirejs.org/docs/api.html#config

requirejs dependencies grouping

I am trying to integrate requirejs framework to my app.
Is possible to create a virtual module (which doesn't exists as a physically file), where i could group all the jquery-validation plugins together?
For example, i need to load 4 dependencies everytime i want to use jquery-validate.
Instead of requesting them, each time, i create a jquery-val "virtual module", which should request all the dependencies automatically.
However, trying to load "jquery-val" actually tries to load the file from disk (which i don't have).
What should be the best practice in solving this issue?
// config
requirejs.config({
baseUrl: '/Content',
paths: {
'jquery': 'frameworks/jquery-3.1.1.min',
"jquery-validate": "frameworks/jquery.validate.min",
"jquery-validate-unobtrusive": "frameworks/jquery.validate.unobtrusive.min",
"jquery-unobtrusive-ajax": "frameworks/jquery.unobtrusive-ajax.min"
},
shim: {
"jquery-val": ["jquery", "jquery-validate", "jquery-validate-unobtrusive", "jquery-unobtrusive-ajax"]
}
});
// Solution 1: working, but ugly
define(["jquery", "jquery-validate-unobtrusive", "jquery-unobtrusive-ajax"], function ($) {
// My Module
});
// Solution 2: not working
define(["jquery-val"], function () {
// My Module
});
// Solution 3: create jquery-val.js file, which loads the dependencies automatically
// jquery-val.js
(function (global) {
define(["jquery", "jquery-validate-unobtrusive", "jquery-unobtrusive-ajax"], function ($) {
});
}(this));
take some time and read:
http://requirejs.org/docs/api.html#modulenotes
One module per file.: Only one module should be defined per JavaScript file, given the nature of the module name-to-file-path lookup algorithm. You shoud only use the optimization tool to group multiple modules into optimized files.
Optimization Tool
To answer your question:
It is good practice to define one module per file, so you don't need to define explicit a name for the module AND do the need for inserting it somewhere to be available before the other modules are loaded.
So you could require just the file: require("../services/myGroupModule") and this file would hold your module and requireJS would take care of the loading dependencies (and later the optimizations for concatenating into one file!). Here the module name is the file name.
You could nevertheless do the following and loading it as a file module or like you tried to define it beforehand and give the module a name:
//Explicitly defines the "foo/title" module:
define("myGroupModule",
["dependency1", "dependency2"],
function(dependency1, dependency2) {
return function myGroupModule {
return {
doSomething: function () { console.log("hey"); }
}
}
}
);
Maybe you should also give a look at some new module loaders:
WebPack 2: https://webpack.js.org/
SystemJS: https://github.com/systemjs/systemjs

How can I use a local file during Require.js optimisation, but a CDN-hosted version at runtime?

My page includes several components that exist as separate AMD modules. Each of these components is turned into a single file by the Require.js optimiser. Because several of these components share dependencies (e.g. jQuery and d3), the optimiser paths config uses CDN URLs for those dependencies, rather than bundling them into the optimised file.
Here's where it gets tricky. I've written a module loader plugin for Ractive.js called rvc.js, which allows me to include Ractive components that are defined in HTML files. (Yes, I'm asking for help on how to use my own library.)
This works fine - code like this gets optimised as you'd expect:
define( function ( require ) {
var ChartView = require( 'rvc!views/Chart' );
var view = new ChartView({ el: 'chart' });
});
Because Ractive is used by several of the components, it should be served from a CDN like jQuery and d3. But it's used by rvc.js during the optimisation process, which means that the Ractive entry for the optimiser's paths config can't point to a CDN - it has to point to a local file.
Is there a way to tell Require.js 'use the local file during optimisation, but load from CDN at runtime'?
So here's the solution I eventually settled on. It feels somewhat kludgy, but it works:
Stub out the loaders and the library you don't want bundled
Add an onBuildWrite function that rewrites modules depending on the library, so that they think they're requiring something else entirely - in this case Ractive_RUNTIME
Add an entry to your runtime AMD config's paths object, so that Ractive_RUNTIME points to the CDN
My optimiser config now looks like this:
{
baseUrl: 'path/to/js/',
out: 'build/js/app.js',
name: 'app',
optimize: 'none',
paths: {
'amd-loader': 'loaders/amd-loader',
'rvc': 'loaders/rvc',
'Ractive': 'lib/Ractive'
},
stubModules: [ 'amd-loader', 'rvc', 'Ractive' ],
onBuildWrite: function ( name, path, contents ) {
if ( contents === "define('Ractive',{});" ) {
// this is the stub module, we can kill it
return '';
}
// otherwise all references to `Ractive` need replacing
return contents.replace( /['"]Ractive['"]/g, '"Ractive_RUNTIME"' );
}
}
Meanwhile, the script that loads the app.js file created by the optimiser has a config entry that points to the CDN:
require.config({
context: uniqueContext,
baseUrl: baseUrl,
paths: {
'amd-loader': 'loaders/amd-loader',
'rvc': 'loaders/rvc',
'Ractive': 'lib/Ractive',
'Ractive_RUNTIME': 'http://cdn.ractivejs.org/releases/0.3.9/Ractive.min'
}
});

requirejs: is there a way to set several places for search for 1 resource

I need to implement something very common to the view resolve algorithm in .net MVC but with requirejs - if the resource is not present in the folder search for it in the shared folder.
Do you know if that is possible with requirejs?
Certianly, you will have to include pathconfig fallbacks, taken directly from requirejs manual.
http://requirejs.org/docs/api.html#pathsfallbacks
requirejs.config({
//To get timely, correct error triggers in IE, force a define/shim exports check.
enforceDefine: true,
paths: {
jquery: [
'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min',
//If the CDN location fails, load from this location
'lib/jquery'
]
}
});
//Later
require(['jquery'], function ($) {
});

Categories

Resources