I am working with an existing application (canvas-lms) that uses RequireJS in its build system. I'm working on a pseudo-standalone application that plugs into Canvas (a "client_app" in Canvas parlance). This is a fontend-only app that makes API calls back to the host Canvas app. The details aren't terribly important for my question - all a client_app needs to do is have a build script that spits out a JS file in a defined place within the Canvas app tree.
I'm trying to use Webpack to build my app instead of RequireJS. Everything works great if I keep all my dependencies self-contained (e.g. npm-install everything I need); however, Canvas already provides many of these dependencies (e.g. React, jQuery), and in jQuery's case, it provides a patched version that I'd like to use instead. This is where I start to have problems.
Getting React to work was easy; Canvas installs it with bower, so I was able to add an alias
in my webpack config to point at it:
alias: {
'react': __dirname + '/vendor/canvas/public/javascripts/bower/react/react-with-addons',
}
(__dirname + /vendor/canvas
is a symlink in my application tree to the host Canvas application's tree)
Where I'm having trouble is trying to load the provided copy of jQuery.
Canvas has the following jQuery structure:
/public/javascripts/jquery.js:
define(['jquery.instructure_jquery_patches'], function($) {
return $;
});
/public/javascripts/jquery.instructure_jquery_patches.js:
define(['vendor/jquery-1.7.2', 'vendor/jquery.cookie'], function($) {
// does a few things to patch jquery ...
// ...
return $;
});
/public/javascripts/vendor/jquery.cookie.js -- looks like the standard jquery.cookie plugin, wrapped in an AMD define:
define(['vendor/jquery-1.7.2'], function(jQuery) {
jQuery.cookie = function(name, value, options) {
//......
};
});
and finally, /public/javascripts/vendor/jquery-1.7.2.js. Not going to paste it in, since it's bog-standard jQuery1.7.2, except that the AMD define has been made anonymous -- reverting it to the stock behaviour doesn't make a difference.
I want to be able to do something like var $ = require('jquery')
or import $ from 'jquery'
and have webpack do whatever magic, poorly-documented voodoo it needs to do to use jquery.instructure-jquery-patches
.
I've tried adding the path to resolve.root
in my webpack.config.js
file:
resolve: {
extensions: ['', '.js', '.jsx'],
root: [
__dirname + '/src/js',
__dirname + '/vendor/canvas/public/javascripts'
],
alias: {
'react': 'react/addons',
'react/addons/lib': 'react/../lib'
}
},
This should mean that when I do a require('jquery')
, it first finds /public/javascripts/jquery.js
, which defines a module with instructure_jquery_patches
as a dependency. That falls into instructure_jquery_patches
, which defines a module with two dependencies ('vendor/jquery-1.7.2', 'vendor/jquery.cookie'
).
In my main entry point (index.js), I am importing jQuery (also tried a commonjs require, no difference), and trying to use it:
import React from 'react';
import $ from 'jquery';
$('h1').addClass('foo');
if (__DEV__) {
require('../scss/main.scss');
window.React = window.React || React;
console.log('React: ', React.version);
console.log('jQuery:', $.fn.jquery);
}
Building the bundle with webpack seems to work; there are no errors. When I try to load the page in the browser, though, I'm getting an error from within jquery.instructure-jquery-patches.js
:
It would seem that jQuery is not availble within jquery.instructure-jquery-patches.
It is, however, available in the global scope after the page loads, so jQuery is being evaluated and executed.
My guess is that I'm running into some sort of requirejs/amd asynchronicity problem, but that's a shot in the dark. I don't know enough about requirejs or amd to know for sure.
As you may know, webpack supports a couple of module types out of the box, including both CommonJS and ES modules. Webpack also works on both client- and server-side JavaScript, so with webpack, we can also easily handle assets and resources like images, fonts, stylesheets, and so on.
This section covers all methods available in code compiled with webpack. When using webpack to bundle your application, you can pick from a variety of module syntax styles including ES6, CommonJS, and AMD.
RequireJS is a basic loader, which is used to loads the JavaScript files, it is a framework to manage dependencies between JavaScript files, and in modular programming, all the functionality divides in different modules, so RequireJs is a best tool to assemble different JavaScript files from different modules by which ...
TobiasK's comment pointed me at needing to add amd: { jQuery: true }
to my webpack config. Everything is working now.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With