This a continuation of a related problem that #rossta fixed part of, but now the problem is moved so thought I'd start over.
No errors and the script is completing (verified by console.log outputs in the script). The body element shows up. This worked with gem leaflet and now webpack in Rails 5.2, but not now in Rails 6 with webpack
I moved the script into the page to isolate the problem map/index.html.erb
<p id="notice"><%= notice %></p>
<% provide(:title, 'Map') %>
<h4>This is map/index.html.erb and is put in layouts/map.html.erb.</h4>
<div id="map_two" class="map clearfix"></div> -->
<script>
function makeMapTwo() {
console.log('Hello from makeMapTwo in map/index.html.erb')
var mapVar = L.map("map_two", { center: [34.040951, -118.258579], zoom: 13 });
L.tileLayer('https://crores.s3.amazonaws.com/tiles/bkm/{z}/{x}/{y}.png').addTo(mapVar);
$.getJSON("line_data.geojson", function (data_data) {
var timelineData = L.timeline(data_data, {
style: function(data_data){
return {
stroke: true,
fillOpacity: 0.5
}
}, // end style: function(data_data)
waitToUpdateMap: true,
onEachFeature: function(data_data, layer) {
layer.bindTooltip(data_data.properties.popup, { direction: 'top' } );
} // onEachFeature:
}); // end let timelineData = L.timeline
var timelineControl = L.timelineSliderControl({
enableKeyboardControls: true,
steps: 100,
start: 1885,
end: 1928,
});
timelineData.addTo(mapVar);
timelineControl.addTo(mapVar);
timelineControl.addTimelines(timelineData);
}); // end $.getJSON
}; // end function makeMapTwo()
$(document).ready(function() {
makeMapTwo();
});
</script>
views/layouts/map.html.erb
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<h6>This is layouts/map.html.erb. A note to remind me that header is happening twice in maps TODO</h6>
<%= favicon_link_tag 'favicon.ico' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', 'data-turbolinks-suppress-warning': true %>
<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<style>
.map {
height: 400px;
width: 100%
}
</style>
<%= csrf_meta_tags %>
</head>
<%= render 'layouts/header' %> <!-- the navbar -->
<body class="container" data-mapbox-token="<%= ENV['MAPBOX_TOKEN'] %>">
<%= yield %>
<%= render 'layouts/footer' %>
</body>
</html>
and app/javascript/packs/application.js:
import "core-js/stable"
import "regenerator-runtime/runtime"
import '../stylesheets/application'
window.jQuery = $
window.$ = $
import 'leaflet'
import "leaflet.timeline"
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("trix")
require("#rails/actiontext")
require("jquery")
import "bootstrap"
import 'bootstrap/dist/js/bootstrap'
document.addEventListener("turbolinks:load", () => {
$('[data-toggle="tooltip"]').tooltip()
$('[data-toggle="popover"]').popover()
})
config/webpack/environment.js:
const { environment } = require('#rails/webpacker')
const webpack = require('webpack')
environment.plugins.append('Provide',
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
jquery: 'jquery',
Popper: ['popper.js' ,'default'],
}))
module.exports = environment
package.json
const { environment } = require('#rails/webpacker')
const webpack = require('webpack')
environment.plugins.append('Provide',
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
jquery: 'jquery',
Popper: ['popper.js' ,'default'],
}))
module.exports = environment
Debugging needed, but I'm not sure where to start.
I can't believe that this change had any effect but it did.
Changed the map_two in <div id="map_two"... var mapVar = L.map("map_two"... to just map and it loads. I was using map_two because when I was experimenting earlier I thought the two pages I was using with just map were getting confused. I also tried map-two and it didn't work either (not that I would have expected it, but I still do't understand what is happening. I restarted the server between the changes to be more sure of what is going on.
Related
I would to use easy-autocomplete to add suggestions while my users are typing the pseudo of a player on my web-app.
But it doesn't work.
Here is the message I've got :
people.js:7 Uncaught TypeError: $input.easyAutocomplete is not a function
at HTMLDocument.<anonymous> (people.js:7)
at Object../node_modules/turbolinks/dist/turbolinks.js.e.dispatch (turbolinks.js:75)
at r.notifyApplicationAfterPageLoad (turbolinks.js:994)
at r.pageLoaded (turbolinks.js:948)
at turbolinks.js:872
Here is my code :
In app/javascript/packs/people.js
document.addEventListener("turbolinks:load", function() {
$input = $("[data-behavior='autocomplete']")
var options = {
getValue: "pseudo"
}
$input.easyAutocomplete(options)
});
console.log("custom js file loaded")
Here is my layout :
app/views/layouts/application.html.erb
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', defer: true %>
<%= javascript_pack_tag 'people', 'data-turbolinks-track': 'reload' %>
Of course in my layout, before and after this part there are script for OG facebook and twitter balises
Here is my environment.js :
const { environment } = require('#rails/webpacker')
const webpack = require('webpack')
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
$: 'jquery/src/jquery',
jQuery: 'jquery/src/jquery'
})
)
module.exports = environment
I also tried this but it did not work as well :
const { environment } = require('#rails/webpacker')
const webpack = require('webpack');
// Preventing Babel from transpiling NodeModules packages
environment.loaders.delete('nodeModules');
// Bootstrap 4 has a dependency over jQuery & Popper.js:
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
Popper: ['popper.js', 'default']
})
);
module.exports = environment
If you need more information I'm ready to answer.
Thanks by advance
You are including the javascript file in wrong way.
As the helper method doc say:
# DO:
#
# <%= javascript_pack_tag 'calendar', 'map' %>
#
# DON'T:
#
# <%= javascript_pack_tag 'calendar' %>
# <%= javascript_pack_tag 'map' %>
https://github.com/rails/webpacker/blob/f1b06c7fd5bc4b7fc7128742d1078466b94af71f/lib/webpacker/helper.rb#L89-L97
In your case:
<%= javascript_pack_tag 'application', 'people', 'data-turbolinks-track': 'reload', defer: true %>
I am new with Rails 6 and webpacker. I have created a new app with rails and webpacker, got everything working but when I tried to utilize the select2 I ran into a problem where I get readyException.js:6 Uncaught TypeError: $(...).select2 is not a function errors and not am not able to submit the selected attribute to the database. I have reviewed and tried several suggestions presented on the web but didn't work. Not sure where I went wrong. Any help is much appreciated. By the way I am using simple_form and Slim.
app/assets/application.scss
#import 'bootstrap/scss/bootstrap';
app/javascript/stylesheets/application.scss
#import 'bootstrap/scss/bootstrap';
app/javascript/packs/application.js
import Rails from "#rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "#rails/activestorage"
import "channels"
import "jquery";
import "popper.js";
import "bootstrap";
import "../stylesheets/application"
import "#fortawesome/fontawesome-free/js/all"
import select2 from 'select2';
import 'select2/dist/css/select2.css';
require("#rails/activestorage").start()
require("channels")
require("jquery")
Rails.start()
Turbolinks.start()
ActiveStorage.start()
$(document).ready(function() {
$('.select').select2();
});
config/webpack/environment.js
const { environment } = require('#rails/webpacker')
const webpack = require('webpack')
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
$: 'jquery/src/jquery',
jQuery: 'jquery/src/jquery'
})
)
module.exports = environment
the view form
views/users/_form.html.slim
= simple_form_for [:admin, #user] do |f|
= f.error_notification
= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present?
.form-inputs.form-group.center-block style="width:240px"
= f.input_field :first_name,
placeholder: 'First Name',
class: 'form-control',
autofocus: true,
required: true
.form-inputs.form-group.center-block style="width:240px"
= f.input_field :last_name,
placeholder: 'Last Name',
class: 'form-control',
autofocus: true,
required: true
.form-inputs.form-group.center-block style="width:240px"
= f.input_field :email,
placeholder: 'Email',
class: 'form-control',
autofocus: true,
required: true
.form-inputs.form-group.center-block style="width:240px"
= f.select :roles, Role.all.map { |role| role.name }, {include_blank: true, required: true,
include_hidden: false}, class: 'form-control', input_html: {class: 'select'}
.form-actions.form-group.center-block style="width:240px"
button.btn.btn-primary.space-above type="submit" Save
= link_to "Cancel", admin_users_path, class: 'btn btn-default space-left'
I think you may be causing issues by importing jquery twice.
Remove these lines:
require("#rails/activestorage").start()
require("channels")
require("jquery")
These are duplicating imports on lines above and (I think) the second require("jquery") could be clobbering the select2 plugin.
Also, you're not using the local select2 variable from the import. This should be sufficient:
import $ from 'jquery'
import 'select2'
$(document).ready(function() {
$(...).select2()
})
I have a branch in a demo repo that has a working example https://github.com/rossta/rails6-webpacker-demo/compare/example/select2
Started a new Rails 6.0.3 project and added jQuery and Bootstrap. jQuery works fine and the Bootstrap CSS seems to render properly but whenever I try running $.fn.tooltip.Constructor.VERSION in the browser javascript console I get an error Uncaught TypeError: Cannot read property 'tooltip' of undefined. Also trying to add plugins like bootstrap-select, Bootstrap Tags Input, etc. all fail. I'm not sure if it's related but I've also had the same trouble adding awesome-fonts, the CSS works but Javascript does not. Below are configs that might be relevant:
// package.json
{
"name": "myproject",
"private": true,
"dependencies": {
"#rails/actioncable": "^6.0.0",
"#rails/activestorage": "^6.0.0",
"#rails/ujs": "^6.0.0",
"#rails/webpacker": "5.2.1",
"bootstrap": "^4.5.2",
"channels": "^0.0.4",
"jquery": "^3.5.1",
"popper.js": "^1.16.1",
"turbolinks": "^5.2.0"
},
"version": "0.1.0",
"devDependencies": {
"axios": "^0.20.0",
"cypress": "^5.1.0",
"webpack-dev-server": "^3.11.0"
}
}
// config/webpack/environment.js
const { environment } = require('#rails/webpacker')
const webpack = require('webpack')
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
$: 'jquery/src/jquery',
jQuery: 'jquery/src/jquery',
Popper: ['popper.js', 'default']
})
)
module.exports = environment
// config/webpack/development.js
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
const environment = require('./environment')
module.exports = environment.toWebpackConfig()
// app/javascript/packs/application.js
require("jquery")
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("channels")
require("bootstrap")
// app/views/layouts/application.html.erb
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
<title>My Project</title>
</head>
<body>
<%= yield %>
</body>
</html>
Got it working through the following addition...
// config/webpack/custom.js
module.exports = {
resolve: {
alias: {
jquery: 'jquery/src/jquery'
}
}
};
... and changes:
// config/webpack/environment.js
const { environment } = require('#rails/webpacker')
const customConfig = require('./custom')
const webpack = require('webpack')
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
$: 'jquery/src/jquery',
jQuery: 'jquery/src/jquery',
Popper: ['popper.js', 'default']
})
)
environment.config.merge(customConfig)
module.exports = environment
// config/webpack/environment.js
require("jquery")
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("channels")
require("bootstrap")
import $ from "jquery"
document.addEventListener("turbolinks:load", () => {
$('[data-toggle="tooltip"]').tooltip()
$('[data-toggle="popover"]').popover()
})
Related question that was helpful in getting to a solution: $(...).tooltip is not a function rails 6 webpack
I recently added the code mirror editor to my rails 6 app. I was able to get everything working fine on my local environment (ubuntu 18.04), but when I deploy the app to heroku the code mirror editor renders the actual text editing area far below the div. It also seems to be filling it with x's. here is a screenshot of it. The x's near the top are actually part of the top editor not shown, and the lower x's are part of the main editor in the picture.
Here is my application.js file:
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("channels")
require("jquery")
import { autocompleteExport } from '../custom/autocomplete';
import { initialize } from '../custom/editor';
import { formatToc } from '../custom/page_display';
window.jQuery = $;
window.$ = $;
$(document).on("turbolinks:load", autocompleteExport.categories)
$(document).on("turbolinks:load", autocompleteExport.search)
$(document).on("turbolinks:load", autocompleteExport.admins)
$(document).on("turbolinks:load", initialize)
$(document).on("turbolinks:load", formatToc)
and here is the editor file that initializes the editors:
import CodeMirror from 'codemirror/lib/codemirror.js'
import 'codemirror/lib/codemirror.css'
import 'codemirror/mode/markdown/markdown.js'
function initialize(){
let textArea = document.getElementById('page_edit_content')
let editor = document.getElementById('content-editor')
if(textArea && !editor){
var contentEditor = CodeMirror.fromTextArea(textArea, {
lineWrapping: true,
mode: "markdown",
});
contentEditor.display.wrapper.id = "content-editor"
}
textArea = null
editor = null
textArea = document.getElementById('page_edit_summary')
editor = document.getElementById("summary-editor")
if(textArea && !editor){
var contentEditor = CodeMirror.fromTextArea(textArea, {
lineWrapping: true,
mode: "markdown",
});
contentEditor.display.wrapper.id = "summary-editor"
}
textArea = null
editor = null
textArea = document.getElementById('page_content')
editor = document.getElementById("new-content-editor")
if(textArea && !editor){
var contentEditor = CodeMirror.fromTextArea(textArea, {
lineWrapping: true,
mode: "markdown",
});
contentEditor.display.wrapper.id = "new-content-editor"
}
textArea = null
editor = null
textArea = document.getElementById('page_summary')
editor = document.getElementById("new-summary-editor")
if(textArea && !editor){
var contentEditor = CodeMirror.fromTextArea(textArea, {
lineWrapping: true,
mode: "markdown",
});
contentEditor.display.wrapper.id = "new-summary-editor"
}
}
export {initialize}
Lastly here is one of the views which is having the issue:
<% #page_title = "New Page" %>
<div class="container form-container">
<%= form_for #page, url: world_pages_path(params[:world_name]), html: {style: "width: 100%"} do |f| %>
<%= render 'shared/error_messages', errors: flash[:errors] %>
<div class="form-group">
<%= f.label :title %>
<%= f.text_field :title, autofocus: true, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :summary %>
<%= f.text_area :summary, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :content %>
<%= f.text_area :content, class: "form-control" %>
</div>
<div class="form-group">
<%= f.submit "Create!", class: "btn btn-primary" %>
</div>
<% if params[:category] %>
<%= hidden_field_tag :category, params[:category] %>
<% end %>
<% end %>
</div>
I'm pretty much at a loss for what could be causing this any help would be greatly appreciated.
edit:
After looking a bit through my browsers devtools, it is looking like the issue may be coming from the css not properly loading in my editor.js file, which is where I import the css files for code mirror.
edit-2:
When I remove the css import statement from the editor.js file, I get the same behavior in development, so I know for sure that that is the issue. If anyone knows the correct way to import styles from node modules that would be very helpful
If anyone runs into something like this in the future, I was able to find an answer.
The issue was stemming from my misunderstanding of webpack.
I was directly importing the css from the node module into the editor.js file. I am still not a webpack expert so I couldn't say why this worked locally, but it didn't properly set up the css files to be compiled by webpack in production.
The fix was to instead create an application.scss file in app/javascript/src. It was in this file I added #import 'codemirror/lib/codemirror.css';
After doing this I added import '../src/application.scss' to my application.js file so that webpack would know to compile the css.
Finally, I added <%= stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' %> into my application.html.erb layout file which pulls in the css from the compiled files.
I have project where I use ejs files. Only problem that I use ejs files for server side. Code below. I need set up webpack in way, that on fly it insert in index.ejs <script src="frontend/build/..."></script> and <style src="frontend/build/..."/>. Only that I know is that I should use webpack-middleware somehow. If someone have experience, please help me set up.
// webpack.config.js
import path from 'path';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import CleanWebpackPlugin from 'clean-webpack-plugin';
const inProduction = process.argv[process.argv.length - 1]
.match(/[a-z]+$/g)[0] === 'production';
const basic = {
entry: {
app: path.join(__dirname, 'frontend/source/scripts/main.js'),
},
output: {
path: path.join(__dirname, 'frontend/build'),
filename: '[name].[chunkhash].js',
},
};
const module = {
rules: [{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: ['css-loader'],
}),
},
{
test: /\.js$/,
use: ['babel-loader'],
exclude: ['/node_modules'],
},
],
};
const plugins = [
new ExtractTextPlugin('[name].[contenthash].css'),
new CleanWebpackPlugin('build'),
];
export default {
...basic,
module,
plugins,
};
<!-- index.ejs -->
<header class="header">Git Rendering</header>
<main class="container">
<% if (branches) { %>
<%- include('branches'); %>
<% } %>
<% if (commits) { %>
<%- include('commits'); %>
<% } %>
<% if (files) { %>
<%- include('files'); %>
<% } %>
<% if (file) { %>
<%- include('file'); %>
<% } %>
</main>
The easiest solution would be to load the files with html-webpack-plugin. You can write templates and inject your script tags.
If you just want to add your webpack entries, it will already happen automatically.
The only thing you need to watch out for is, that html-webpack-plugin uses ejs templating as well. So you will need to change either your or the plugins templating syntax.