I'm trying out Webpack for the first time on one of my old website. The website has JQuery installed via CDN.
On one of my js file, I need to have Fancybox js plugin so I import as below
import { fancybox } from "#fancyapps/fancybox";
import "#fancyapps/fancybox/dist/jquery.fancybox.min.css";
I executed "npm run dev" and webpack gave me error "Can't resolve "jquery". So I have to include Jquery as a plugin in my webpack.config.js as follow
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery",
}),
],
Execute "npm run dev" again and it works as expected. My question is how to avoid duplicate jquery loading since the website template already include JQuery via CDN and now my webpack output file also include JQuery? I tried to remove the Jquery CDN but then it caused my other js files to break. Thanks.
I found the solution to my issue. Adding it here for anyone who has similar issue in the future. Instead of importing jquery into webpack, I set webpack config to use external jquery as follow
externals: {
jquery: "jQuery",
},
Related
I'm setting up a project (typescript, webpack) with a couple of js libraries, configured as externals in webpack. They should not be part of the bundle, instead provided by script tags within the html.
But when trying to use them in my class, they resolve to undefined.
Fabric configured as an external in webpack is resolving to undefined
An error occurs when trying to set up the fabric js library as an external within a (typescript + webpack ) project. Fabric should not be bundled in the output file since it will be the responsibility of the consumer to provide (eg. through a browser script tag).
Note: jQuery initially had an issue (as an external) but is now resolved, and works as expected. Fabric on the other hand does not.
fabric has been configured as an external so that it will not be included in the webpack bundle.
Here's how...
Added as an external within the webpack.config.js
...
externals: {
jquery: 'jQuery',
fabric: 'fabric',
},
...
Installed the declaration files for both libraries
npm install #types/jquery -D
npm install #types/fabric -D
Added the libraries in public folder and index.html (since they must not be part of the app bundle)
<script src="js/lib/jquery.min.js"></script>
<script src="js/lib/fabric.min.js"></script>
Created a class App.ts, imported and implemented instances of these two libraries. (see App.ts)
import { fabric } from "fabric";
import $ from 'jquery';
fabric resolves to undefined within the class App.ts with the error:
TypeError: Cannot read property 'Canvas' of undefined
Please don't recommend ProvidePlugin or installing Babel.
More about webpack "externals": https://webpack.js.org/configuration/externals/
Update #1
jQuery is now working as an external library. I was not referencing the actual jquery global "jQuery" in the externals setup. I had "JQuery" (with a capital J). That's now resolved and jquery is working. Thanks #Aluan
Fabric on the other hand seems to be a different issue altogether.
What you're looking for is called shimming. Webpack docs cover this extensively here: https://webpack.js.org/guides/shimming/
Edit to add example:
In your webpack.config.js plugins array:
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
]
EDIT:
I pulled down your code and got it working. Here are the steps:
ts-loader chokes on shims, so use babel's #babel/preset-typescript -- otherwise you'll need to find a way to tell the ts compiler to ignore them. This will get you started:
npm install --save-dev #babel/core #babel/cli #babel/preset-env #babel/preset-typescript core-js#3
In your root, create a file called .babelrc and add the following:
{
"presets": [
"#babel/preset-typescript",
[
"#babel/env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
"useBuiltIns": "usage",
"corejs": "3"
}
]
]
}
Add this to your webpack.config.js:
plugins: [
new ProvidePlugin({
$: "jquery",
jQuery: "jquery",
fabric: "fabric"
})
]
Also update ts-loader, changing it to babel-loader.
Now in your code, you'll need to prefix your shimmed libraries with window:
constructor(private readonly selector: string, canvasHeight: number, canvasWidth: number) {
window.$(`#${selector}`).replaceWith(`<canvas id="${selector}" height=${canvasHeight} width=${canvasWidth}> </canvas>`);
this.canvas = new window.fabric.Canvas(`${selector}`, { selection: false });
}
It turns out that the issue with fabric is from fabric itself! The reason fabric is resolving to undefined (when being configured as an external on webpack) is related to the way that fabric exposes its library for consumption. It's an issue they need to fix.
I've added an issue on the official fabric github page
But there is a quick solution for us. Just import using CommonJS like this:
const fabric = require('fabric');
Now it works!
I want to add (https://selectize.github.io/selectize.js/ to my Rails Webpack application.
I have done the following:
Run: npm install selectize --save from terminal.
Gone to my pack's index.js and imported it with: import 'selectize/dist/js/selectize';
And When I open the compiled application.js I can search for "selectize" - but when I try this in my javascript (or via console):
$('#list').selectize({
delimiter: ','
});
It tells me Uncaught TypeError: $(...).selectize is not a function.
I know that I had to add some stuff to config/webpack/environment.js to get jQuery working, do I have to do something to get this library working? If so, what have I missed?
use jquery as plugin in webpack to automatically.Here you will find the documentation.
you have to make some changes in webpack.config.js file.
plugins: [
new webpack.ProvidePlugin({$: 'jquery',jQuery: 'jquery'})]
npm i jquery and you can import and try with this hope this help for u.
import jquery from "jquery";
new webpack.ProvidePlugin({
$: jquery,
jQuery: jquery
});
The following Github issue addresses your question: https://github.com/selectize/selectize.js/issues/1421. This is a problem with the selectize library breaking when imported through webpack. A temporary solution for this is to just manually import the library.
How to include third party jQuery library in Angular 2 application?
How to include http://keith-wood.name/calendarspicker.html jQuery library in angular 2 application?
1-In addition to install it through npm , try to include this line in your angular-cli.json file, inside apps->scripts key like this example:
{
"apps": {
"scripts": [
"../node_modules/jquery/dist/jquery.min.js"
]
}
}
2-Add this plugin to your webpack plugins in webpack.config.js (in module.exports):
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
3- Then import it in the component you need to use it, for example:
import * as $ from 'jquery';
To add an external library to an Angular 2 app you download the files and place them in your assets folder (or any folder you may chose to add) angular/src/assets/<your-library> then add the path to the library in your angular-cli.json file. If you upgrade to angular 6 the file is renamed angular.json
Here is an example of one of my angular-cli.json files
"styles": [
"../node_modules/materialize-css/dist/css/materialize.css",
"../node_modules/font-awesome/css/font-awesome.min.css",
"styles.css"
],
"scripts": [
"../node_modules/jquery/dist/jquery.js",
"../node_modules/jqueryui/jquery-ui.js",
"../node_modules/materialize-css/dist/js/materialize.js",
"./assets/RTCMultiConnection.min.js",
"../node_modules/hammerjs/hammer.js",
"./assets/popup.js"
],
It may, however be easier to add an "angular ready" alternative like angular-bootstrap-calendar
I am trying to make a jQuery plugin accessible to inline JavaScript using Webpack 4.
I am using the PluginProvider to make jQuery available to my website:
plugins: [
new webpack.ProvidePlugin({
"$": "jquery",
"jQuery": "jquery"
}),
],
This is working fine and I can access jQuery from any page that includes my bundle.
I tried to add bootstrap-datepicker by creating a bundle called vendor.js with the following contents:
import 'bootstrap-datepicker';
I can call $('input').datepicker() from within the vendor.js bundle, however if I try and call it using an inline <script> I get:
Uncaught TypeError: $(...).datepicker is not a function
How can I configure Webpack 4 to make bootstrap-datepicker available to the global scope?
UPDATE
I've uploaded the sourcecode demonstrating this issue here: https://github.com/LondonAppDev/webpack-global-jquery-issue
It appears the issue is that the second bundle import is re-adding jQuery without the datpicker add-on. Is there a way around this?
I've gone a few rounds with this type of issue and had the most success with the expose-loader. In your webpack config you should set up a section for jQuery using the following expose loader configuration:
module.exports = {
module: {
rules: [
{
test: require.resolve('jquery'),
use: [{
loader: 'expose-loader',
options: 'jQuery'
}, {
loader: 'expose-loader',
options: '$'
}]
},
...
]
}
}
There is a similar SO posts here:
How to import jquery in webpack (their regex pattern did not work for me)
Expose jQuery to real Window object with Webpack
Webpack 2 loading, exposing, and bundling jquery and bootstrap
You should be able to find several other articles/posts using this configuration, it is the only one that I have successfully been able to get to work to date.
Also of note, bootstrap 4 seems to also load or do a require on jQuery internally, so if you include an import or require after your jQuery import/require and plugins, it will reinit jQuery and cause your plugins to lose scope.
I'm using webpack as my bundler/loader and I can load materialize css in fine (js/css), but when I try to use the toast, it says
Uncaught TypeError: Vel is not a function
I am including the library in the main index.js file by:
import 'materialize-css/bin/materialize.css'
import 'materialize-css/bin/materialize.js'
Does anyone know why this could be happening? Looking at the bundled source, the js for materialize is there.
Had a same problem & came up with somewhat simpler solution:
Only 2 things are needed to be done:
First: Import following in you root module like app.js
//given you have installed materialize-css with npm/yarn
import "materialize-css";
import 'materialize-css/js/toasts';
Second: if webpack, set following Plugin or get the velocity.min.js as global variable just like you would use jquery:
new webpack.ProvidePlugin({
"$": "jquery",
"jQuery': "jquery",
"Vel": "materialize-css/js/velocity.min.js"
}),
I'm also trying to use materialize-css with webpack and have also run into this issue (albeit not for the same reason). Materialize isn't really built with a module loader in mind, and use global variables. They also bundle dependencies into their script directly in a way you might not want in a webpack-workflow.
I have a setup not exactly the same as you but I'll share it anyways, hoping it will help, my webpack+materialize works like this in a file i've created;
/**
* custom-materialize.js
*/
// a scss file where we include the parts I use.
require('./custom-materialize.scss');
/**
* materialize script includes
* we don't use all the plugins so no need to
* include them in our package.
*/
require('materialize-css/js/initial');
require('materialize-css/js/jquery.easing.1.3');
require('materialize-css/js/animation');
// note: we take these from npm instead.
//require('materialize-css/js/velocity.min');
//require('materialize-css/js/hammer.min');
//require('materialize-css/js/jquery.hammer');
require('materialize-css/js/global');
//require('materialize-css/js/collapsible');
require('materialize-css/js/dropdown');
Then just install Velocity from npm npm install velocity-animate
and point the global Vel materialize use to that package instead in webpack.
new webpack.ProvidePlugin({
'$': 'jquery',
'jQuery': 'jquery',
'Vel': 'velocity-animate'
}),
you have to import css and js Files separately in your index.html
you must not import css file in index.js
Make sure that the uglifyJsPlugin is like this.
new webpack.optimize.UglifyJsPlugin({sourceMap: true, mangle: false})
mangle property should be false so that the variable names of your source file doesn't change when you minify.