Module not found: Error: Can't resolve 'vue/dist/vue.esm' - ruby-on-rails

I added Vue to a Rails 6 app and I'm getting the following error:
ERROR in ./app/javascript/packs/hello_vue.js
Module not found: Error: Can't resolve 'vue/dist/vue.esm'
It's looking for it within app/javascript/packs but I'm not sure why.
The file vue.esm also does not exist within vue/dist directory.
My hello_vue.js file is:
import TurbolinksAdapter from 'vue-turbolinks'
import Vue from 'vue/dist/vue.esm'
import App from '../app.vue'
Vue.use(TurbolinksAdapter)
document.addEventListener('turbolinks:load', () => {
const app = new Vue({
el: '#hello',
data: () => {
return {
message: "Can you say hello?"
}
},
components: { App }
})
})
I also added the following to application.html.erb:
<head>
...
<%= javascript_pack_tag 'hello_vue' %>
<%= stylesheet_pack_tag 'hello_vue' %>
...
</head>
<body>
...
<div id='hello'>
{{message}}
<app></app>
</div>
...
</body>

Related

Rails 7 toastr using importmaps

Im trying to use toastr to display a message. Im using rails 7 but Im unsure if i have it imported and implemented correctly
import { Controller } from "#hotwired/stimulus";
import { initializeApp } from 'firebase';
import { getMessaging, getToken, onMessage } from "firebase-messaging";
// import { onBackgroundMessage } from "firebase-messaging-sw";
import * as toastr from 'toastr';
onMessage(messaging, (payload) => {
alert(`${ payload.notification.title }\n ${ payload.notification.body }`);
toastr['success']("Message will come here", "Title");
});
That last line is where nothing happens. the alert shows up as expected
pin "toastr", to: "https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"
That is my pin statement in importmap.rb
<head>
<title>NitroCabs</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %>
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
<%= javascript_importmap_tags %>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/firebase-messaging-sw.js');
});
}
</script>
<%= favicon_link_tag asset_path('firebase-logo.png') %>
That is my head in application.html.erb

Vue-meta tags not updating meta tags with rails as backend

I am using Ruby 2.5.1 , Rails 6.0.3.4 and Vue 2.6.
Here in rails,
application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>This is my back-end title</title>
<%= csrf_meta_tags %>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<%= csp_meta_tag %>
<%= stylesheet_pack_tag 'application' %>
<%= javascript_pack_tag 'application' %>
</head>
<body>
<%= yield %>
</body>
</html>
For vue:
javascript/packs/application.js
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
import App from '../app.vue'
import router from '../routes'
import index from '../stores'
import Meta from 'vue-meta'
Vue.use(Meta)
Vue.use(Vuex)
let token = document.getElementsByName('csrf-token')[0].getAttribute('content')
let meta = document.createElement('meta')
document.getElementsByTagName('head')[0].appendChild(meta)
axios.defaults.headers.common['X-CSRF-Token'] = token
axios.defaults.headers.common['Accept'] = 'application/json'
document.addEventListener('DOMContentLoaded', () => {
const el = document.body.appendChild(document.createElement('hello'))
const app = new Vue({
el,
router,
store: index,
render: h => h(App),
})
console.log(app)
})
javascript/routes.js
import Vue from 'vue'
import VueRouter from 'vue-router'
.....
import AboutUs from './components/LandingPage/Footer/AboutUs.vue'
Vue.use(VueRouter)
export default new VueRouter({
scrollBehavior() {
return {x: 0, y: 0}
},
routes: [
{
path: '/AboutUs',
name: 'AboutUs',
component: AboutUs,
},
...
]
)}
AboutUs.vue
<template>
<div>
<p> I am about us page </p>
</div>
</template>
<script>
export default {
metaInfo() {
return {
title: `About Us`,
titleTemplate: '%s - test.com',
meta: [
{name: 'keywords', content: this.keywords},
{name: 'description', content: this.description, vmid: 'description'},
{property: 'og:title', content: 'About Us',
template: (chunk) => `${chunk} - test.com`, vmid: 'og:title'},
{property: 'og:description', content: this.description,
template: (chunk) => `${chunk}`, vmid: 'og:description'},
],
}
},
computed: {
description() {
return 'This is about us description'
},
keywords() {
return 'apple, ball, cat'
},
},
}
</script>
While I inspect I can see:
<html>
<head>
<title>About Us - test.com</title>`
<meta name="csrf-param" content="authenticity_token">
<meta name="csrf-token" content="dLn5c24Bcel/KwzvAwDSqBhG9EFmt6qwsah8yyLo1pUEToI2PpLLYF/cg4sfguF7DtXhYE0LKie9WJMmjNVdxQ==">
<style>
......
</style>
<meta>
<meta data-vue-meta="1" name="keywords" content= "apple, ball, cat">
<meta data-vue-meta="1" name="description" content="This is about us description" data- vmid="description">
<meta data-vue-meta="1" property="og:title" content="About Us - test.com" data- vmid="og:title">
</head>
</html>
On my local server I can see updated tags from vue.
But When we go to production or on https://developers.facebook.com/tools/debug/
http://test.com/#/AboutUs
I am getting og:title from backend which is:
This is my back-end title
and Warnings like:
Inferred Property
The 'og:image' property should be explicitly provided, even if a value
can be inferred from other tags.
Missing Properties
The following required properties are missing: og:url, og:type,
og:title, og:image, og:description, fb:app_id

[Rails][Vue] Empty array returned when fetching the children nested within a parent component. Any idea why is this happening?

I'm using Rails 5.1 + Webpack running Vue 2. I'm fairly new to Vue, not so new to Rails.
I'm building a navbar component starting from the Bulma navbar. My objective is to be able to dynamically create links in the navbar by simply adding a navlink element nested within.
In my application.html.erb I have already created this structure (navlink nested inside navbar).
In hello_vue.js I'm initializing the Vue components and assigning them to a root element (one for the navbar and one for the rest of the content).
In navbar.vue, I'd like to iterate through all the and create a menu item accordingly. In order to do so, I added an empty navlinks data to navbar that I want to populate once it gets mounted() by fetching all its children (the nested navlink tags).
This is however not working, whenever I reference this.$children I get an empty array. Any idea why is this happening?
This is all the code.
application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>RailsVue</title>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= stylesheet_pack_tag 'hello_vue' %>
</head>
<body>
<div id="navbar-container">
<navbar>
<navlink href="http://google.com">
Link 1
</navlink>
<navlink href="http://facebook.com">
Link 2
</navlink>
</navbar>
</div>
<%= yield %>
<%= javascript_pack_tag 'hello_vue' %>
</body>
</html>
hello_vue.js
import Vue from 'vue/dist/vue.esm'
import App from './app.vue'
import Navlink from './components/navlink.vue'
import Navbar from './components/navbar.vue'
const navbar = new Vue({
el: "#navbar-container",
components: { Navbar, Navlink }
})
const app = new Vue({
el: '#hello',
data: {
message: "Can you say hello?"
},
components: { App }
})
navbar.vue
<template>
<div>
<nav class="navbar is-transparent">
<div class="navbar-brand">
<a class="navbar-item" href="http://bulma.io">
<img src="http://bulma.io/images/bulma-logo.png" alt="Bulma: a modern CSS framework based on Flexbox" width="112" height="28">
</a>
<div class="navbar-burger burger" data-target="navMenuTransparentExample">
<span></span>
<span></span>
<span></span>
</div>
</div>
<div id="navMenuTransparentExample" class="navbar-menu">
<div class="navbar-start">
<a v-for="navlink in navlinks" class="navbar-item" :href="navlink.href">
<slot></slot>
</a>
</div>
</div>
</nav>
</div>
</template>
<script>
import Navlink from './navlink.vue'
export default {
name: "Navbar",
data: function () {
return {
navlinks: []
}
},
created: function(){
// let children = this.$children;
console.log(this.$children);
// this.navlinks = this.$children;
// this.navlinks = this.$children;
}
}
</script>
navlink.vue
<template>
<div class="navlink">
<slot></slot>
</div>
</template>
<script>
export default {
name: "Navlink"
}
</script>
Instead of created hook, use mounted hook, you can able to get this.$children
mounted : function(){
// let children = this.$children;
console.log(this.$children);
// this.navlinks = this.$children;
// this.navlinks = this.$children;
}
You can modify components to achieve your requirement as follows
application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>RailsVue</title>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= stylesheet_pack_tag 'hello_vue' %>
</head>
<body>
<div id="navbar-container">
<navbar>
<navlink>
<a class="navbar-item" href="http://google.com">
Link 1
</a>
</navlink>
<navlink>
<a class="navbar-item" href="http://facebook.com">
Link 2
</a>
</navlink>
</navbar>
</div>
<%= yield %>
<%= javascript_pack_tag 'hello_vue' %>
</body>
</html>
hello_vue.js
import Vue from 'vue/dist/vue.esm'
import App from './app.vue'
import Navlink from './components/navlink.vue'
import Navbar from './components/navbar.vue'
const navbar = new Vue({
el: "#navbar-container",
components: { Navbar, Navlink }
})
navbar.vue
<template>
<div>
<nav class="navbar is-transparent">
<div class="navbar-brand">
<a class="navbar-item" href="http://bulma.io">
<img src="http://bulma.io/images/bulma-logo.png" alt="Bulma: a modern CSS framework based on Flexbox"
width="112" height="28">
</a>
<div class="navbar-burger burger" data-target="navMenuTransparentExample">
<span></span>
<span></span>
<span></span>
</div>
</div>
<slot></slot>
</nav>
</div>
</template>
<script>
// import Navlink from './navlink.vue'
export default {
name: 'Navbar',
data: function () {
return {
navlinks: []
}
},
mounted: function () {
// let children = this.$children;
// console.log(this)
console.log(this.$children)
// console.log(this.$root.$children[0])
// this.navlinks = this.$children
// this.navlinks = this.$children;
}
}
</script>
navlink.vue
<template>
<div class="navlink">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'Navlink'
}
</script>

Pass data from Rails template to Vue Instance

I've been trying to pass data from my Rails view to the Vue component as described here
Everything works much as expected, but I'm rather stumped as to how to access the data that I'm passing in via props. Not appearing in the Vue developer tools anywhere and I'm not able to find it by fiddling with/inside the Vue object.
Could someone point me in the right direction. I'm fairly green with Vue, so struggling to even know what to search for :/
show.html.erb
<%= javascript_pack_tag 'test_vue' %>
<%= stylesheet_pack_tag 'test_vue' %>
<%= content_tag :div, id: "test", data: {
message: "this wont!",
name: "nor will this!" }.to_json do %>
<% end %>
test.vue
<template>
<div id="app">
<p>{{test}}{{message}}{{name}}</p>
</div>
</template>
<script>
export default {
data: function () {
return {
test: 'This will display',
}
}
}
</script>
<style>
</style>
test_vue.js
import Vue from 'vue'
import Test from './test.vue'
document.addEventListener('DOMContentLoaded', () => {
const node = document.getElementById('test')
const props = JSON.parse(node.getAttribute('data'))
new Vue({
render: h => h(Test, { props })
}).$mount('#test');
})
Looks like all you need to do is declare the properties in your component:
<template>
<div id="app">
<p>{{test}}{{message}}{{name}}</p>
</div>
</template>
<script>
export default {
props: ["message","name"],
data: function () {
return {
test: 'This will display',
}
}
}
</script>
<style>
</style>
This would be the relevant documentation.
A child component needs to explicitly declare the props it expects to
receive using the props option

My request for a second view it doesn't show anything

I'm using ruby on rails as framework and vue.js to display de data and for the request to the API I'm using axios.
first I create project with:
rails new myapp --webpack=vue
that created one folder in rails:
app/javascript
└── packs
├── app.vue
└── hello_vue.js
app.vue:
<template>
<div id="app">
<ul v-for="result in results">
<li>{{result.name}}</li>
</ul>
<!-- <p>{{ results.name}}</p> -->
</div>
</template>
<script>
export default {
data: {
results: []
},
mounted(){
axios.get("xxxxx")
.then(response => {
this.results = response.data
})
}
}
</script>
hello_vue.js:
import Vue from 'vue'
import App from './app.vue'
document.addEventListener('DOMContentLoaded', () => {
document.body.appendChild(document.createElement('hello'))
const app = new Vue(App).$mount('hello')
console.log(app)
})
that allow me to insert the information in the views like:
<%= javascript_pack_tag 'hello_vue' %>
and works it show the information.
But when I try to make a new folder with new files like this :
app/javascript
└── datos
├── app2.vue
└── hello2_vue.js
app2:
<template>
<div id="app2">
<ul v-for="result in results">
<li>{{result.name}}</li>
</ul>
</div>
</template>
<script>
export default {
data: {
results: []
},
mounted(){
axios.get("xxxxxxxxxxxx")
.then(response => {
this.results = response.data
})
}
}
</script>
hello2:
import Vue from 'vue'
import App2 from './app2.vue'
document.addEventListener('DOMContentLoaded', () => {
document.body.appendChild(document.createElement('hello2'))
const app2 = new Vue(App2).$mount('hello2')
console.log(app2)
})
and them load the files:
<%= javascript_datos_tag 'hello2_vue' %>
it show this error:
undefined method `javascript_datos_tag' for #<#<Class:0x0055a86f9b0218>:0x007fd3cf6d9958>
Did you mean? javascript_cdata_section
javascript_tag
javascript_pack_tag
Sorry for that guy I just check my server foreman and apparently it needs to be re-start every time I add new views ans requests, in the foreman server like.
$foreman start

Resources