Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using webpack with an existing requirejs application

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.

like image 754
grahamb Avatar asked Apr 14 '15 01:04

grahamb


People also ask

Does Webpack use CommonJS?

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.

Does Webpack support ES6?

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.

Why do we need RequireJS?

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 ...


1 Answers

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

like image 144
grahamb Avatar answered Oct 16 '22 00:10

grahamb