Error when using webpack with jQuery - javascript

I'm just starting to use Webpack, and I have an issue when I try to use jQuery with it. I'm a very newbie with Webpack, so please apologize if my question seems very basic.
Here is my webpack.config.js:
var webpack = require("webpack");
var path = require("path");
var bower_dir = __dirname + "/public/js/bower_components";
var compiled_dir = __dirname + "/public/js/compiled";
module.exports = {
entry: {
signup: compiled_dir + "/signup"
},
plugins: [
new webpack.ProvidePlugin({
$ : "jquery",
jQuery : "jquery",
"window.jQuery" : "jquery",
"root.jQuery" : "jquery"
})
],
resolve: {
alias: {
jquery : bower_dir + "/jquery/src/jquery",
}
},
output: {
path: path.join(__dirname, "public/js/dist"),
filename: "[name].bundle.js"
}
};
As I'm using ProvidePlugin (for jQuery plugins), I have no require("jquery") at the begininng of my file.
However, at execution, I get this output on the console :
TypeError: jQuery.expr is undefined
http://localhost:9000/js/dist/signup.bundle.js
Line 6250
Do you have any clue ?
Thanks in advance.

Solved by removing "resolve" section in webpack.config.js and by installing jquery with npm.
However, if someone could explain me why it works now, I would be very grateful :-)

This seems to be an issue with an earlier/current version of JQuery, according to this issue raised here - https://github.com/webpack/webpack/issues/1066.
To summarize from the above link, JQuery uses RequireJS, which has an implementation of AMD different from that of the actual AMD spec. This might be fixed in later versions. For now, try using the dist folder, which works just fine as well.
Just change this line here -
alias: {
jquery : bower_dir + "/jquery/src/jquery",
}
to this -
alias: {
jquery : bower_dir + "/jquery/dist/jquery",
}
In the meantime, there is a Webpack loader to fix this, and also a tutorial on how to use it, by Alexander O'Mara -
https://github.com/AlexanderOMara/amd-define-factory-patcher-loader
http://alexomara.com/blog/webpack-and-jquery-include-only-the-parts-you-need/

Related

Why requiring javascript asynchronous loading under my webpack configuration

I'm really struggling with odd codes.
I want to include some query parameters by $.ajaxPrefilter in all jQuery ajax request.
I found below the code make it if it load correctly synchronous order.
But, following code in entry.js loaded jscode in unpredictable order.Sometimes prefilter.js were preloaded ,the other time, post_ajaxs.js were preloaded.(I inspected server post message,and sometimes lack of data and I checked timing loading using chrome devtools).
require(['prefilter'])
$(function(){
if($("#page_id").length > 0) {
require([
"src/common/post_ajax.js"
]);
}
});
Why is it caused? I'm confused because I first thought require keyword is synchronous loading.
I show partial fragment of webpack.config.js may be related.
entry: {
/webroot/js/entry.js: __dirname+"/src/entry.js"
},
resolve: {
alias: {
"prefilter": __dirname + "/src/common/prefilter.js",
}
},
output: {
path: __dirname + "/webroot/js/",
filename: "[name].js",
chunkFilename: "[hash].[id].js?" + (+new Date()),
publicPath: "/js/"
},
plugins: [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.AggressiveMergingPlugin(),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery",
d3: "d3"
})
]
I want to enforce prefilter.js preloaded and load post_ajax after it. Please, give me help.Any information I'll appreciate.
Edit:
Here is prefilter.js.
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
options.data = $.param($.extend(originalOptions.data, {'data[extra]':$("#some_id").val() }));
}
});
It might be scope problem because outer required js is global scope and not nested by function curly braces. Webpack might separate dependencies because I test two case using require.ensure nesting $(function{}) and putting require(['prefilter']) into $(function{})'s scope, both works correctly though it is my prediction.
But,more correct answer welcome if you have.

Webpack: Exposing global variable without using ProvidePlugin and expose-loader

I'm working in this ReactJS project and I have a requirement to read subfolder package.json, install them all into the node_modules and after, all dependencies installed add them to the global variable so they can be used anywhere in the code.
The problem being is that I don't have access to the jsons on expose-loader due to the syntax from webpack.config.js (I need to add them dynamically), so instead I created a loader that adding as test the package.json, gets the dependencies and tries to replicate expose-loader behaviour.
This is
var toCamelCase = function(str) {
return str.toLowerCase()
.replace( /[-_]+/g, ' ')
.replace( /[^\w\s]/g, '')
.replace( / (.)/g, function($1) { return $1.toUpperCase(); })
.replace( / /g, '' );
}
var returning_string = function(dependencies_object){
var final_string = "";
Object.keys(dependencies_object).map(function(dependency){
var location = require.resolve(dependency);
var export_dependency = 'module.exports = global["'+toCamelCase(dependency)+'"] = require("-!'+ location+'");';
final_string += export_dependency;
})
return final_string;
};
module.exports = function() {};
module.exports.pitch = function(e){
if(this.cacheable) {this.cacheable();}
var dependencies = require(e).dependencies;
return returning_string(dependencies);
};
The problem is that for some reason even though the output is exactly the same, it is not adding the library to the global context while using the expose loader it does work. When doing both things I manually added the dependency to provide plugin which I'll need to replicate later somehow anyway.
Is there any better way to do this? Or I am doing right but I am missing something?
After a research I found out the following in webpack 2.x (I am using webpack 1.x but I guess the phylosophy is valid for my version) documentation about configuration says:
write and execute function to generate a part of the configuration
So my approach to this problem is not to use a new plugin but reuse the ones that should work. Basically I wrote a new javascript file that creates all loaders that I need in a webpack.config way.
This is the file:
dependencies_loader.js
https://gist.github.com/abenitoc/b4bdc02d3c7cf287de2c92793d0a0b43
And this is aproximately the way I call it:
var webpack = require('webpack');
var dependency_loader = require('./webpack_plugins/dependencies_loader.js');
module.exports = {
devtool: 'source-map',
entry: {/* Preloading */ },
module: {preLoaders: [/*Preloading*/],
loaders: [/* Call all the loaders */].concat(dependency_loader.getExposeString()),
plugins: [
new webpack.ContextReplacementPlugin(/package\.json$/, "./plugins/"),
new webpack.HotModuleReplacementPlugin(),
new webpack.ProvidePlugin(Object.assign({
'$': 'jquery',
'jQuery': 'jquery',
'window.jQuery': 'jquery'
}, dependency_loader.getPluginProvider())), // Wraps module with variable and injects wherever it's needed
new ZipBundlePlugin() // Compile automatically zips
]
Notice that I concat the array of loaders adding the following loaders with getExposeString() that I need and reassign the object with the new global elements in pluginProvider with getPluginProvider.
Also because I use jsHint I exclude global names that's why the other method.
This only solves for node_modules dependencies, there is a different approach if you need a local library.

Webpack gives undefined for adding Javascript library

I'm new to webpack , I trying to add skrollr.js to webpack configurations to use it whenever required, but I not sure what is the right approach for this , what I find that either using alias or export as module , but something is missing
webpack.config.js
module.exports = {
entry: ["./app/scripts/main.js","./app/scripts/skrollr.js"],
output: {
filename: "./app/scripts/bundle.js"
},
resolve: {
extensions: ['', '.js', '.jsx'],
alias: {"skrollr" : "./skrollr.js"}
},
module: {
loaders :[
{test:/\.(jsx|js)$/,exclude: /node_modules/,loader: 'imports?jQuery=jquery,$=jquery,this=>window' },
{test:/skrollr.js/,exclude: /node_modules/,loader: 'exports?skrollr'}
]
}
};
I have a file that is main.js which requires skroller variable , in the old way it was in a script tag in HTML loaded before the main so it is available ,
main.js
(function () {
'use strict';
require('./skrollr.js');
var s = skrollr.init({
but when ever i run the webpack using
node_modules/.bin/webpack -display-error-detalis
it gives an error
Uncaught ReferenceError: skrollr is not defined
clicking of the error file :
/*** IMPORTS FROM imports-loader ***/
var jQuery = require("jquery");
var $ = require("jquery");
/*** EXPORTS FROM exports-loader ***/
module.exports = skrollr;
}.call(window));
/*****************
** WEBPACK FOOTER
** ./app/scripts/skrollr.js
** module id = 2
** module chunks = 0
**/
You shouldn't need an alias for it, I would only use alias to remove the need relative paths in deeply nested import statements.
Does skrollr.js export anything? Have you tried
var skrollr = require('./skrollr.js');
...without the alias config in webpack.
Also, if you were to use aliases the pathname has to be absolute so webpack can find it
you need to pass your required module to variable
(function () {
'use strict';
require('./skrollr.js'); //you are just requiring it
var s = skrollr.init({
Change to
var skorllr = require('./skrollr.js');
(function () {
'use strict';
var s = skrollr.init({
and this line to be removed
{test:/skrollr.js/,exclude: /node_modules/,loader: 'exports?skrollr'}
you are getting error because if it. when you are bundling your files it is exporting skrollr which does not exist the time you run your code
NOTE:- you are already testing all js files with
{test:/.(jsx|js)$/,exclude: /node_modules/,loader: 'imports?jQuery=jquery,$=jquery,this=>window' }
you don't need to test separate skrollr.js

why require("angular") returns an empty object

I've configured webpack like this:
resolve: {
alias: {
angular: path.join(__dirname, './node_modules/angular/angular.js')
}
},
and in my file I require angular like this:
var angular = require("angular");
But for some reason an empty object is returned, why?
The other answers aren't quite accurate - it's true that the core angular.js file doesn't support CommonJS, but if you install it from NPM, a tiny wrapper file called index.js is provided. It's literally just two lines:
require('./angular'); // Runs angular.js, which attaches to the window object
module.exports = angular; // Exports the global variable
This allows you to use it in CommonJS environments like normal. So if you update your config like so, it should work:
resolve: {
alias: {
angular: path.join(__dirname, './node_modules/angular/index.js')
}
},
(That said, this should be Webpack's default behaviour even if you don't alias angular, as index.js is marked as Angular's main file in its package.json - you probably can get away with just using no alias at all!)
The other answers are not providing a working solution. It is true that Angular 1 is not working nicely with webpack out-of-the-box (see https://github.com/webpack/webpack/issues/2049), but it can be loaded with a shim. Try this webpack loader config:
module: {
loaders: [
/*
* Necessary to be able to use angular 1 with webpack as explained in https://github.com/webpack/webpack/issues/2049
*/
{
test: require.resolve('angular'),
loader: 'exports?window.angular'
},
]
},
plugins: [
new webpack.ProvidePlugin({
'angular': 'angular',
}),
],
This should initialize the angular object properly instead of the default action of setting it to an empty object (which does not have a property named module).
Conceptual answer -
Angular 1.x does not support CommonJS modules that's why following approach of exporting yields an empty object:
var angular = require("angular");
So better omit the var angular part and just make use of require("angular");
Angular 1 doesn't support CommonJS modules, so it 'exports' an empty object.
Instead, just require it (without assigning the result):
require('angular')

Injecting variables into webpack

I'm trying to inject a variable into each module within my webpack bundle in order to have debugging information for JS errors per file. I've enabled
node: {
__filename: true
}
Current file path in webpack
in my webpack.config, but I would like to inject something like
var filename = 'My filename is: ' + __filename;
into each module before compilation. I've seen the Banner Plugin with the raw option but it seems this would only inject the banner outside of the webpack closure rather than my desired result of injecting script into each module.
I use variables to resolve a couple of variables in my webpack.config.js file:
plugins: [
new webpack.DefinePlugin({
ENVIRONMENT: JSON.stringify(process.env.NODE_ENV || 'development'),
VERSION: JSON.stringify(require('./package.json').version)
})
]
It might not be dynamic enough, but if it is, then you might be able to bypass that loader solution.
Write your own loader:
my_project/my_loaders/filename-loader.js:
module.exports = function(source) {
var injection = 'var __filename = "' + this.resourcePath + '";\n';
return injection + source;
};
Add it to your pipeline and make sure to add also the configuration:
resolveLoader: {
modulesDirectories: ["my_loaders", "node_modules"]
}
See the documentation on how to write a loader.

Categories