Using laravel mix to include js dependencies - javascript

i can't really get my js libraries to work , some time ago i decided to have a separate js file for every library i use (so i have a jquery.js file and a bootstrap.js file included in my layout) ,everything was working just fine until i had to add jquery-ui to this chaos , and got this error
Uncaught TypeError: $(...).slider is not a function
until i loaded ,jquery and jquery-ui in the same file .The problem is i dont want to include jquery ui everywhere i include jquery , beacuse i only use it in 2 pages. Below i will put my code :
jquery-ui.slider.js:
require('jquery-ui/ui/widgets/slider');
require('./components/carFilter.js');
app.js:
window.$ = window.jQuery = require('jquery');
require('./bootstrap');
webpack.mix.js:
mix.js('resources/assets/js/app.js', 'public/js')
mix.js('resources/assets/js/jquery-ui.slider.js', 'public/js');
I am using the following npm modules :
bootstrap-sass
jquery
jquery-ui

I ended up by just creating a file where i require jquery,bootstrap.js and then i require this file in a specific file for the two pages...
Below its the code:
app.js
window.$ = window.jQuery = require('jquery');
require('./bootstrap');
page.js
require('./app.js')
require('jquery-ui/ui/widgets/slider');
It seams that now it is working ,even if now i have to include a js file in all the views...Question its still open , i hope somone have a beter idea .

I think laravel-mix only serves the purpose when you have small sites with pages that all include the same app.js & app.css files.
When you have complex portal with multiple pages that have different set of frontend "plugins" you have to split your entries & generate a table of dependencies automatically.
After a lot of time searching I've come to the conclusion that the best approach would be switch to webpack-encore from Symfony.
You can read more about it's capabilities here Webpack Encore Official Documentation.
Now the question is how to embed it to Laravel? It's quite easy, I've just reverse engineered the Symfony's PHP bundle for that and here is the result:
https://github.com/ntpages/laravel-encore
Now you just have to include you're dependency in the page entry and it's all handled automatically.

I think you should load jquery-ui when a condition is met, like:
if (window.loadJQueryUI) {
require('jquery-ui');
}
And you need to initialize loadJQueryUI for the two pages, like this:
<script type="text/javascript">
window.loadJQueryUI = true;
</script>

Related

yarn: $ is not defined

For the first time I am using Yarn. I have installed the latest version of Laravel Boilerplate (http://laravel-boilerplate.com/) and there is used Yarn.
My need is to include the JS library DataTables (https://datatables.net/).
Unfortunately I am new to Yarn and I am not sure if I am making everything right, because I get the error:
[Show/hide message details.] ReferenceError: $ is not defined
which is on the this line:
$(document).ready(function() {
...
This is telling me that it cannot find the jquery library, but it should be there.
Here is the webpack.mix.js code:
const mix = require('laravel-mix');
/*
|--------------------------------------------------------------------------
| Mix Asset Management
|--------------------------------------------------------------------------
|
| Mix provides a clean, fluent API for defining some Webpack build steps
| for your Laravel application. By default, we are compiling the Sass
| file for the application as well as bundling up all the JS files.
|
*/
mix.setPublicPath('public');
mix.sass('resources/sass/frontend/app.scss', 'css/frontend/frontend.css')
.sass('resources/sass/backend/app.scss', 'css/backend/backend.css')
.js('resources/js/frontend/app.js', 'js/frontend/frontend.js')
.js([
'resources/js/backend/before.js',
'resources/js/backend/app.js',
'resources/js/backend/after.js'
], 'js/backend/backend.js')
.extract([
'jquery',
'datatables.net-dt',
'bootstrap',
'popper.js/dist/umd/popper',
'axios',
'sweetalert2',
'lodash',
'#fortawesome/fontawesome-svg-core',
'#fortawesome/free-brands-svg-icons',
'#fortawesome/free-regular-svg-icons',
'#fortawesome/free-solid-svg-icons'
]);
if (mix.inProduction() || process.env.npm_lifecycle_event !== 'hot') {
mix.version();
}
Every time I call the command "yarn prod" in order to create the CSS and js files, but the DataTables are not working.
Did I miss something?
Thanks in advance!
It's not because of yarn. Yarn is a package manager, it doesn't run any part of your application's code so cannot generate an error like yours. Yarn is just for downloading packages and manage their dependencies.
Then comes Laravel Mix for you, which is just a wrapper around Webpack. Webpack reads your application code, handles your require and import commands in your .js files and then generates your bundles.
How to make it work:
I suppose you did run the yarn command (without params) in your project root once when you installed Laravel Boilerplate. There should be a lot of packages inside your node_modules directory (more than 900).
Then you did run yarn add -D datatables.net-dt also. Now you should have a datatables.net and a datatables.net-dt folder inside node_modules.
I see you've added datatables.net-dt in your webpack.mix.js, this is OK! You don't need any other require( 'datatables.net-dt' )( window, $ ); as said in the documentation. That one line in your webpack.mix.js is enough! DataTable will be inside your vendor.js.
Now create an example table with attribute id="example" in your index.blade.php then add this code to the bottom of your resources\js\frontend\app.js:
$(document).ready(function() {
$('#example').DataTable();
});
Then run yarn dev to let Webpack generate your bundles (compiled js files) and view your site in the browser. Following these, it should be working on a fresh install install of Laravel Boilerplate, without any error. I've just tested id now, works like charm.
Your possible bug:
$ is not defined tells that some part of your code is trying to use jQuery before it has been loaded.
It's important that you must write your codes using jQuery (shortened $) inside your resources\js\frontend\app.js or in a separate .js which is later required/imported into this file! It's because jQuery and other vendor packages like DataTable are stored in vendor.js, which must be loaded before any calls to them.
So don't use custom <script> tags in your html's <head> tag for your app code because that will be loaded and executed before any other defined in the bottom of your <body> tag!
Have a look at this file resources\views\frontend\layouts\app.blade.php. In the bottom of the body tag you'll see this:
<!-- Scripts -->
#stack('before-scripts')
{!! script(mix('js/manifest.js')) !!}
{!! script(mix('js/vendor.js')) !!}
{!! script(mix('js/frontend.js')) !!}
#stack('after-scripts')
Your resources\js\frontend\app.js and all its imported scripts will be compiled to this js/frontend.js file.
How jQuery is imported in Laravel Boilerplate:
This is done well by default, you don't have to bother with it. Open your resources\js\bootstrap.js and see these two lines:
import $ from 'jquery';
window.$ = window.jQuery = $;
This file will then imported by frontend/app.js. So write your code here and you'll be fine...
PS.: If this doesn't helps you to make it work, you should edit your question and provide more info on your sources. A screenshot for example taken from your Chrome DevTools, showing the lines of your JavaScript where the error occurred.

Webpack + Symfony encore - how to add libraries

I am quite new in using webback and encore, so I don't know exactly which is the approach to handle this.
I have a website with a few js files, and it uses jQuery and Bootstrap. I want to create a unique minified js file using webpack.
I've been able to successfully do it following the examples at Symfony website, so I am able to just include one app.js and encore builds the dependencies correctly.
There are some javascript libraries that are not used in my app.js but will be used in some javascript code inlined in the website, like for example the PhotoSwipe.
Currently, I am requiring the PhotoSwipe library inside my main.js file, although this file doesn't use this library.
// Resources/public/js/main.js
import PhotoSwipe from 'photoswipe';
import PhotoSwipeUI_Default from 'photoswipe/dist/photoswipe-ui-default';
So, how can I tell encore to add this library into the builded app.js without having to add it in my main.js?
I've tied to add it in webpack.config.json
.addEntry('app', [
'./src/AppBundle/Resources/public/js/main.js',
'photoswipe',
'photoswipe/dist/photoswipe-ui-default'
])
If I check the app.js generated I can see the code has been added to app.js, but when I try in my html code to call Photoswipe I get the error Uncaught ReferenceError: PhotoSwipe is not defined
I guess that this is as the libraries are confined inside the js file, and I should add some kind of export to be accessible, I don't know, as I've said, I am very new in this ;)
This is how I managed my libraries:
// Resources/public/js/myCustomScript.js
const PhotoSwipe = require('photoswipe.js)';
const PhotoSwipeUI_Default = require ('photoswipe/dist/photoswipe-ui-default');
[...] // do PhotoSwipe stuff
And in your webpack.config.json only:
.addEntry('myCustomScript', './src/AppBundle/Resources/public/js/myCustomScript.js')
Then in the templates that needs this script :
<script type="text/javascript" src="{{ asset('build/myCustomScript.js') }}"></script>

Define the order of require in Laravel-mix/Webpack

I'm having trouble with adding Summernote to my NPM. I want to use NPM so that all of the JS and CSS files are in one file. Unfortunately, I have not been able to get Summernote to work when I add it in the Laravel-mix and Webpack. I know it works when I add the script link in my main.blade.php. The problem is that jQuery is always at the end of my app.js file, but I need Summernote to be the last.
webpack.mix.js
mix.js([
'resources/assets/js/app.js',
// I tried to add a new file with only summernote required to get it to be the
// last package to be in the app.js but no luck.
//'resources/assets/js/summernote.js'
], 'public/js');
assets/js/app.js
require('./bootstrap');
// Menu
require('./sidebar.js');
./bootstrap
window._ = require('lodash');
/**
* We'll load jQuery and the Bootstrap jQuery plugin which provides support
* for JavaScript based Bootstrap features such as modals and tabs. This
* code may be modified to fit the specific needs of your application.
*/
window.$ = window.jQuery = require('jquery');
// Packages
require('bootstrap-sass');
require('owl.carousel');
require('perfect-scrollbar/jquery')(window.$);
require('datatables.net-bs');
require('codemirror');
require('summernote');
require('select2');
// Set some global options for select2
$.fn.select2.defaults.set("theme", "bootstrap");
I know that all the version of jQuery, bootstrap etc are working together so that is not the problem. I just need to get the summernote js code underneath the jquery...

ember.js include custom js

Attempting to wrap my head around Ember.js.
Seems I understand the complex things, but miss out on the little things.
How would one go about adding an example.js file?
For simplicity, let's say the example.js file only contains:
(function(){
console.log("example is alive in console");
})(window);
This should display "example is alive in console" within the browser console.
I have tried:
adding app.import('vendor/javascripts/example.js'); within ember-cli-build.js and adding <script src="{{rootURL}}vendor/javascripts/example.js"></script> to index.html
Console is showing
ⓧ GET http://localhost:4200/vendor/javascripts/example.js
DEBUG: -------------------------------
DEBUG: Ember : 2.11.3
DEBUG: Ember Data : 2.12.1
DEBUG: jQuery : 3.2.1
DEBUG: -------------------------------
ⓧ GET http://localhost:4200/vendor/javascripts/example.js
All of the answers I have found stated that just adding custom.js to vendor file works. Sadly, I am missing something.
When modifying ember-cli-build.js you MUST RESTART the ember server manually. The livereload server will not pick up the changes.
This works for me when I don't nest assets in the /vendor directory. The ember-cli build process bundles JS files in /vendor into a single vendor.js file, which you can see linked in app/index.html. So place your example.js file at the root of /vendor, and then add the import to ember-cli-build.js:
app.import('vendor/example.js`);
Now when you start the server, your code from example.js should execute, since it will be included in assets/vendor.js.
Firstly, Ember.js has Convention Over Configuration approach, and your URL can do a lot of things than a normal HTML website.
Whatever you may want to do with your custom.js file it is not ember way of having it as a path. You need routes for navigation across the app. Although routes do much more than navigation. You specify the structure of your app that a user can browse through using Router's map function in app/router.js file.
However if you want to include custome.js file in your app, and have custom.js do some set of tasks for your app. You can simply go ahead and create a directory with any name, javascript for instance inside app directory. Have your javascript files placed inside it. Then you can import these files as simply as referencing any other files in ember:
import customObject from 'yourApp/javascript/custom.js';
Here, your custom.js should be exporting customObject.
Do read the guides if you want to learn more. And the API docs if you actually want to learn more.
Note: At the time of writing this answer current ember-cli version is #2.12.0

how to use webpack to load CDN or external vendor javascript lib in js file, not in html file

I am using react starter kit for client side programming. It uses react and webpack. No index.html or any html to edit, all js files. My question is if I want to load a vendor js lib from cloud, how to do I do that?
It would be easy to do that in a html file. <script src="https://forio.com/tools/js-libs/1.5.0/epicenter.min.js"></script>
However, in js file, it only uses npm installed packages. How can I import the above lib with no html file? I tried import and require, they only work for local files.
update 10/21/15
So far I tried two directions, neither is ideal.
#minheq yes there is a html file sort of for react start kit. It is html.js under src/components/Html. I can put cloud lib and all its dependencies there like this:
<div id="app" dangerouslySetInnerHTML={{__html: this.props.body}} />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://forio.com/tools/js-libs/1.5.0/epicenter.min.js"></script>
<script src="/app.js"></script>
<script dangerouslySetInnerHTML={this.trackingCode()} />
</body>
Good news is it works, I don't need do anything else in js file, no import or require. However, now I have two jquery libs loaded in different ways. One in here, the other through npm and webpack. I wonder it will give me trouble later. The react-routing I use give me 'undefined variable' error if I type a none home path in browser window due to the server side loading I guess. So this solution is not very good.
Use webpack externals feature. This is documented as: link. "You can use the externals options for applications too, when you want to import an existing API into the bundle. I.e. you want to use jquery from CDN (separate tag) and still want to require("jquery") in your bundle. Just specify it as external: { externals: { jquery: "jQuery" } }."
However, the documentation I found a few places are all fussy about how to do this exactly. So far I have no idea how to use it to replace <script src="https://forio.com/tools/js-libs/1.5.0/epicenter.min.js"></script> in html.
externals is not intended to let you do this. It means "don't compile this resource into the final bundle because I will include it myself"
What you need is a script loader implementation such as script.js. I also wrote a simple app to compare different script loader implementations: link.
var $script = require("scriptjs");
$script("//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js", function() {
$('body').html('It works!')
});
You can create a script tag in your JS as
$("body").append($("<script src="https://forio.com/tools/js-libs/1.5.0/epicenter.min.js"></script>"))
There is one html file that is definitely being used to serve to users with your js bundle attached. Probably you could attach the script tag into that html file
Use webpack's externals:
externals allows you to specify dependencies for your library that are
not resolved by webpack, but become dependencies of the output. This
means they are imported from the environment during runtime.
I have looked around for a solution and most of all proposals were based on externals, which is not valid in my case.
In this other post, I have posted my solution: https://stackoverflow.com/a/62603539/8650621
In other words, I finished using a separate JS file which is responsible for downloading the desired file into a local directory. Then WebPack scans this directory and bundles the downloaded files together with the application.

Categories

Resources