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).
Related
I just want to ask how I can include popper.js in my bootstrap 5 using rollup compiler. Here is my rollup.config.js file . but It always said that "popper is not defined in my browser console . thanks
'use strict'
const path = require('path')
const { babel } = require('#rollup/plugin-babel')
const { nodeResolve } = require('#rollup/plugin-node-resolve')
import multi from '#rollup/plugin-multi-entry'
const banner = require('./banner.js')
let fileDest = 'child-theme.js'
const external = ['jquery','#popperjs/core']
const plugins = [
babel({
// Only transpile our source code
exclude: 'node_modules/**',
// Include the helpers in the bundle, at most one copy of each
babelHelpers: 'bundled'
}),
nodeResolve(),
multi()
]
const globals = {
jquery: 'jQuery', // Ensure we use jQuery which is always available even in noConflict mode
'#popperjs/core': 'Popper'
}
module.exports = {
input: [path.resolve(__dirname, '../js/bootstrap.js'), path.resolve(__dirname, '../js/skip-link-focus-fix.js'), path.resolve(__dirname, '../js/custom-javascript.js')],
output: {
banner,
file: path.resolve(__dirname, `../../js/${fileDest}`),
format: 'umd',
globals,
name: 'understrap'
},
external,
plugins
}
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.
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"
}),
]
}
Let's say that I have a node.js application, which does NOT go through my webpack bundling:
Node App
const Html = require('./build/ssr-bundle.js');
let result = Html.ssrbundle.render();
console.log(result);
Here is my ES6/JSX file, which is getting processed by webpack and I want to be able to access that render function in my node app (you guessed right, I am trying to SSR react stuff ;) )
src/Html.js -(webpack)-> build/ssr-bundle.js
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import CustomComponent from './custom-component.js';
module.exports = {
render : function () {
return ReactDOMServer.renderToString(<CustomComponent />);
} };
And here is my Webpack config
webpack.config.js
var path = require('path');
module.exports = {
entry: {
ssr: './src/Html.js',
//frontend: './src/frontend-Html.js'
},
output: {
path: path.resolve(__dirname, 'build'),
filename: 'ssr-bundle.js',
library: 'ssrbundle'
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
query: {
presets: ['env','react'],
plugins: ["transform-es2015-destructuring", "transform-object-rest-spread"]
}
},
{
test:/\.css$/,
use:['style-loader','css-loader']
}
]
},
stats: {
colors: true
},
devtool: 'source-map'
};
Whatever I do, I cannot figure out how to properly use that exported variable "ssrbundle" and subsequently the render function. If I had my node app included in the bundle, everything would be all right, but this is not what I want to do.
As apokryfos suggested, I played around with the libraryTarget Webpack setting. You can find more info on using Webpack to author a library (what I was really trying to achieve) here:
https://webpack.js.org/guides/author-libraries/
and here are code examples:
https://github.com/kalcifer/webpack-library-example/blob/master/webpack.config.babel.js.
What did the trick for me, was to set the libraryTarget to "umd" , which is different than the "var" setting which is set by default and is suitable i.e. for including the script in an HTML file
I'm new to Django and ReactJS, was trying to compile a simple JSX code to JS using this tutorial : http://geezhawk.github.io/2016/02/02/using-react-with-django-rest-framework.html
Didn't work, so I used npm run dev to compile, now it worked but giving error in browser console : Uncaught ReferenceError: react is not defined
Here is my webpack.config.js
var path = require('path');
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');
var nodeExternals = require('webpack-node-externals');
module.exports = {
//the base directory (absolute path) for resolving the entry option
context: __dirname,
//the entry point we created earlier. Note that './' means
//your current directory. You don't have to specify the extension now,
//because you will specify extensions later in the `resolve` section
entry: './assets/js/index',
output: {
//where you want your compiled bundle to be stored
path: path.resolve('./assets/bundles/'),
//naming convention webpack should use for your files
filename: '[name]-[hash].js',
},
target: 'node', // in order to ignore built-in modules like path, fs, etc.
externals: {
react: 'react'
}, // in order to ignore all modules in node_modules folder
plugins: [
//tells webpack where to store data about your bundles.
new BundleTracker({filename: './webpack-stats.json'}),
//makes jQuery available in every module
new webpack.ProvidePlugin({
//React: "react",
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
})
],
module: {
loaders: [
//a regexp that tells webpack use the following loaders on all
//.js and .jsx files
{test: /\.jsx?$/,
//we definitely don't want babel to transpile all the files in
//node_modules. That would take a long time.
/*exclude: /node_modules/,*/
//use the babel loader
loader: 'babel-loader',
query: {
//specify that we will be dealing with React code
presets: ['react']
}
}
]
},
resolve: {
//tells webpack where to look for modules
modulesDirectories: ['node_modules'],
//extensions that should be used to resolve modules
extensions: ['', '.js', '.jsx']
}
}
And assets/bundles/index.js
var React = require('react')
var ReactDOM = require('react-dom')
//snaha//
var BooksList = React.createClass({
loadBooksFromServer: function(){
console.log(123454657);
$.ajax({
url: this.props.url,
datatype: 'json',
cache: false,
success: function(data) {
this.setState({data: data});
}.bind(this)
})
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadBooksFromServer();
setInterval(this.loadBooksFromServer,
this.props.pollInterval)
},
render: function() {
if (this.state.data) {
console.log('DATA!')
var bookNodes = this.state.data.map(function(book){
return <li> {book.title} </li>
})
}
return (
<div>
<h1>Hello React!</h1>
<ul>
{bookNodes}
</ul>
</div>
)
}
})
ReactDOM.render(<BooksList url='/api/' pollInterval={1000} />,
document.getElementById('container'))
And templates/body.html
{% load render_bundle from webpack_loader %}
<!doctype html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-with-addons.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-dom.js"></script>
<meta charset="UTF-8">
<title>Hello React
{% block content %}
{{ id }}
{% endblock %}
</title>
</head>
<body>
<div id="container"></div>
{% render_bundle 'main' %}
</body>
</html>
Anything I'm missing? here is my Django project structure
Finally I've solved it!
Problem was : it was trying to get variable react where as React.js on browser was providing variable React!
So I simple change of externals of webpack.config.js to
externals: {
React: 'react'
},
solved the issue!
Next Problem Faced :
"process was not defined"
Solution : added
var env = process.env.WEBPACK_ENV;
to top of webpack.config.js
and
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"'
}),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': '"production"'
}
})
into the plugins part of model.export
So Final webpack.config.js would be :
var path = require('path');
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');
var nodeExternals = require('webpack-node-externals');
var env = process.env.WEBPACK_ENV;
module.exports = {
//the base directory (absolute path) for resolving the entry option
context: __dirname,
//the entry point we created earlier. Note that './' means
//your current directory. You don't have to specify the extension now,
//because you will specify extensions later in the `resolve` section
entry: './assets/js/index',
output: {
//where you want your compiled bundle to be stored
path: path.resolve('./assets/bundles/'),
//naming convention webpack should use for your files
filename: '[name]-[hash].js',
},
target: 'node', // in order to ignore built-in modules like path, fs, etc.
externals: {
React: 'react'
}, // in order to ignore all modules in node_modules folder
plugins: [
//tells webpack where to store data about your bundles.
new BundleTracker({filename: './webpack-stats.json'}),
//makes jQuery available in every module
new webpack.ProvidePlugin({
//React: "react",
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"'
}),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': '"production"'
}
})
],
module: {
loaders: [
//a regexp that tells webpack use the following loaders on all
//.js and .jsx files
{test: /\.jsx?$/,
//we definitely don't want babel to transpile all the files in
//node_modules. That would take a long time.
/*exclude: /node_modules/,*/
//use the babel loader
loader: 'babel-loader',
query: {
//specify that we will be dealing with React code
presets: ['react']
}
}
]
},
resolve: {
//tells webpack where to look for modules
modulesDirectories: ['node_modules'],
//extensions that should be used to resolve modules
extensions: ['', '.js', '.jsx']
}
}
Now Enjoy React! Happy Coding :-)
Can you look if you have all the requirements installed.
Look inside package.json. You should have react noted in requirements if you do run.
npm install
If you don't, then run
npm install react --save
ps: in my option if you are running Webpack try to add babel to Webpack presets and write javascript in ES2015 specification.