Using velocity with jquery for IE8 in ES6 - javascript

I am trying to use velocity together with jQuery (only for IE8 support) in an ES6 module. Consider this code:
import { Component } from 'react';
import ReactDOM from 'react-dom';
import jquery from 'jquery';
import velocity from 'velocity-animate';
export default class ScrollTo extends Component {
render() {...}
scrollToTop() {
velocity(ReactDOM.findDOMNode(this), 'scroll', { container: ReactDOM.findDOMNode(this.props.container) });
}
In IE8 velocity complains it cannot find jQuery. I checked in the source and it looks like velocity looks for jQuery on the window object but I'm importing it as a module.
Is there a way to instantiate/bind velocity with the imported jquery?

you can use ShimPlugin to shim jquery with webpack
see:
https://github.com/webpack/webpack/issues/192
or use ProvidePlugin to expose jquery to window, so that you don't have to import jquery every time you need it.
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
plugin ProvidePlugin This plugin makes a module available as variable
in every module. The module is required only if you use the variable.
Example: Make $ and jQuery available in every module without writing
require("jquery").

Related

React: Import Js with from and curly braces part

I am currently thinking of using "fabric-webpack" and looking at the demo using react "https://codesandbox.io/s/8k7kvwqx70?file=/src/index.js"
I under import { ... } from '....'
But not sure how this work if typing like this
import 'fabric-webpack'
You need to use import { fabric } from "fabric"; as shown here
The demo imports globally the library, that attaches the interface to window, window.fabric

Build module to use it in environment without modules

Our application uses TypeScript's namespaces and do not use any kind of modules. We want to use react-datepicker, which is written using modules.
For example, it contains the next code:
import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import onClickOutside from 'react-onclickoutside';
import moment from 'moment';
import { Manager, Popper, Target } from 'react-popper';
...
export default DatePicker;
Or transpiled:
var React = _interopDefault(require('react'));
var PropTypes = _interopDefault(require('prop-types'));
var classnames = _interopDefault(require('classnames'));
var onClickOutside = _interopDefault(require('react-onclickoutside'));
var moment = _interopDefault(require('moment'));
var reactPopper = require('react-popper');
...
exports['default'] = DatePicker;
It is required to build some js-bundle for this package, that will contain react-datepicker itself as global variable DatePicker, and all its dependecies, besides react, moment, classnames.
These libraries are already added to the application as global variables (React, moment, classNames), so it should use these global variables.
Is there some plugins and techniques for rollup, webpack, etc. that can help to build such bundle?
You can achieve this with rollup, you would need to use its external and globals option like this:
external: ['react', 'react-dom', 'moment', 'classnames'],
globals: {
'react': 'React',
'react-dom': 'ReactDOM',
'classnames': 'classNames',
'moment': 'moment'
},
Depending on the source file you're using, you might need to use these 2 plugins:
import commonjs from "rollup-plugin-commonjs";
import resolve from 'rollup-plugin-node-resolve';
Also, you might need to use rollup-plugin-replace because react-datepicker seems to include process.env.NODE_ENV in its code, and you will need to remove that.
In case you would like to see a full working example, check this repo I created:
https://github.com/mxcoder/rollup-iife-react-datepicker

React - '$' is not defined

I have a React Redux application. Im adding materialize as the CSS framework, but materialize requires jquery. So i installed Jquery and added it to my project via npm. If i import jquery like so
import $ from 'jquery';
No errors are thrown and im able to use it. But only on that component. So i added the wepback plug so i can call $ anymore in my react application. However, when i do this as described on webpacks website, it get the following error.
Line 13: '$' is not defined
Any ideas on why this is ?
app.js
import React from 'react';
import '../styles/index.css';
import Header from './header/Header';
class App extends React.Component {
constructor(props){
super(props);
console.log('Application ready');
}
componentWillMount(){
$('ul.tabs').tabs();
}
render = () => (
<div>
<Header />
<div>
{this.props.children}
</div>
</div>
)
}
export default App;
webpack.config.dev.js
alias: {
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web',
jquery: "jquery/src/jquery" // What i added
// $: "jquery/src/jquery"
},
jquery is in the node_modules folder, from the npm install, i didnt add it to any other location.
You've aliased jQuery to the global variable jQuery, not $ - do alias: { $: 'jquery' }.
Wrong, this isn't what alias is for, see https://webpack.js.org/configuration/resolve/
Global variables in (browser) JS are really properties of window. So at the start of your script you could do
import $ from 'jquery';
window.$ = $;
and it'd be available globally after that. Including jQuery in its own <script> tag would do the same thing. But these are both un-webpack, a bit naughty, not modular. The 'correct' thing to do is import $ from 'jquery' in every file where you need it. Yeah this will be tedious if you need it in a lot of places, but it means you know where you need jQuery and where you don't, and if you removed all the components that used jQuery, jQuery would disappear as well.
To add on for Gatsby.js you can npm i jquery and then import jquery in gatsby-browser.js.
import 'jquery/dist/jquery.min';
import 'popper.js/dist/popper.min'; // for navbar animation
import 'bootstrap/dist/js/bootstrap.min';
import $ from 'jquery'; in the relevant files will then detect $

How can import jQuery UI using ES6 syntax and browserify?

I am trying to import JQuery and JQuery into a project using ES6 syntax using Babel and Browserify to package the code. From what I have been able to figure out the problem is that JQuery UI expects jQuery to be defined as a global variable. I tried setting the global variable after importing jQuery and before importing JQuery UI like this:
import { default as $, default as jQuery} from 'jquery';
wiindow.jQuery = jQuery;
window.$ = $;
import 'jquery-ui';
but it seems browserify puts all imports at the top of the file, so the globals are defined too late. I understand that webpack provides a way to define globals but is there a workaround for browserify?
Try this
window.$ = window.jQuery = import $ from "jquery";
or
import { default as $, default as jQuery} from 'jquery';
window.jQuery = windows.$ = jQuery;

Can I use an ES6/2015 module import to set a reference in 'global' scope?

I have this situation where I am trying to import an existing library, which I'll call troublesome (using Webpack/Babel FWIW) and it has a global reference to jQuery in it which i am trying to resolve using module syntax.
I have successfully imported jquery into the 'local' scope of a module, via:
import jQuery from 'jquery'
so I tried:
import jQuery from 'jquery'
import 'troublesome'
but perhaps not surprisingly, I get something like jQuery is not a function kicked back from troublesome.js
I have tried this as well:
System.import('jquery')
.then(jQuery => {
window.jQuery = jQuery
})
import 'troublesome'
but, it turns out that System.import is part of the, so-called, 'module-loader' spec, which was pulled from the es6/2015 spec, so it isn't provided by Babel. There is a poly-fill, but Webpack wouldn't be able to manage dynamic imports accomplished via calls to System.import anyway.
but... if I call out the script files in index.html like so:
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/troublesome/troublesome.js"></script>
<script src="the-rest-of-my-js.js"></script>
the reference to jQuery is resolved in troublesome.js and things are good,
but I would prefer to avoid the script tag route as webpack doesn't manage those.
Can anyone recommend a decent strategy for dealing with scenarios like this?
update
with some guidance from #TN1ck, I was eventually able to identify one Webpack-centric solution, using the imports-loader
The configuration for this solution looks something like this:
//...
module: {
loaders: [
//...
{
test: require.resolve('troublesome'),
loader: "imports?jQuery=jquery,$=jquery"
}
]
}
Shimming modules is the way to go: http://webpack.github.io/docs/shimming-modules.html
I quote from the page:
plugin ProvidePlugin
This plugin makes a module available as variable in every module. The module is required only if you use the variable.
Example: Make $ and jQuery available in every module without writing require("jquery").
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
To use this with your webpack-config just add this object to an array called plugins in the config:
// the plugins we want to use
var plugins = [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
];
// this is your webpack-config
module.exports = {
entry: ...,
output: ...,
module: ...,
plugins: plugins
}
For es6/2015 I done the following.
import {jsdom} from 'jsdom';
import jQuery from 'jquery';
var window = jsdom(undefined, {}).defaultView;
var $ = jQuery(window);
//window.jQuery = $; //probably not needed but it's there if something wrong
//window.$ = $;//probably not needed but it's there if something wrong
Then you can use it as normal
var text = $('<div />').text('hello world!!!').text();
console.log(text);
Hope this helps.
Importing jQuery into your module does not make it available for 'troublesome'. Instead, you could create a thin wrapper module for 'troublesome' that provides jQuery and any other required "globals".
troublesome-module.js:
// Bring jQuery into scope for troublesome.
import jQuery from 'jquery';
// Import any other 'troublesome'-assumed globals.
// Paste or have build tool interpolate existing troublesome.js code here.
Then in your code you should be able to
import 'troublesome-module';
I've had a similar issue using jspm and dygraphs. The way i solved it was to use dynamic loading like you attempted using System.import but the important part was to chain-load each consecutive "part" using System.import again inside the promise onfulfillment handler (then) after setting the global namespace variable. In my scenario I actually had to have several import steps separated between then handlers.
The reason it didn't work with jspm, and probably why it didn't work for you as well is that the import ... from ... syntax is evaluated before any code, and definitely before System.import which of async.
In your case it could be as simple as:
import jQuery from 'jquery';
window.jQuery = jQuery;
System.import('troublesome').then(troublesome => {
// Do something with it...
});
Also note that the System module loader recommendation has been left out of the final ES6 specification, and a new loader spec is being drafted.
run npm install import-loader.
replace import 'troublesome' with import 'imports?jQuery=jquery,$=jquery!troublesome.
In my opinion, this is the simplest solution to your question. It is similar to the answer you wrote in your question #TN1ck, but without altering your webpack config. For more reading, see: https://github.com/webpack/imports-loader
Shimming is fine and there are various ways of resolving this, but as per my answer here, the simplest is actually just to revert to using require for the loading of the library that requires the global dependency - then just make sure your window. assignment is before that require statement, and they are both after your other imports, and your ordering should remain as intended. The issue is caused by Babel hoisting imports such that they all get executed before any other code.

Categories