6
votes

I'm using Rails 5.2.0 and Webpacker gem to deploy a Vue application.

The show.html.erb file is very simple:

<div data-behavior="vue-app"><MyComponent></MyComponent></div>

And then in my entry pack, packs/my_vue_app.js:

import TurbolinksAdapter from 'vue-turbolinks';
import Vue from 'vue/dist/vue.esm'
Vue.use(TurbolinksAdapter);
import MyComponent from '../components/my_app/index.vue'

document.addEventListener('turbolinks:load', () => {

  var element = $('[data-behavior="vue-app"]');

  if(!element) { return };

  console.log('Initializing Vue');

  const app = new Vue({
    el: element[0],
    data: {

    },
    components: { MyComponent }
  })
})

In development, everything works absolutely fine. The app is mounted and functional.

But in production, after the page load and JS runs, <div data-behavior="vue-app"> is removed from the paging, leaving only <!-- --> in it's place.

In the console, there are absolutely no errors. I can confirm using DevTools that the pack js file is loaded, and it was parsed, since the console.log is printed in the console.

Heck, the proof that Vue is working is that the entire <div> where it was mounted was removed from DOM after JS parsing.

The weirdest thing of all is that I could get the app to mount ONCE, by attaching a debugger on the console.log line and turning it off while the debugger paused execution. Even tough I saw the app mounting that time, I could not get it to mount later on, even fiddling with the debugger again ... it's really, really weird.

These are the versions of package.json:

"vue": "^2.5.16", "vue-loader": "14.2.2", "vue-template-compiler": "^2.5.16",

The Rails app is brand new, with no config other than the default.

Webpacker gem is 3.5.3 and Rails is 5.2.0.

After spending a really long time on this, I only found this github issue: https://github.com/rails/webpacker/issues/1520

EDIT: I'm providing a link to the real, production app where this bug is happening: https://planilha.tramitacaointeligente.com.br/planilhas/ED2sUXz32-R9CJKdkmtf8Q

You'll see it's not mounting. Here's the same page in development:

screenshot of app mounted

2
I'm having the same problem with my app in production with chrome browser. It worked with firefox, though. I can see the app you linked working fine. Did you managed to solve it?torce

2 Answers

7
votes

I eventually managed to solve it by changing how the Vue app loading was defined.

Try import Vue from 'vue' (instead of from 'vue/dist/vue.esm') and then:

const app = new Vue({
    el: domElement,
    render: h => h(RootComponent)
  })

The comments that appear in the hello_vue.js scaffold from the Webpacker gem tell you that you can choose between using the DOM as your template OR load the component with a render function; they both do work in development, but only the latter (loading the component with a render function, using vue instead of vue/dist/vue.esm and render: h => h(RootComponent) worked for me in production.

This has been, by far, the longest, most frustrating debugging session of my life, since there are absolutely no errors in console, you just stare into a blank screen, and Vue is running since it removes the DOM element it was mounted to from the DOM.

Source of solution: https://stackoverflow.com/a/48651338/1290457 and here's the github issue (currently open) on Webpacker gem https://github.com/rails/webpacker/issues/1520

I still don't know how to use DOM as template with Vue in production tough.

5
votes

I had similar problem in Rails 5.2 + webpack Vue. All was good in development, but not working in production. After hours of investigating I found the reason. It was in this recommendation from webpaker gem docs.

Adding this

Rails.application.config.content_security_policy do |policy|
  if Rails.env.development?
    policy.script_src :self, :https, :unsafe_eval
  else
    policy.script_src :self, :https
  end
end

brokes production. Removing else part - fixing the situation.

Chrome silently ignoring this. Firefox shows warnings.