15

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:

enter image description here

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.

enter image description here

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.

Tomáš Zato
  • 50,171
  • 52
  • 268
  • 778
grahamb
  • 887
  • 3
  • 7
  • 22
  • 2
    It looks like `jquery.instructure_jquery_patches` isn't exported correctly (You can try to `console.log(require("jquery"))` to vertify it). Check the AMD code in this file. Some older versions of jquery do a check for `define.amd.jQuery` and this is not provided by default. You'll need to provide it (http://webpack.github.io/docs/configuration.html#amd). – Tobias K. Apr 14 '15 at 15:18
  • @TobiasK. adding `amd: { jQuery: true }` to my webpack config file worked. Thanks! – grahamb Apr 14 '15 at 18:45

1 Answers1

8

TobiasK's comment pointed me at needing to add amd: { jQuery: true } to my webpack config. Everything is working now.

Community
  • 1
  • 1
grahamb
  • 887
  • 3
  • 7
  • 22