I am using requirejs. My main.js content is like following.
requirejs.config({
async: true,
parseOnLoad: true,
packages: [],
paths: {
jquery: 'https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min'
}
});
require(["login"], function (loginService) {
loginService.login('validUser');
});
Now, my config elements are little. But later, I will add packages, paths and others, so the require.config lines will increase.
I wanna separate require.config as a different file and use it?
If jquery load delays, does the error occurs? My other javascript files are using it.
Yes you can, require your config before you require anything else, like this:
config example:
require.config({
baseUrl: '/Public/js',
paths: {
jquery: '../../Scripts/jquery-1.10.2.min',
jqueryui: '../../Scripts/jquery-ui-1.10.2.min',
},
shim: {
jqueryui: {
deps: ['jquery']
},
}
waitSeconds: 3
});
and, then I load it:
require(['/Public/js/config.js'], function() {
require(['home/index'], function() {
});
});
Just remember that you reference the config.js by path in the first require-statement because require.js can not resolve by baseUrl since it has not been loaded. When you get to the inner require()-statement, its loaded and you can reference dependencies relative to baseUrl.
You can put the config into a separate JS file, that's not a problem. Just make sure that file is loaded prior to the require() call in your main code.
If you're using jQuery for other scripts that are not loaded via requireJS, you will get errors if they happen to load sooner than jQuery. What you need to do is convert all those static files into requireJS modules and load them all via requireJS. By using a define() function in each of the modules, you can set up dependencies, so all modules will wait for jQuery to load prior to executing their own code.
This is an example of a multipage requirejs based project where the requirejs.config call is in a separate file
https://github.com/requirejs/example-multipage/tree/master/www
Related
I want to use a simple jQuery function like so:
$( document ).ready(function(){
$('body').addClass("faded");
});
From a single view in a rails 5.1.3 app, in this case 'login.html.erb'
On webpack's application.js I have:
var $ = require('jquery');
which makes the aforementioned jquery call work IF I put it on the same application.js file but this would mean it would be called for all the pages since <%= javascript_pack_tag 'application' %> is on the layout.
When I try to run it on login.html.erb like so:
<script type="text/javascript">
$( document ).ready(function(){
$('body').addClass("faded");
});
</script>
I get an error on console: "ReferenceError: $ is not defined".
If I try to do " import $ from 'jquery'; " on the login.html.erb file I get this error instead: "SyntaxError: import declarations may only appear at top level of a module" which understandably means that my local .erb view doesn't get access to the javascript referenced on webpacker's application.js and cant import it from there.
How can I reference jquery and for that matter any module being served by webpacker, from the views?
I apologize if this has been asked before, I'm posting this question after days of reading about webpack, the webpacker gem and javascript without finding a solution.
:)
Install jQuery /bin/yarn add jquery
open config/webpack/shared.js, and add/overwrite with this code:
module: {
rules: sync(join(loadersDir, '*.js')).map(loader => require(loader)),
noParse: function(content) {
return /jquery/.test(content);
}
},
plugins: [
new webpack.EnvironmentPlugin(JSON.parse(JSON.stringify(env))),
new ExtractTextPlugin(env.NODE_ENV === 'production' ? '[name]-[hash].css' : '[name].css'),
new ManifestPlugin({
publicPath: output.publicPath,
writeToFileEmit: true
}),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": 'jquery',
}),
],
resolve: {
extensions: settings.extensions,
modules: [
resolve(settings.source_path),
'node_modules'
],
alias: {
jquery: 'jquery/dist/jquery.slim.js',
}
},
you might want full jQuery, instead jQuery slim
import jQuery global.$ = require('jquery') into any js file on app/javascripts/packs
Now you can use it
$(document).ready(function() {
//
});
First things first. You cannot transpile es6 in erb templates within script tags with webpacker.
Since introduction of assets pipeline in rails the general idea is to deliver bundles of multiple javascript files. Prior to webpacker by defining sprockets manifests and now with packs. This allows to save http requests for the js assets files. The browser loads only one file with all of the javascript on the first http request to the app and caches it for further page requests.
Thus you can define separate js files for the parts of your application and import the all in the application.js pack. Only pack files can be inlcuded via a javascript_include_tag. You must also import jquery in each imported es6 module, because es6 modules have their own variable scope. (just check the transpiled output in chrome dev tools)
However now, you can`t just call addClass on body, because you only want it to happen on the login page. One way to solve is setting a separate class (e.g ".login") within the erb template and use it as a selector.
//app/javascript/packs/application.js
import 'startpage'
import 'login'
//app/javascript/src/login/index.js
import $ from 'jquery'
$('.login .content').addClass("faded");
If faded really has to be added on the body (which is not in the template) you can either try select it via parent matcher from the ".login" class or somehow introduce a variable in the rails layout which is set from within an erb template, in order to add controller specific marker for the layout.
Ofc you can also deliver a separate js file per page, if you think that this does not produce to many http requests and the speed is good enough for your users. Just make them all separate packfiles within packs folder.
I had to move some scripts to synchronious load through bundle, and I want to set those scripts as already defined, so require.js would not ask server for them in next calls.
Let me explain:
I had some scripts that were required everywhere, e.g. i18n, and jquery. So I have hundreeds if calls all around the project such as
require(['jquery', 'i18n', 'commonjs', ...
I bundled 'jquery', 'i18n', 'commonjs' into one script core.js which now is inserted in layout <script src="/core.js"></script>
All functions from jquer, i18n now can be accesses globally, without need of requiring them. I want to specifically say to reuire.js that those scripts are already loaded, something wich bundles should do.
I've read article about using bundles and tryied to put
bundle in my config file
bundles: {
'core': ['jquery', 'i18n', 'commonjs']
}
but it doesnt work, there lots of mistakes fallen and as I understood th only way to use bundle is to use r.js which optimizes js and folders.
Actually, all I want is to set some scripts as already loaded for require.js. Is ther a dirty way to do it?
There's no configuration option to mark a script as already defined. What you can do is to call define yourself with a module name and an appropriate return value. For instance, if you load jQuery with a script element before you start loading any module through RequireJS, you can do:
define("jquery", [], function () {
return $;
});
The code above makes it so that whenever any module requires the module jquery, they get the value of $. I normally place such modules like the one just before my call to require.config. It's just a convenient place for them.
I am building a JavaScript module. Can load the first file in the module no problem. From there I want to load other files, but requirejs follows the path from the index. I want the functions in the module to be available in global scope. The structure is like this:
index.html:
<script src="scripts/app.js"></script>
app.js:
requirejs([ "../../modules/foo" ], function(util) {
});
modules/foo.js:
requirejs([ "bar" ], function(util) {
});
That gives the error: ERR_FILE_NOT_FOUND, well, yes, if you look from app.js you will not find it. How to force requirejs to load from the module?
These posts are probably related, but I can't wrap my head around it:
RequireJS relative paths
Using require with relative paths
This is the way I found around this: Create a minified && uglified && required file, where all other files are loaded into. Also know as the RequireJS Optimizer.
I'm testing out requireJS and am trying to make a simple project using highcharts. I've started with the requireJS multipage example project as a starting point.
My dir structure looks the same as the base structure, with highstock.js added in the lib directory.
page1.html: page 1 of the app.
page2.html: page 2 of the app.
js
app: the directory to store app-specific modules.
lib: the directory to hold third party modules, like jQuery.
common.js: contains the requirejs config, and it will be the build
target for the set of common modules.
page1.js: used for the data-main for page1.html. Loads the common
module, then loads app/main1, the main module for page 1.
page2.js: used for the data-main for page2.html. Loads the common
module, then loads app/main2, the main module for page 2.
common.js holds the configuration and I've added a shim for highstock there:
requirejs.config({
baseUrl: 'js/lib',
paths: {
app: '../app'
},
shim: {
"highstock": {
"exports": "Highcharts",
"deps": [ "jquery"]
},
} // end Shim Configuration
} );
I also am using the base build file, with the addition of a line to set common.js as the config file and another to disable minifying.
optimize: "none",
mainConfigFile: '../www/js/common.js',
In apps/main1.js I've added a var HighCharts= require('highstock'); and I then try to use it.
When I run this in the normal build everything works fine. All the dependencies hold and everything loads.
When I attempt to optimize my build, highcharts doesn't receive the jQuery dependency. I think I see why its happening, but I'm not sure how to fix it.
My build creates 3 files, common.js, page1.js, and page2.js.
The relevant parts of the build output:
js/lib/../common.js
----------------
js/lib/../common.js
js/lib/jquery.js
...
js/lib/../page1.js
----------------
js/lib/../page1.js
js/lib/highstock.js
js/app/main1.js
...
My page then references the built page1. When it attempts to load the highstock module it errors out since jQuery has not yet been loaded/isn't accessible.
When I see the built page1 I can see why.
require(['./common'], function (common) {
require(['app/main1']); //highcharts is in main1 in the non-optimized version
});
define("../page1", function(){});
//a few more defines
(function () { // start highcharts module definition HERE
So instead of being defined in the callback after common (including jQuery) has been loaded, its loaded after making the request, but before the callback executes.
My question is, why is this happening there instead of inside the callback (which is where it is loaded in the non-optimized version). I've tried multiple options in the build.js file and config file and I seem to be missing some key concept or small error.
Sorry for the super long question but I felt all the info was necessary. If more info is needed I can post it, or get rid of something superfluous.
Please take look at very simple example which use require js http://jsfiddle.net/wAM3h/
require({
paths: {
jquery: "//cdnjs.cloudflare.com/ajax/libs/jquery/1.8.2/jquery.min",
hchart: [
"http://code.highcharts.com/highcharts",
"http://code.highcharts.com/highcharts-more",
"http://code.highcharts.com/modules/exporting"
]
}
},
['jquery', 'hchart'], function($, hc) {
window.chart = new Highcharts.Chart(options);
});
Not sure you're still involved with the project or not:
I see that you've not defined the path to the highcharts library in the code above. I could not see it even in the repo you mentioned.
And, again, highcharts prevents re-declaration of this namespace, so you must use a different name
- Hence, you must use a different name while shim-ming it
Note: Libraries like highcharts can be safely used in an amd module without using a shim (unless you need explicit access to the object exported by it).
So, your Config File should look like this:
requirejs.config({
baseUrl: 'js/lib',
paths: {
app: '../app',
'highstock-custom-name': 'path/to/highcharts.js'
},
shim: {
"highstock-custom-name": {
... //as is, although not necessary
}
}
});
I am trying to wrap my head around dependencies in requirejs.
If I already declared dependencies for a file using shim, do I need to re-declare it when I define the module in that file?
If I use require to load dependencies such as backbone, do I need to re-declare it when I define a module that is loaded as part of require?
Here's my code so far:
require.config({
//alias
paths: {
Backbone: 'libs/backbone-min',
Config: 'config',
Dom: 'dom',
App: 'app'
},
//dependencies
shim: {
'Backbone': ['libs/underscore-min'],
'Dom': ['libs/sizzle']
}
});
//used to load and use stuff
require(['Config','Dom','App','Backbone'], function(){
});
So in dom.js can I just define a module using define(function(){...}); and start using Sizzle? Or do I still need to define it like this define(['libs/sizzle'], function(){...});
Also if I define a module in app.js, do I still need to load backbone in define, since I already included it as part of require().
1) If I already declared dependencies for a file using shim, do I need
to re-declare it when I define the module in that file?
For every module you need to define it's set of dependencies.
2) If I use require to load dependencies such as backbone, do I need
to re-declare it when I define a module that is loaded as part of
require?
If you want to use backbone as dependency in arbitary modyle you could write
define(['backbone'], function(Backbone) { .. }