I'm using Laravel-mix and Webpack to combine and control scripts for a site.
I'm my main app.js I have these lines:
var jQuery = require( 'jquery' );
require( './vendor/polyfill-library.min.js' );
require( './vendor/polyfill-init.js' ); // which is using jQuery
In polyfill-init.js I'm doing this: jQuery( document ).ready( .... That results in this error:
Uncaught ReferenceError: jQuery is not defined
I also get this error if I try and mix it together using Laravel-mix, by adding this to my webpack.mix.js:
mix.js( [
'resources/js/app.js',
'resources/js/vendor/polyfill-library.min.js',
'resources/js/vendor/polyfill-init.js',
], 'assets/js/app.js')
I assume the error is because Webpack keeps the required/imported scripts in seperate namespaces/environments, so no conflicts occur. And that's all fine and dandy, - but I don't know how to combine two required/imported scripts, so they're using the same namespace/environment.
... If I copy all the code into app.js (instead of requiring it), then it works, but it's not pretty. Not pretty at all.
I looked at Webpack's documentation to see if there's a way to define a dependency for an imported/a required script, but either it's not there; or I'm not getting it.
I also looked at the 7 billion ways that this post suggest that I'd do it, - but I'm trying to figure out how Webpack/Laravel-mix want me to do it.
So my question is... Are there a way that I can do something like this:
var jQuery = require( 'jquery' );
require( './vendor/polyfill-library.min.js' );
require( './vendor/polyfill-init.js' ); // which is using jQuery
... and let Webpack know, that polyfill-init can use jQuery?
You can use provideplugin:
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
]
Try window.jQuery = require( 'jquery' );
polyfill-init.js probably looks for jQuery in global scope while the var jQuery is only available in the local scope of this module.
U should externalize JQuery from the webpack.
index.html
<script
src="https://code.jquery.com/jquery-3.1.0.js"
integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
crossorigin="anonymous">
</script>
webpack.config.js
module.exports = {
//...
externals: {
jquery: 'jQuery'
}
};
polyfill-init.js
import $ from 'jquery';
Refer more details here https://webpack.js.org/configuration/externals/
Related
I tried to require materialize in Vue and Laravel
in bootstrap.js I have
window.Materialize = require('materialize-css');
in App.vue component I have
mounted(){
Materialize.toast('I am a toast!', 4000)
}
and received
"Uncaught ReferenceError: Materialize is not defined"
message.
Either drop a script tag with materialize js or, make sure jquery is loaded before requiring materialize.
I suppose you have a browserify setup and if you do you can do something like that:
require('jquery')(window);
require('materialize-css')(window);
Or something like that:
global.jQuery = require('jquery')
global.Materialize = require('materialize-css')
Or import globally jQuery only then simply var Materialize=require('materialize-css') and use the variabile instead.
For webpack setups add a plugin for the stuff you have installed via npm and need globally:
plugins:[
new webpack.ProvidePlugin({
$: "jquery",
jQuery:'jquery',
jquery:'jquery'
}),
],
I am trying to achieve the following:
bundle (in this order) jquery, tether, and bootstrap.js.
load this bundle within a HTMLpage and beneath it load other page specific scripts.
To achieve this I am using webpack 2 and the CommonsChunkPlugin. Here is my config.
For entries I have:
const scriptsEntry = {
blog_index: SRC_DIR + "/js/pages/blog_index.js",
blog_about: SRC_DIR + "/js/pages/blog_about.js",
vendor: ["jquery", "tether", "bootstrap"]
};
In the plugins section:
scriptsPlugins.push(
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
filename:"vendor.bundle.js",
minChunks: 2
}),
...
}));
Inside 'index.html' I load the bundles:
<script src="{{ url_for('static', filename='dist/js/vendor.bundle.js') + anti_cache_token }}"></script>
<script src="{{ url_for('static', filename='dist/js/home.js') + anti_cache_token }}"></script>
Inside the source directory in the blog_index.js I make use of jquery:
import $ from "jquery";
$(".home-click").click(function () {
alert("clicked from .home-click");
});
The result:
everything bundles without any errors.
when I click .home-click the alert box fires as expected.
checking the bundled files I see that:
vendor.bundle.js contains: jquery, tether, and bootstrap.
looking inside, for instance, blog_index.js (after it was run through webpack 2), I notice that the jquery import is not bundled inside this file, but vendor.bundle.js (this is as expected).
However, I have the following problem when I check the browser console:
I tried switching the order of the libraries in this line vendor: ["jquery", "tether", "bootstrap"], but nothing changed--the error is still there.
Do you know how can I solve this, preferably without using additional webpack plugins?
Bootstrap's javascript assumes that jQuery is hooked on the window object, it does not require it or anything.
By bundling stuff up, you do not expose variables to the global scope, or at least you should not be doing that. So the bootstrap code cannot find jQuery.
Add this to your plugins and you should be ok
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
tether: 'tether',
Tether: 'tether',
'window.Tether': 'tether',
})
This will replace all instances where jQuery is assumed as global with the export of the jQuery package, which is the jQuery object. Same for Tether
Maybe I have fundamentally misunderstood how requirejs config works but I thought my configuration below made some libraries global so I could just use them in other files while only having to require and define files that I needed to use within the individual script. However I cannot reference $ (jQuery) in my application code without getting a reference error indicating it is not globally accessible. I've isolated the problem to the simple example below.
My file set up is as follows:
test
|
|-index.html
|-TestApp.js
|-MainApp.js
|-lib
| |-require.js
| |-jquery.js
| |-loadash.js
| |-backbone.js
|-css
|-test.css
The library file versions are RequireJS 2.1.22, jQuery 2.0.3, Loadash 3.10.1 and Backbone 1.2.1. I'm just trying to set up my environment and the approach I am taking is to pass my TestApp.js file to require.js to load the required files and bootstrap the application code in MainApp.js. The script in index.html is as follows:
<!DOCTYPE html>
<html>
<head>
<link rel='stylesheet' type='text/css' href='css/test.css'/>
</head>
<body>
<div></div>
<script src="./lib/require.js" type="text/javascript" data-main="./TestApp.js"></script>
</body>
</html>
The referenced css script file simply ensured the div is visible as an orange square. See below:
div {
height: 100px;
width: 100px;
background-color: #FA6900;
border-radius: 5px;
}
It's the script line in index.html that then kicks off the application code by passing my configuration file to requirejs. This is the TestApp.js passed across as data-main. The TestApp.js is here:
require.config({
paths: {
'jquery': 'lib/jquery',
'lodash': 'lib/lodash',
'backbone': 'lib/backbone'
},
map: {
'*': {
// Backbone requires underscore. This forces requireJS to load lodash instead:
'underscore': 'lodash'
}
},
shim: {
jquery: {exports: '$'},
underscore: {
deps: ['jquery'],
exports: '_'
},
backbone: {
deps: ['underscore'],
exports: 'Backbone'
},
TestApp: {
deps: ['backbone'],
exports: 'TestApp'
}
}
});
require(['MainApp'], function(MainApp) {
MainApp.run();
});
The file above references the paths to the library files I want to use, I then remap loadash to be loaded when underscore is required (I need some of the extra loadash capability), I then use the shim to ensure the dependancies are correct as the files are loaded. Passing this config file to require.js in the index.html seems to be working as all of the files are showing as loaded in my browser. However the problem seems to be they do not appear to be globally accessible as I thought they would be.
Following the config section the last require call loads the MainApp.js file and calls the exposed run function. The MainApp.js looks like this:
define(function(require) {
var run = function() {
$(document).ready(function() {
$('div').click(function() {
$('div').fadeOut('slow');
});
});
};
return {
run: run
};
});
As far as I understood I should not need to require the files I already mentioned in the require config, I thought they should be loaded and available to this code. This is where I have misunderstood what is going on or have missed a step out. The exposed run function is being called but the first line that calls $ throws the error:
ReferenceError: Can't find variable: $
So my questions are:
What have I got wrong in my thinking?
(or) What am I doing incorrectly?
What should I be doing in order to preload and make available
frequently referenced libraries so that I do not need to require and
define them in every file I have?
As far as I understood I should not need to require the files I already mentioned in the require config, I thought they should be loaded and available to this code.
You misunderstood how RequireJS works. You should read the documentation from start to finish. For now, here are things you should change.
You should require jquery in your MainApp module:
define(function(require) {
var $ = require("jquery");
You should remove your shims that you have for jquery, underscore and backbone as they all call define and shim is only for code that does not call define. I don't know what TestApp is but if it is your own code, you really should make it into a proper AMD module and remove the shim.
#Louis has made me realise the error in what I was doing above. Changing the shim in TestApp.js so that is reads:
MainApp: {
deps: ['backbone'],
exports: 'MainApp'
}
Corrected the problem, now Backbone, $ and _ are all available to the rest of my application code without cluttering up each files require. i.e. I do not need to begin every file with:
define (['lib/jquery', 'lib/loadash', 'lib/backbone'], function($, _ , Backbone) {
Given in my actual app the list of common deps is quite large this means I only need to define locally used resources and can control the paths from a single location.
First question so please be nice!
I've been able to get Isotope working fine, but as soon as I try to use RequireJS to load it alongside jQuery, I can't seem to get it to work.
It's definitely loading the files because I can see them in the head of the dev toolbar, so the paths are fine. I'm stumped about what isotopePkg does, he even says it's undefined (???)
this is what my app.js looks like...
requirejs.config({
paths: {
'jquery' : ['//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min',
'jquery-1.10.2.min'],
'isotope' : 'isotope.min'
},
shim: {
'isotope' : ['jquery']
}
});
require(['jquery', 'isotope'], function(jQuery, Isotope) {
jQuery('#container').isotope({
itemSelector: '.element'
});
});
Does anyone have a working example of what this code should look like, or have any ideas about where I'm going wrong here?
I encountered the same issue where requiring the isotope package on live environment was requesting for other modules. Please see the code below and link isotope documentation for further instruction on how to implement isotope with requirejs.
I realize that answer is late but hopefully this might help anyone who come across this issue as well.
// require the require function
requirejs( [ 'require', 'jquery', 'path/to/isotope.pkgd.js' ],
function( require, $, Isotope ) {
// require jquery-bridget, it's included in isotope.pkgd.js
require( [ 'jquery-bridget/jquery.bridget' ],
function() {
// make Isotope a jQuery plugin
$.bridget( 'isotope', Isotope );
// now you can use $().isotope()
$('#container').isotope({...});
}
);
});
In my project I want to use RequireJS and bootstrap my app as follows:
requirejs.config({
baseUrl: 'scripts/vendor',
paths: {
jquery: [
'https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min',
'jquery'
],
angular: [
'http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min',
'angular'
],
app: '../app'
}
});
require(['require', 'jquery', 'angular', 'app'], function(require, $, angular, app) {
console.log(require);
console.log($);
console.log(angular);
console.log(app);
});
On my index.html only RequireJS is loaded via script tag, where the RequireJS loads the above code.
What works:
- in my Network monitor I can see that RequireJS, jQuery, Angular and app are loaded
- The console.log messages print correct for require, jQuery and app
The angular object is somehow undefined. But if I don't load it from CDN and use my local load, it works! The local file is a RequireJS wrapper that looks like this:
define(['/components/angular/angular.min.js'], function () {
return angular;
});
How do I get this work with Angular'S CDN? Or does this depend on support from Angular?
First, you are confusing "paths" with "shim"
Path is good, don't go for "shim" behavior. But, you need to make your "paths" proper:
paths: {
jquery: 'https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min',
// NOTE: angular is "plain JS" file
angular: 'http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min',
app: '../app'
}
Then, you need to let go of the need to have something returned to you... Just "use the force, Luke" :) and expect the right globals to be there when you need them:
require(['jquery', 'app', 'angular'], function($, app, thisValueDoesNotMatter) {
// you don't need to wrap "require" Just use global
console.log(require);
console.log($);
console.log(app);
// note, angular is loaded as "plain JavaScript" - not an AMD module.
// it's ok. It returns "undefined" but we just don't care about its return value
// just use global version of angular, which will be loaded by this time.
// because you mentioned it in your dependencies list.
console.log(window.angular);
});