parcel-bundler / parcel

The zero configuration build tool for the web. 📦🚀
https://parceljs.org
MIT License
43.49k stars 2.27k forks source link

jQuery not being loaded correctly #2724

Closed hunterInt closed 3 years ago

hunterInt commented 5 years ago

🐛 bug report

I've spent almost a week trying to figure out why I'm having such problems with jquery being required. My only guess is that it has something to do with how Parcel is handling asset files. As you'll see below, I've tried including jQuery in my index.html file multiple ways, CDN and locally, and my jQuery(document).ready(function($) {console.log("jQuery loaded");... seems to load correctly, but the other files that require jQuery are not able to access it.

🎛 Configuration (.babelrc, package.json, cli command)

{
  "name": "foobar",
  "version": "0.1.0",
  "description": "",
  "main": "server.js",
  "dependencies": {
    "babel-preset-env": "^1.7.0",
    "coinbase-commerce-node": "^1.0.0",
    "express": "^4.16.4",
    "http": "0.0.0",
    "https": "^1.0.0",
    "jsonwebtoken": "^8.4.0",
    "jwt-decode": "^2.2.0",
    "moment": "^2.24.0",
    "mongoose": "^5.4.4",
    "morgan": "^1.9.1",
    "nodemailer": "^5.1.1",
    "parcel-bundler": "^1.10.3",
    "secure-remote-password": "^0.3.1"
  },
  "devDependencies": {
    "@babel/core": "^7.1.6"
  },
  "scripts": {
    "start": "npm-run-all --parallel watch:server watch:build",
    "watch:build": "parcel index.html",
    "watch:server": "nodemon server.js"
  },
}

🤔 Expected Behavior

jQuery should be loaded.

😯 Current Behavior

capture

💁 Possible Solution

🔦 Context

Other local files, seem to have loaded and been imported just fine, at this point I've stripped the entire app down the minimum; so the only files required are the ones needed to produce the error.

💻 Code Sample

index.html:

<script
      src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"
      type="text/javascript"
      async="false"
      defer="false"
    ></script>
<script
  src="./client/components/assets/front-assets/vendor/jquery-migrate/dist/jquery-migrate.js"
  type="text/javascript"
  async="false"
  defer="false"
></script>

<script
  src="./client/components/assets/front-assets/vendor/popper.js/dist/umd/popper.min.js"
  type="text/javascript"
  async="false"
  defer="false"
></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>
<script>
      jQuery(document).ready(function($) {
        console.log("jQuery loaded");
      });
</script>

🌍 Your Environment

ExpressJS sever:


const bundler = new Bundler(indexFile);

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(morgan("dev"));

const http = require("http").Server(app);

require("./app/routes")(app, db, consts, indexFile, express, auth, mail);

http.listen(port);

app.use(bundler.middleware());
Software Version(s)
Parcel 1.10.3
Node 10.8.0
npm/Yarn 6.8.0
Operating System Ubuntu
mschaaf commented 5 years ago

I ran into the same issue. There is code in the jquery file that does not init the global variables if it is loaded in scenarios like parcel. This is the code from jquery:

    if ( typeof module === "object" && typeof module.exports === "object" ) {

        // For CommonJS and CommonJS-like environments where a proper `window`
        // is present, execute the factory and get jQuery.
        // For environments that do not have a `window` with a `document`
        // (such as Node.js), expose a factory as module.exports.
        // This accentuates the need for the creation of a real `window`.
        // e.g. var jQuery = require("jquery")(window);
        // See ticket #14549 for more info.
        module.exports = global.document ?
            factory( global, true ) :
            function( w ) {
                if ( !w.document ) {
                    throw new Error( "jQuery requires a window with a document" );
                }
                return factory( w );
            };
    } else {
        factory( global );
    }

With parcel, it runs through the then block where it should run through the else in your scenario.

There is a workaround. You can change the line factory( global, true ) in the jquery file to factory( global, false ). I don't like this workaround but it is the only one I am aware of.

hunterInt commented 5 years ago

@mschaaf that worked! Thanks! I was just pasting in the JS into a <script> tag instead of pulling from a URL, which also works, but is very messy.

MindTooth commented 5 years ago

Is there a more trivial fix to this? Been toying with Parcel for the past few hours, and this seems to be a stopper. Currently trying to make https://github.com/fancyapps/fancybox work.

hunterInt commented 5 years ago

@MindTooth I'm still looking for a solution on importing other types of dependencies globally (besides jQuery). No luck here. :p

bakeiro commented 5 years ago

any solutions here? im running the same issue ;(

reducm commented 5 years ago
$ yarn add bootstrap@3 jquery babel-polyfill
  // index.js
import 'babel-polyfill'

import("jquery").then(async (jquery) => {
    $ = window.$ = window.jQuery = jquery
    await import('bootstrap')
    $(document).ready(function() {
      console.log('hello')
    })
})

//or

const jquery = require('jquery')
//
$ = window.$ = window.jQuery = jquery;

require('bootstrap')

$(document).ready(() => {
  console.log("hello");
});
cliffordp commented 4 years ago

@reducm That worked for me. Thanks!

Is there a way to make $ available but NOT require jQuery as a dependency in package.json? I'm using Parcel for a WordPress plugin, and I've got things working, including using PHP enqueueing which allows me to specify 'jquery' as a dependency, and WP already loads jQuery, so I just want to make sure I'm not double-including jQuery with both WP and my JS.

===

Update:

I got it working by using https://www.npmjs.com/package/parcel-plugin-externals (from https://github.com/parcel-bundler/parcel/issues/144#issuecomment-544297197)

yonkeltron commented 4 years ago

I can confirm that this still exists in 2.0.0-alpha.3.2, specifically with jQuery.

SeanBannister commented 4 years ago

Based on the solution presented by @reducm but I didn't want jQuery as a global and I had no need for it to be accesible at jQuery() only $() in which case you can use this:

import('jquery').then(async ($) => {
  // your code that uses jQuery
});
github-actions[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs.

MattFerzz commented 2 years ago

This issue is still happening on 2.6.2