I bumped into troubles with webpacker. I'm using Rails 6.beta3 and trying to add Datatables to my app. My steps:
yarn add datatables.net-dt
then in app/javascript/packs/application.js:
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("channels")
import 'bootstrap/dist/js/bootstrap';
import 'popper.js/dist/popper.js';
require( 'datatables.net-dt' )();
config/webpack/environment.js:
const { environment } = require('#rails/webpacker')
const webpack = require('webpack')
module.exports = environment
environment.plugins.append('Provide', new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
Popper: ['popper.js', 'default']
}))
After this if load a page I get an error in js console:
Uncaught TypeError: Cannot set property '$' of undefined
at DataTable (jquery.dataTables.js:129)
jquery.dataTables.js:
var DataTable = function DataTable(options) {
this.$ = function (sSelector, oOpts) { // <---------error is here. Turns out this is not defined variable
return this.api(true).$(sSelector, oOpts);
};
Any ideas? Thanks in advance
Opps. Its my bad. I found the issue. At the end of app/javascript/packs/application.js there was an error. I thought it didn't make impact on overall performance, but after eliminating of this things started working properly.
my app.js
// that code so it'll be compiled.
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("channels")
import 'bootstrap/dist/js/bootstrap';
require('select2');
import 'popper.js/dist/popper.js';
require("chart.js");
require("leaflet");
import $ from 'jquery';
window.jQuery = $;
window.$ = $;
// var dt = require( 'datatables.net-dt' );
// var dt = require( 'datatables.net-bs4' )( window, window.$ );
require('datatables.net-bs4');
var moment = require('moment');
window.moment = moment
require('bootstrap-daterangepicker');
var feather = require('feather-icons/dist/feather.js')
function onready() {
feather.replace()
console.log('onready')
}
$(document).on('ready turbolinks:load', onready);
/* globals Chart:false, feather:false */
(function () {
feather.replace()
}())
My app/javascript/packs/application.js
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("channels")
import 'bootstrap/dist/js/bootstrap';
import 'popper.js/dist/popper.js';
My application.js
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("channels")
import 'bootstrap/dist/js/bootstrap';
import 'popper.js/dist/popper.js';
require( 'datatables.net-dt' )();
And the result is
jquery.dataTables.js:129 Uncaught TypeError: Cannot set property '$' of undefined
at DataTable (jquery.dataTables.js:129)
at Module../app/javascript/packs/application.js (application.js:38)
at __webpack_require__ (bootstrap:19)
at bootstrap:83
at bootstrap:83
The odd thing is the bootstrap part of the stack!
Related
I'm trying to implement what is described here on my Rails 6.1 app (with webpacker).
"dependencies": {
"#rails/ujs": "^6.1.3",
"#rails/webpacker": "5.4.3",
...
}
My packs/application.js looks like
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
// require("channels")
document.addEventListener("turbolinks:load", () => {
const remoteLinks = Array.from(document.querySelectorAll("a[data-remote='true']"))
remoteLinks.forEach(function(element) {
element.dataset.url = element.href
element.href = "javascript:void(0);"
})
Rails.href = function(element) {
return element.dataset.url || element.href
}
})
And I get Uncaught ReferenceError: Rails is not defined.
What am I missing here?
UPDATE
I was missing
import Rails from "#rails/ujs"
I have a rails 6.1 app using webpacker and tailwind.
My page load speed test shows a bad loading speed and suggests to "Reduce unused JavaScript". Sidenote: it also suggests to "Reduce unused CSS". So purge seems not to work. But on the page where I perform the page load speed test, the chartkick/chart.js is not even used. So it seems like it is loading every JS library, despite it is not even used on a page.
Here is my packs/application.js file:
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.
import Rails from "#rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "#rails/activestorage"
import "channels"
import "chartkick/chart.js"
import ahoy from "ahoy.js"
import { initMapbox } from '../packs/init_mapbox'
require("stylesheets/application.scss")
require("../stylesheets/components/pagination.scss")
require("../stylesheets/components/vacancy_description.scss")
Rails.start()
Turbolinks.start()
ActiveStorage.start()
document.addEventListener('turbolinks:load', () => {
initMapbox();
})
Here is my tailwind.config.js file:
const colors = require('tailwindcss/colors')
module.exports = {
purge: {
enabled: process.env.NODE_ENV === "production"
content: ['./app/views/**/*.html.erb', './app/javascript/**/*.js',],
},
darkMode: false, // or 'media' or 'class'
theme: {
colors: {
transparent: 'transparent',
current: 'currentColor',
black: colors.black,
white: colors.white,
gray: colors.trueGray,
indigo: colors.indigo,
red: colors.rose,
yellow: colors.amber,
green: colors.emerald
},
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}
Hope someone can help!
My problem is similar to the one described in https://github.com/nathanvda/cocoon/issues/399.
Adding and removing nested fields works, but callbacks don't fire.
application.js:
import Rails from "#rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "#rails/activestorage"
import "channels"
// Bootstrap
require("bootstrap")
// Toastr
global.toastr = require("toastr")
// Cocoon
require("#nathanvda/cocoon")
import "../stylesheets/application"
require("packs/ingredient")
Rails.start()
Turbolinks.start()
ActiveStorage.start()
ingerdient.js
$(document).on('ready page:load turbolinks:load', function() {
$("a.add_fields")
.on('cocoon:before-insert', function () {
console.log('before insert');
})
.on('cocoon:after-insert', function () {
console.log('after insert');
})
.on("cocoon:before-remove", function () {
console.log('before remove');
})
.on("cocoon:after-remove", function () {
console.log('after remove');
});
$("a.add_fields").on('click', function(){
console.log('looks like clicking works...');
});
});
Console output:
Event Listeners:
jquery.js:4487:
Maybe the problem is double jQuery but I'm newbie and I can't figure it how solve that.
Thanks.
The OP registered the callbacks on the link, but it is recommended to register them on the container object.
Quoting from the cocoon documentation:
Note that for the callbacks to work there has to be a surrounding container to which you can bind the callbacks.
I have a Rails 6 application and using Webpacker for assets.
I have the following code in file app/javascript/packs/application.js :
export var Greeter = {
hello: function() {
console.log('hello');
}
}
And I have the following script in one of my view (HTML) file:
<script>
$(document).ready(function(){
Greeter.hello();
});
</script>
Note: I am using JQuery and it is working fine.
I am getting the following error:
Uncaught ReferenceError: Greeter is not defined.
How can we use libraryTarget and library to expose the bundled modules, so that it can be accessed from HTML files as well ?
Or, is there any other way of doing it using Rails Webpacker ?
Any help would be much appreciated!
To do this without directly mutating the window object in your application code, you'll want to export Greeter as a named export from your application.js pack and extend the Webpack config output to designate the library name and target var (or window will also work).
// config/webpack/environment.js
environment.config.merge({
output: {
library: ['Packs', '[name]'], // exports to "Packs.application" from application pack
libraryTarget: 'var',
}
})
// app/javascript/packs/application.js
export {
Greeter
}
<script>
$(document).ready(function(){
Packs.application.Greeter.hello();
});
</script>
The library name is arbitrary. Using the [name] placeholder is optional but allows you to export to separate modules if you're using multiple "packs".
As I cannot comment rossta's answer, here is what I had to do. My default config was:
// config/webpack/environment.js
const { environment } = require('#rails/webpacker')
module.exports = environment
and I just had to add the additionnal config in it:
// config/webpack/environment.js
const { environment } = require('#rails/webpacker')
environment.config.merge({
output: {
library: ['Packs', '[name]'], // exports to "Packs.application" from application pack
libraryTarget: 'var',
}
})
module.exports = environment
After that, as mentioned by rossta, each symbol which is exported in app/javascript/packs/application.js can be accessed from the DOM as Packs.application.<symbol>.
in app/javascript/packs/application.js:
import Greeter from '../greeter.js'
Greeter.hello()
and in app/javascript/greeter.js:
export default {
hello : function(){
console.log('hello')
}
}
I could fix the issue exposing Greeter object to window as follows:
export var Greeter = {
hello: function() {
console.log('hello');
}
}
window.Greeter = Greeter;
However, I am still looking for a Webpack way of accomplishing this.
Rails 5.2.1 webpacker4.0
app/javascript/application.scss
#import "material-components-web/material-components-web";
I use webpacker with the default setting, but it does not work well.
What additional settings do I need?
I want to use material-components-web in webpacker
err
Module build failed:
#import "#material/base/mixins";
File to import not found or unreadable: #material/base/mixins.
webpack/environment.js
const { environment } = require('#rails/webpacker')
const webpack = require('webpack')
const { VueLoaderPlugin } = require('vue-loader')
const vue = require('./loaders/vue')
environment.plugins.append('VueLoaderPlugin', new VueLoaderPlugin())
environment.loaders.append('vue', vue)
module.exports = environment