I wrote a post yesterday that talked about:
Using Webpack with Angular CLI directly from official Github source
The post seemed to get a bit of traction on twitter, and among other feedback, I got an interesting question in a direct message:
Hi Meligy, Have you tried importing jQuery in Angular-CLI webpack branch project anytime??
Well, turns out I didn’t. I expected it to be just a
import ... line away. With Webpack, you often don’t need much more than that.
But then when I tried, I found a problem after another, which turned to be very specific to jQuery. It’s an edge case, but for the library the community size of jQuery, it’s worth showing:
A Working Configuration
First, install jQuery:
Then install jQuery typings:
Adding a test
Then you can modify
src/main.ts to include and test jQuery:
- Change the
bootstrap(AppComponent); line to:
You can go ahead and run
ng serve or
ng build -prod. I saw what looked like a TypeScript error in the output, so, go run just that:
You’ll get an error:
Explaining the problem
This error is because of a conflict between Angular Protractor and jQuery. Angular Protractor defines a global “$” that you use to write your Selenium element selectors nicer, etc. Normally you don’t write real jQuery code in a Selenium test, but Protractor is included in the TypeScript definitions that are included in the entire application.
Working around it
A temporary workaround is to manage the typings files for the website (
src folder) and End To End tests (
e2e folder) separately.
Each of the the folders have a
typings.d.ts file that has (possibly among other things), a typings reference to the root level
The problem is that the
typings/index.d.ts file looks like:
Now, we can’t have both
jQuery in the same file, but we cannot modify
typings/index.d.ts directly because every time we run
typings install, the file will be overridden (and many even add the
typings folder to .gitignore).
What we can do though, is replace the reference to it from
e2e/typings.d.ts. When we do, we need to account for path change, we’ll need to prefix the paths with
../typings/ to point to their correct location.
src/typings.d.ts, we replace the
../typings/index.d.ts reference line with:
e2e/typings.d.ts, we replace the
../typings/index.d.ts reference line with:
And that should be it. No errors n TypeScript compilation, and running
ng serve, then opening http://localhost:4200 shows us that the app still works, with the
bootstrap() call now executed from jQuery’s
ready call – which we added only to make sure it works!
ng build -prod and check the output in
dist. You’ll find that it also works well.
Remember, this is only a workaround!
A drawback of what we did is that every time we add typings for a new library using the typings command, we’ll have to add a reference to it manually in
e2e/typings.d.ts depending on fit. It’s easy to forget the manual step and get confused.
Luckily though, this is an edge case. Most of the libraries will not have such conflicts (see, that’s why everybody says modules are cool and globals are bad!). For most libraries, all you’ll need to do is to
import ... a module from the library, and everything will happen magically. Thanks to Webpack, you’ll not even need to setup vendor or systemjs config etc. Check my previous post for more information.
A few other starters seem to have the same problem. One other way to tackle it is to exclude the path
typings/globals/angular-protractor from the Webpack config, but currently, I can’t see this config exposed from the Angular CLI. I’m sure it’ll be there once it’s final etc., but it’s not there now.
Another idea is to have a
noConflict typings version of jQuery. There’s a pull request to DefinitelyTyped registry to include that, but it’s abandoned and closed at the moment. You can try calling the exact file via typings as a
github~ file not
dt~. But obviously you miss potential updates.
The best thing that can happen is that the Angular CLI would bring the separation of typings for
src code and
e2e tests built-in, which may or may not land in the CLI. Let’s see!
Should you use jQuery with Angular 2 at all?
I think the answer is: avoid it if you can.
I’m currently working with a team that has it included, and it was mostly due to needing some UI widgets that are only available for jQuery. I’m hoping that this is going to change with more UI widgets coming standalone, and easy to wrap in Angular 2 components / directives. Many widgets are becoming available with the Angular 2 wrappers already, like the lovely ng2-bootstrap collection.