Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

webpack jquery plugin loading its own instance of jquery

I've been trying to load a jquery plugin through webpack. This plugin is packaged as a npm module and in its dependencies includes only jquery. I think webpack loads that instance of jquery instead of using the one I provide globally with the ProvidePlugin. I tried all the solutions provided in another stackoverflow post (Managing jQuery plugin dependency in webpack) but they didn't make the trick; the result is always the same: "terminal() is not a function". If I manually modify the package in the node_modules folder deleting the jquery dependency in the package.json and the downloaded dependency in the node_modules plugin folder webpack successfully binds the plugin with the global instance of jquery. I know, I could simply make a fork of that package and use a private npm repository but I would like to use the official package.

That's my webpack configuration:

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var CleanWebpackPlugin = require('clean-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var moment = require('moment');
var path = require('path');
var environment = process.env.APP_ENVIRONMENT || 'dev';

module.exports = {

  entry: {
    'app': './src/main.ts',
    'polyfills': './src/polyfills.ts',
    'vendor': './src/vendor.ts'
  },
  /*devtool: 'source-map',*/
  output: {
    path: './dist',
    filename: '[name].browser.' + moment().format('DDMMYYYYHHmm') + '.js'
  },
  module: {
    loaders: [
      { test: /\.component.ts$/, loader: 'ts!angular2-template' },
      { test: /\.ts$/, exclude: /\.component.ts$/, loader: 'ts' },
      { test: /\.html$/, loader: 'raw-loader' },
      { test: /\.css$/, include: path.resolve('src/app'), loader: 'raw-loader' },
      {
        test: /\.css$/, exclude: path.resolve('src/app'), loader: ExtractTextPlugin.extract('style', 'css', {
          fallbackLoader: "style-loader",
          loader: "css-loader"
        })
      },
      { test: /\.(png|jpe?g|gif|ico)$/, loader: 'file?name=fonts/[name].[ext]' },
      { test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff&name=fonts/[name].[ext]" },
      { test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff&name=fonts/[name].[ext]" },
      { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/octet-stream&name=fonts/[name].[ext]" },
      { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file?name=fonts/[name].[ext]" },
      { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=image/svg+xml&name=fonts/[name].[ext]" },
    ]
  },
  resolve: {
    extensions: ['', '.js', '.ts', '.html', '.css']
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: ['vendor', 'polyfills']
    }),
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new webpack.DefinePlugin({
      app: {
        environment: JSON.stringify(environment),
        config: JSON.stringify(require('./profile/' + environment + ".profile.js"))
      }
    }),
    new CleanWebpackPlugin(
      ['dist']
    ),
    new CopyWebpackPlugin([
      { from: './src/images', to: 'images' }
    ]),
    new ExtractTextPlugin('[name].browser.css'),
    new webpack.optimize.UglifyJsPlugin({ minimize: true }),
    new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery",
      "window.jQuery": "jquery"
    })
  ]
};

Here the jquery.terminal package.json:

{
  "_args": [
    [
      {
        "raw": "[email protected]",
        "scope": null,
        "escapedName": "jquery.terminal",
        "name": "jquery.terminal",
        "rawSpec": "0.11.11",
        "spec": "0.11.11",
        "type": "version"
      },
      "/home/giovanni/Projects/Private/site"
    ]
  ],
  "_from": "[email protected]",
  "_id": "[email protected]",
  "_inCache": true,
  "_installable": true,
  "_location": "/jquery.terminal",
  "_nodeVersion": "4.2.6",
  "_npmOperationalInternal": {
    "host": "packages-16-east.internal.npmjs.com",
    "tmp": "tmp/jquery.terminal-0.11.11.tgz_1475868856610_0.3736777463927865"
  },
  "_npmUser": {
    "name": "jcubic",
    "email": "[email protected]"
  },
  "_npmVersion": "3.5.2",
  "_phantomChildren": {},
  "_requested": {
    "raw": "[email protected]",
    "scope": null,
    "escapedName": "jquery.terminal",
    "name": "jquery.terminal",
    "rawSpec": "0.11.11",
    "spec": "0.11.11",
    "type": "version"
  },
  "_requiredBy": [
    "#USER",
    "/"
  ],
  "_resolved": "https://registry.npmjs.org/jquery.terminal/-/jquery.terminal-0.11.11.tgz",
  "_shasum": "eaeed2f8f305ac0477d71ef492e7d98d6064d812",
  "_shrinkwrap": null,
  "_spec": "[email protected]",
  "_where": "/home/giovanni/Projects/Private/site",
  "author": {
    "name": "Jakub Jankiewicz",
    "email": "[email protected]",
    "url": "http://jakub.jankiewi.cz"
  },
  "bugs": {
    "url": "https://github.com/jcubic/jquery.terminal/issues"
  },
  "dependencies": {
    "jquery": "^2.1.4"
  },
  "description": "jQuery Terminal Emulator is a plugin for creating command line interpreters in your applications.",
  "devDependencies": {
    "istanbul": "^0.4.3",
    "jasmine": "^2.4.1",
    "jasmine-node": "^1.14.5",
    "jsdom": "^3.1.2"
  },
  "directories": {},
  "dist": {
    "shasum": "eaeed2f8f305ac0477d71ef492e7d98d6064d812",
    "tarball": "https://registry.npmjs.org/jquery.terminal/-/jquery.terminal-0.11.11.tgz"
  },
  "gitHead": "0f2e55a6501d96aa17d42e4fcc071fab906309d8",
  "homepage": "http://terminal.jcubic.pl",
  "keywords": [
    "terminal",
    "emulator",
    "prompt",
    "console",
    "keyboard",
    "type",
    "rpc",
    "input",
    "ui"
  ],
  "license": "MIT",
  "main": "js/jquery.terminal-0.11.11.js",
  "maintainers": [
    {
      "name": "jcubic",
      "email": "[email protected]"
    }
  ],
  "name": "jquery.terminal",
  "optionalDependencies": {},
  "readme": "ERROR: No README data found!",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/jcubic/jquery.terminal.git"
  },
  "scripts": {},
  "version": "0.11.11"
}
like image 924
Giovanni Di Santo Avatar asked Oct 18 '16 12:10

Giovanni Di Santo


2 Answers

I solved my problem by slightly modifying my Webpack configuration. As suggested here (Managing jQuery plugin dependency in webpack), I added a jquery alias. In the example provided the alias is statically specified and it didn't work for me. I switched to a dynamic value and that solved the problem.

Here it is the snippet:

alias: {
      'jquery': path.resolve(path.join(__dirname, 'node_modules', 'jquery'))
     },
like image 104
Giovanni Di Santo Avatar answered Sep 18 '22 00:09

Giovanni Di Santo


An alternative solution, for the yarn package manager, is to force using the library dependency of your main application. By specifying the resolutions in your package.json, it can be used to prevent downloading of differing versions of sub-dependencies. Other than your what your application uses.

You should not use this solution if your package is publicly redistributed.

Issue

If for example your application depends on"jquery": "~1.12.0" and jquery-plugin which includes its own dependencies: { "jquery": ">=1.9" }. Assuming the latest version of jquery is 3.4.1, running yarn install will download a directory structure like.

node_modules
    [email protected]
    jquery-plugin
        node_modules
             [email protected]
//app.js
const $ = require('jquery');
require('jquery-plugin');
console.log(typeof $.fn.plugin); //undefined

Solution

Add a resolutions field to your package.json file and define your version overrides.

package.json

Force ALL sub-dependencies to use jQuery ~1.12.0

{
    "name": "project-name",
     "dependencies": {
         "jquery": "~1.12.0",
         "jquery-plugin": "*"
     },
     "resolutions": {
         "jquery": "~1.12.0"
     }
}

or Force jquery-plugin to use jQuery ~1.12.0

{
    "name": "project-name",
     "dependencies": {
         "jquery": "~1.12.0",
         "jquery-plugin": "*"
     },
     "resolutions": {
         "jquery-plugin/jquery": "~1.12.0"
     }
}

Then run yarn install.

Result the duplicate jquery sub-dependencies are removed.

node_modules
    [email protected]
    jquery-plugin
//app.js
const $ = require('jquery');
require('jquery-plugin');
console.log(typeof $.fn.plugin); //function
like image 22
Will B. Avatar answered Sep 20 '22 00:09

Will B.