Make webpack include a global jquery plugin in the bundle - javascript

I'm working with an older ui library that requires their ui components be extensions of jQuery. We have some files that extend their ui components. These files need to be run in the global context before the main logic of the app starts up.
Here's the index.js file:
import $ from "jquery";
import '#progress/kendo-ui';
document.addEventListener('DOMContentLoaded', () => {
$('#main').kendoTelephone();
window.jquery = $;
});
here's the file that makes the kendoTelephone extension:
import '#progress/kendo-ui';
const Telephone = kendo.ui.MaskedTextBox.extend( {
init: function(element, options) {
options || (options = {});
options.mask = "(000) 000-0000";
kendo.ui.MaskedTextBox.fn.init.call(this, element, options);
},
options: Object.assign( {}, kendo.ui.MaskedTextBox.prototype.options, {
name: 'Telephone'
} ),
});
kendo.ui.plugin(Telephone);
export default Telephone;
How do I make it so that webpack will:
1. Include the telephone extension file in the bundle
2. and bundle it in such a way that it runs in the global context
Here's my webpack config:
{
entry: {
index: './src/index.js',
},
mode: 'development',
output: { path: __dirname, filename: 'bundle.js' },
devtool: 'cheap-module-eval-source-map',
module: {
rules: [
{
test: require.resolve('./src/telephone.js'),
use: ['script-loader']
}]
},
plugins: [
new wp.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
}),
]
}

Related

Custom jQuery extensions/plugin not found when using webpack

I am trying to migrate an old project to use webpack. I wrote some custom plugins which not don't work anymore. Though I think this problem shoud have occured to somebody else, I couldn't find any post about it.
Here is my base.js containing:
(function ($) {
$.fn.my_extension = function () {
alert("I am found!");
};
}(jQuery));
That's how I use it in my template:
<script type="text/javascript">
$(document).ready(function() {
$('#my-id').my_extension();
});
</script>
Here's my include in my index.js:
// JS Dependencies
import 'jquery';
...
// Custom JS
import '../js/base.js';
And here is my webpack.config.js:
var path = require('path');
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');
module.exports = {
context: __dirname,
mode: 'development',
entry: './static/js/index.js',
output: {
path: path.resolve('./static/webpack_bundles/'),
filename: "[name]-[hash].js"
},
module: {
rules: [
{
test: require.resolve('jquery'),
use: [{
loader: 'expose-loader',
options: 'jQuery'
}, {
loader: 'expose-loader',
options: '$'
}]
},
...
],
},
plugins: [
new BundleTracker({filename: 'webpack-stats.json'}),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
'window.jQuery': 'jquery'
})]
}
And here's the error I get when calling the template:
TypeError: $(...).my_extension is not a function
Any ideas what I might be doing wrong?
After trying different approaches for ages, I figured out that the registration works but jQuery is not the same instance, when I use it in my template.
What solved my problem was finally adding this line to my base.js.
require('jquery');
I'm not 100% sure but I guess the expose-loader is recognizing this import and creating the global scope for it.

React : You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file(Local Node module)

I have babel loader in the library. Still after I add the library to the react application while yarn serve, I get the above error.
This is the webpack.dev.config.js (required in the webpack.config.js) in library-
//webpack.dev.config.js
const babelRCPath = require('#appfabric/infra-scripts').getConfigPath('babel', 'plugin');
const babelRCGenerator = require(babelRCPath);
const babelRC = babelRCGenerator([]);
module.exports = {
{
BaseModule: `${process.cwd()}/src/BaseModule`,
BaseObject: `${process.cwd()}/src/BaseObject`,
BaseWidget: `${process.cwd()}/src/widgets/BaseWidget`,
HOCWidget: `${process.cwd()}/src/widgets/HOCWidget`,
PortalWidget: `${process.cwd()}/src/widgets/PortalWidget`,
BaseActivator: `${process.cwd()}/src/application/BaseActivator`,
CorePlugin: `${process.cwd()}/src/application/CorePlugin`,
BaseAppDelegate: `${process.cwd()}/src/application/appdelegates/BaseAppDelegate`,
EmbeddedAppDelegate: `${process.cwd()}/src/default/appdelegates/embedded/EmbeddedAppDelegate`,
ActionType: `${process.cwd()}/src/application/appdelegates/actions/ActionType`,
types: `${process.cwd()}/src/application/appdelegates/actions/types`,
CommandActionType: `${process.cwd()}/src/application/appdelegates/actions/CommandActionType`,
CommandForResponseActionType: `${process.cwd()}/src/application/appdelegates/actions/CommandForResponseActionType`,
PluginRegistryService: `${process.cwd()}/src/default/PluginRegistryService`,
},
mode: 'development',
externals: [
'dcl',
'react',
'react-dom',
'prop-types',
'pubsub',
'semver',
'#appfabric/ui-profiler',
].map(
// Add this regex to each entry to ensure we don't miss any imports like 'web-shell-core/...`
(value) => new RegExp(`^(${value})((\\\\|/|!).+)?$`),
),
output: {
path: `${process.cwd()}/build/dist`,
filename: '[name].js',
library: 'web-shell-core',
libraryTarget: 'umd',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: {
loader: 'babel-loader',
options: babelRC,
},
},
],
},
};
This is the webpack.config.js
const developmentConfig = require('./webpack.dev.config.js');
module.exports = merge(developmentConfig, {
mode: 'production',
output: {
filename: '[name].min.js',
chunkFilename: '[name].min.js',
},
});
First I add a new file Secure.jsx(having the tags) in the library. I do npm install --save <path-to-library> on my application. After I do yarn install. Then I can see the new file Secure.jsx in the node modules in the application. When I try to run the application, I get the error.
Please let me know what am I missing and also which side(library / application) I have to add the code.
You can view my full config here
I think you also need to add this
resolve: {
modules: [
path.resolve('./node_modules')
]
},
Then import like this
import "jquery/dist/jquery.min.js";
import "bootstrap/dist/js/bootstrap.min.js";

How to Access jQuery Plugin From A Separate Webpack Bundle

I'm bundling JS and CSS (compiled from SCSS) into two separate bundles, one for 3rd party (vendor) and one for the project code (company). I'm able to access jQuery via $ successfully from scripts in the company bundle as a global, such as from some-other-script.js, without any issues. However when trying to call the stickyTableHeaders function from the StickyTableHeaders plugin in table-headers.js: Uncaught TypeError: $(...).stickyTableHeaders is not a function. I don't get any other errors about loading scripts etc. and I can see that vendor.bundle.js includes the plugin code.
Additionally I see from the bottom of the plugin source that the function is meant to be added to $ as follows:
$.fn[name] = function ( options ) {
return this.each(function () {
var instance = $.data(this, 'plugin_' + name);
if (instance) {
if (typeof options === 'string') {
instance[options].apply(instance);
} else {
instance.updateOptions(options);
}
} else if(options !== 'destroy') {
$.data(this, 'plugin_' + name, new Plugin( this, options ));
}
});
};
Any ideas why it can't find the function on the $ (jQuery) object?
This question seems similar, however the poster was having trouble with the plugin not being able to find jQuery in that case. Additionally I'm not sure if using the import-loader as per one of the suggestions is the right approach in my case, or if I'm doing something fundamentally wrong. You can see commented out lines in the webpack.config.js below where I've tried to register sticky-table-headers as a plugin with webpack without success - same result.
My webpack.config.js is as follows:
var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var extractSass = new ExtractTextPlugin({
filename: "[name].bundle.css",
disable: process.env.NODE_ENV === "development"
});
module.exports = function (env) {
env = env || {};
var isProd = env.NODE_ENV === 'production';
// Setup base config for all environments
var config = {
entry: {
vendor: './Client/js/vendor',
company: './Client/js/company' // Includes all SCSS, which ends up in company.bundle.css via extract-text-webpack-plugin.
},
output: {
// ReSharper disable once UseOfImplicitGlobalInFunctionScope
path: path.join(__dirname, 'wwwroot/dist'),
filename: '[name].bundle.js'
},
devtool: 'eval-source-map',
mode: "development",
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
alias: {
"jquery.validation": "jquery-validation/dist/jquery.validate.js",
//"sticky-table-headers": "sticky-table-headers/js/jquery.stickytableheaders.js"
}
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
Popper: ['popper.js', 'default'],
//"sticky-table-headers": ["sticky-table-headers", "default"]
}),
extractSass
],
module: {
rules: [
{
test: /\.scss$/,
use: extractSass.extract({
use: [{
loader: "css-loader"
}, {
loader: "sass-loader"
}],
// use style-loader in development
fallback: "style-loader"
})
}
]
}
}
// Alter config for prod environment
if (isProd) {
config.devtool = 'source-map'; // SourceMap emitted as a separate file.
//Normally disallow access on webserver or use (none) instead. Internal
//app so leaving them accessible for easier support.
config.mode = "production";
}
return config;
};
Then in vendor.js I have:
import 'jquery';
import 'popper.js';
import 'bootstrap';
import "jquery-validation";
import "jquery-validation-unobtrusive";
import "sticky-table-headers";
In company.js I have:
import '../scss/site.scss';
import './site';
import './some-other-script';
import './table-headers';
Finally in table-headers.js I have:
(function () {
$(function () {
if ($(".my-sticky-table-header").length === 0) return;
var offset = $('.navbar').height();
$(".my-sticky-table-header").stickyTableHeaders({
fixedOffset:offset});
});
})();
Thanks.
Looks like there was a fundamental flaw with this setup. I ended up adding:
import './vendor';
to the top of company.js and then using the SplitChunks plugin mentioned here to avoid everything in the vendor bundle being duplicated. This allowed library functions to be called from the company bundle.
(Something like this may have worked but it seems messy).

Webpack 2 can't find jquery autocomplete module

I have the following webpack config file:
const path = require('path');
const config = {
output: {
filename: '[name].bundle.js',
path: 'assets'
},
resolve: {
modules: [
'./js',
'./js/jquery'
],
alias: {
'jquery': 'jquery/jquery-1.10.2.js',
'jquery-ui': 'jquery/jquery-ui.js'
}
},
entry: {
settings : './js/model/settings.js'
}
};
module.exports = config;
On every build webpack ends with an error "Error: Can't resolve 'jquery-ui/autocomplete'" but jquery autocomplete is included in jquery ui. What is missing?

ES6 import of AMD (e.g. jQuery 3.1.1) module in webpack 2

I'm doing some testing with the latest and greatest webpack 2 version and came across a problem when trying to import jQuery 3.1.1 as a dependency.
I simply used import {$} from 'jquery'; to import but the resulting bundle generated an exception TypeError: __webpack_require__.i(...) is not a function when executed.
Using const $ = require('jquery'); works as expected.
It was my understanding that with webpack 2 I'm allowed to use es6 imports (almost) independently of the format of the library.
webpack.config.js:
'use strict';
const path = require('path');
const webpack = require('webpack');
function config(env) {
const PRODUCTION = env && typeof env.production !== 'undefined';
const PLUGINS = [
new webpack.DefinePlugin({
DEVELOPMENT: JSON.stringify(!PRODUCTION),
PRODUCTION: JSON.stringify(PRODUCTION)
})
];
if (PRODUCTION) {
PLUGINS.push(new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
dead_code: true,
unused: true,
}
}));
}
return {
entry: {
index: './src/index.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.js$/i,
include: /src/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
compact: false,
presets: [['es2015', {modules: false}]]
}
}
]
}
]
},
plugins: PLUGINS,
devtool: 'source-map'
};
}
module.exports = config;
Two questions:
Is this a bug or just not intended to work as I would expect it?
What error does the exception TypeError: __webpack_require__.i(...) is not a function generally indicate?
My mistake: I've used a named import instead of the default import.
Correct:
import $ from 'jquery';
Wrong:
import {$} from 'jquery';

Categories