Search code examples
javascriptjquerytypescriptbootstrap-4parceljs

using parcel to pull in typescript dependencies


I'm using parcel to process typescript for a webextension. JQuery and its type definitions are installed via npm. At the top of my typescript file I have:

import $ from "jquery";
import "bootstrap";

But at runtime, Chrome complains that jquery is not defined. A minimal example to reproduce the problem is on git: https://github.com/lhk/parcel_jquery_bug_demo

git clone https://github.com/lhk/parcel_jquery_bug_demo
cd parcel_jquery_bug_demo
npm install
parcel build src/manifest.json

Now you can open chrome and load the dist folder

The git repo contains:

src/manifest.json

{
  "manifest_version": 2,
  "name": "pc",
  "version": "0.0.1",
  "description": "none",
  "author": "",
  "content_security_policy":"script-src 'self'; object-src 'self'",
  "content_scripts": [
    {
        "matches": ["<all_urls>"],
        "js": [
         "./content/index.ts"]
    }
  ]
}

src/content/index.ts

import $ from "jquery";
import "bootstrap";

$(function () {
  $('[data-toggle="popover"]').popover();
});

./package.json

{
  "name": "pc",
  "version": "0.1.0",
  "description": "",
  "author": "",
  "license": "",
  "devDependencies": {
    "parcel-plugin-web-extension": "^1.4.0",
    "typescript": "^3.1.3"
  },
  "dependencies": {
    "@types/bootstrap": "^3.3.7",
    "@types/jquery": "^3.3.10",
    "bootstrap": "^3.3.7",
    "jquery": "^3.3.1"
  }
}

After you loaded the extension in chrome, you can load any website. The error message is:

Uncaught ReferenceError: jQuery is not defined

I'm using:

  • Parcel 1.10.1
  • Node v8.12.0
  • npm 6.4.1
  • ubuntu 18.04.1 64bit
  • chrome 70

I think this problem is related to the import of bootstrap. The following code works:

import $ from "jquery";

//import "bootstrap";

$(function () {
  //$('[data-toggle="popover"]').popover();
  $('[data-toggle="popover"]').click(function(){});
});

So the dependency of my typescript code is actually handled by parcel. But bootstrap also needs jQuery and that is somehow not satisfied.


Solution

  • Parcel actually takes no part in the issue, it is mostly that jQuery/Bootstrap relies on the $ and jQuery function being exposed in the global scope.

    This is fairly simple to archive by doing the following (for JS only, since TS will complain about window not having the property $ and jQuery):

    import jquery from "jquery";
    window.$ = window.jQuery = jquery;
    import "bootstrap";
    

    But since you're using TypeScript you will need to do more in order to get the linting and intellisense support working too.

    1. Install the TypeScript definition file npm install --save-dev @types/jquery @types/bootstrap
    2. use import * as $ from 'jquery'; to import it.
    3. Configure the libs for the DOM api since they are not enable by default for TypeScript, this will allow you to use a proper window and document but you need to change window to (<any> window)

      tsconfig.json

      {
        "compilerOptions": {
          //...
          "lib": ["dom"],
          //...
        },
      }