How do I globally declare jQuery inside a Vue-CLI 3 project? - javascript

I have seen a lot of questions about this on SO and elsewhere, but so far I had no luck.
For a bit of context, I built a SPA website on a Vue project I created with an "old" command. I don't remember which one but it looked like the following:
vue init webpack <my project>
I recently realized that Vue-CLI 3 would be way easier for me to maintain, keep updated and improve for various contextual reasons, so I installed #vue/cli, created a new project and started to copy/paste files from my old project to the new one.
The old project had a build directory with various webpack config files in it, and I needed jQuery set globally for a package I wanted to use, so I added the following to the "base" config of Webpack.
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}),
However, with the new project, all I have now as config file is babel.config.js and vue.config.js at the project's root, there are no build nor config directory.
I tried to set jQuery globally with the following lines inside my main.js file:
import jQuery from 'jquery'
window.$ = window.jQuery = jQuery
global.$ = global.jQuery = jQuery
But everytime I reload my page, I get the following message:
jQuery is not defined
So, so far, I use the CDN version of jQuery but I don't feel at ease with this solution.
How should I proceed with a Vue-CLI 3 project?
Thank you in advance

You can use Vue plugins. This allows you to add new property to every single component.
In main.js
import Vue from 'vue';
import jQuery from 'jquery';
Vue.use({
install (V) {
V.$jQuery = V.prototype.$jQuery = jQuery
}
})
Then you can use jQuery everywhere in component.
In MyComponent.vue
import Vue from 'vue'
export default {
mounted () {
this.$jQuery('h1').text('Hello World')
Vue.$jQuery('h1').text('Hello World')
}
}
Even another js file.
In util.js
import Vue from 'vue'
Vue.$jQuery('h1').text('Hello World')

You could go on public/index.html and add the script tag to the body with the route to your jquery file or cdn.
If you put it in a jquery folder in public it would look like:
<body>
<div id="app"></div>
<script type="text/javascript" src="/jquery/jquery-3.4.1.min.js"></script>
</body>
I am not sure if that's exactly what you want but it would make it available globally across your project.

If you are using Jquery plugins, you should do this in your main.js:
/*
* If using Jquery plugins they will expect to be available in the global namespace,
* which isn’t the case when you import/require it. So manually assign jquery to
* window. Use require instead of import because the imports are hoisted to the
* top of a file by the compiler, which would break VueJS code.
*/
const $ = require('jquery')
window.jQuery = window.$ = $;

Related

Symfony Webpack Encore with company common bundle

There maybe some documentation out there on how to deal with this situation but i don't even know how to look for it.
Here's the deal, we have a Symfony "module" (ex Bundle) company-made that we share across multiple projects. Atm it is not listed on packagist and we require it with local composer repository paths if that matters.
Inside the shared module we have some css and some js that needs to be included. Since one of those shared-module (or bundle, w/e you want to call it) has bootstrap (the css frontend toolkit) the module itself requires it together with his css.
Inside the shared module we have a JS file "CoreLibrary.js" and we import the required js like this:
import $ from 'jquery';
import 'bootstrap';
export class CoreLibrary {
... more code
}
Then, inside the main application we include the common js file from the app.js file like this:
import { CoreLibrary } from '../public/bundles/thebundlename/js/CoreLibrary';
That doesn't seem to be ideal, and beside that, with encore we have to repeat
import $ from 'jquery';
import 'bootstrap';
import { CoreLibrary } from '../public/bundles/thebundlename/js/CoreLibrary';
In every .js file we need. That's so much of a burden that I can't belive there are no better ways do to that.
Sidenote: not so long ago i had to even follow this one:
Yarn and Webpack Encore configuration in Symfony 4.1 project because i was getting error during "yarn watch".
What is the correct way of doing it with company-shared module that requires 3rd party library like bootstrap?
For global jquery i have this in main js file
const $ = require('jquery');
global.$ = global.jQuery = $;
Also uncommented line in webpack config about jquery.

Properly configure scripts with Angular-CLI

Let's say I have a project which uses these JS libraries:
main.js which has to be loaded in all pages
joe.js which is a npm package to be loaded in all pages
bob.js which is an old-style 3rd party JS library with no module defined to be loaded in all pages
max.js which is a CommonJS library to be loaded on-demand in some components
So far, I succeded in:
including main.js in the scripts property of angular-cli.json
the same as above for joe.js using relative paths (../node_modules/joe/dist/joe.js)
so they end up in the generated bundle that is loaded on every page.
I had instead a lot of problems with the other two. So far I've managed to include bob.js in the bundle by wrapping it in a self-executing function:
(function() {
// old code of bob.js
})();
but why?
And I'm totally clueless on how to include/bundle max.js...
For main, joe and bob.js you should do this:
To have the scripts available everywhere you can use the src/assets folder in your angular-cli folder structure.
And then include your scripts with:
<script src="assets/my-script.js"></script>
As an option you can get those dependencies from node_modules to src/assets with a webpack.
For most cases using CDN is better option than all this.
As for max.js you i would create a service to conveniently inject it:
import { Injectable } from '#angular/core';
#Injectable()
export class MaxService {
lib: any;
constructor(){
this.lib = require('max.js');
}
}

Importing an old ES5 module for use in a ReactJS component

I'm trying to use an ES5 module in a new ReactJS application and I'm struggling to understand how to correctly import that module, such that the main function within it can be found and executed.
I'm loading the module;
import 'air-datepicker';
I know I'm doing something wrong here and that it's not as simple as this, for an old library that doesn't have proper exports!
Anyway, then I should be able to manually initialise a date picker using an existing div like this;
$('#myDiv').datepicker();
I've tried multiple variations of the import and require, but I'm always getting the same error - 'datepicker is not a function'.
The library I'm experimenting with is air-datepicker. I've installed the module using npm without problems and I know the library works perfectly without React on a simple page loading the script manually in a script tag. My ReactJS app is a basic template created using 'create-react-app', from the FB tutorial pages.
If you're using create-react-app, you should be able to import it like
import 'air-datepicker/dist/css/datepicker.min.css';
import 'air-datepicker';
If you added your jQuery using <script> tag in your HTML, you need to add this line before the air-datepicker imports
const $ = window.jQuery;
const jQuery = window.jQuery;
If you added jQuery using npm install, you'll have to add these following lines
import $ from 'jquery';
import jQuery from 'jquery';
window.$ = $;
window.jQuery = jQuery;
//... air-datepicker imports
Make sure to initialize it inside your componentDidMount or somewhere you're sure that the element has been mounted already.
componentDidMount() {
$('#my-element').datepicker();
}
render() {
return <div>
<input
id="my-element"
type='text'
className="datepicker-here"
data-position="right top" />
</div>
}
Well, that's a day of my life that I'm never getting back!
The problem was caused by Babel import ordering. Import statements are hoisted - meaning they are evaluated first, before any other code (i.e. my window. assignments) are executed. This is 'by design' in babel.
The only way to avoid Babel hoisting, from what I can tell, is to avoid 'import' altogether and use require instead.
So, in the following order the global $ will have been set when you come to require air-datepicker. If you try to 'import' air-datepicker it won't work because Babel will evaluate all of your import statements before executing the window. assignment.
import $ from 'jquery';
window.$ = $;
require('air-datepicker');
There are one or two other approaches that also would have worked, but they are all less desirable because they need you to manually configure webpack - i.e. 'ejecting' the create-react-app config and going it alone...
Use the imports-loader;
// only works if you disable no-webpack-loader-syntax
require("imports?$=jquery!air-datepicker");
or, use the ProvidePlugin, making the module available for all modules.
You have to give it an identifier:
import datepicker from 'air-datepicker';

materialize-css Uncaught TypeError: Vel is not a function

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.

Require reactjs modules without Browserify, Webpack or Babel

I'm trying to setup TypeScript HTML app in visual studio. I want to use reactjs v0.14.7
I would like to avoid using tools like Browserify.
However, how to use the react-dom module then?
Let's forget about typescript for a while. I need to get pure ES5 up and running first.
currently, I have this:
<script src="Scripts/react/react.js"></script>
<script src="Scripts/react/react-dom.js"></script>
<script>
var Button = React.createClass({
render: function () {
return (React.createElement("div", { className: "btn btn-default" }, 'hello world'));
}
});
ReactDOM.render(React.createElement('Button'), document.getElementById('container'));
</script>
however, browser complains, ReactDOM object does not exists.
I have tried:
<script src="Scripts/require.js"></script>
<script src="Scripts/react/react.js"></script>
<script src="Scripts/react/react-dom.js"></script>
<script>
var React = require('react');
var ReactDOM = require('react-dom');
....
</script>
however, it does not work with require.js: Module name "react" has not been loaded yet for context: _. Use require([])
Can someone bring a little more light into this, please? How to use react without any server side tools like bundling, transpiling etc.
Answers like "use npm" won't be accepted as answer.
RequireJS and require are very different things - more on that later.
If you want to use React without a tool like Browserify or Webpack, then you don't necessarily need a module loader. The hosted versions of React and ReactDOM will expose global variables that you can use out of the box.
<script src="https://fb.me/react-0.14.7.js"></script>
<script src="https://fb.me/react-dom-0.14.7.js"></script>
<script>
console.log(React, ReactDOM);
</script>
Just download these files if you want to work with them locally.
SystemJS
All of that out the way, it sounds like SystemJS and JSPM might be exactly what you're looking for.
First use jspm to install your packages.
jspm install systemjs react react-dom
Then link and configure SystemJS.
<script src='jspm_packages/system.js'></script>
<script>
System.import('app.js');
</script>
Now inside app.js you can write CommonJS style code.
var React = require('react');
var ReactDOM = require('react-dom');
SystemJS will handle the loading of the rest of your scripts. If you want to make a production build, then it's as simple as running jspm bundle app.
CommonJS
The calls to require that you're seeing in the React tutorials and other examples are for a module format called CommonJS.
You use require('react') to get a reference to the value exported by the React module (installed into node_modules with npm). This means you need a pre-browser build step like Browserify or Webpack, that can staple all of the modules you need together and output one big script file.
RequireJS
Confusingly, CommonJS and RequireJS use a function with the same name to specify dependencies. You're trying to use the RequireJS require function as though you were working with CommonJS modules.
If you want to import React with RequireJS instead, then you need to something like this:
<script src="js/require.js"></script>
<script>
require.config({
'baseUrl' : 'Scripts/',
});
require(["react-0.14.7", "react-dom-0.14.7"],
function(React, ReactDOM) {
console.log(React, ReactDOM);
});
</script>
When your code executes, RequireJS will go off and add script tags for the modules you've specified. Then once these scripts have loaded, it will pass the values that they export into the callback function for you to use.
Take a look at this project
https://github.com/ORESoftware/hr4r2
it is doing what you want to do - it is using RequireJS + React + TypeScript. And it is doing serverside rendering and is a SPA.
This project is not using Webpack or Babel.
Here is an example by Dan Abramov himself, the creator of Redux in which he makes a react app without using webpack, babel or browserify.
http://codepen.io/gaearon/pen/ZpvBNJ?editors=0010
In your HTML file inside your body tag write
<div id="root">
<!-- This div's content will be managed by React. -->
</div>
And In your script tag type this
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
PS Make Sure You Include These 2 Libraries At Top
https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.js
https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.js
Hope it helps.

Categories

Resources