Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Webpack to expose Vue to globally

I'm working in a legacy Rails app that has been partially migrated to use Webpacker and Vue. We also have a legacy script that is being loaded through a CDN. That script needs to use Vue too but, we'd rather not bundle Vue into it and just use the Vue that's already in the legacy Rails app.

I've followed this question How to expose Vue as global object and I got to that point, using expose-loader, to expose the Vue object at Vue.default. Essentially the exposed "Vue" object is actually a Module and the real Vue object is nested in Vue.default.

I got to that point by following all the docs and articles I could find. These were the most relavant I could find: https://bibwild.wordpress.com/2019/08/01/dealing-with-legacy-and-externally-loaded-code-in-webpacker/

It seems less than ideal and I'm wondering if there's a "more correct" way of exposing Vue directly i.e. not nested in the Module default.

What I've tried

I created a new Rails 6 app from scratch. After adding the JS dependencies via:

yarn install
yarn add vue
yarn add -D expose-loader
yarn add -D webpack-dev-serer
rails webpacker:install

I added the expose-loader config to config/webpack/development.js

environment.loaders.append('expose', {
  test: require.resolve('vue'),
  use: [{
      loader: 'expose-loader',
      options: 'Vue'
  }]
})

I then scaffolded a page and made it the root route.

Then created an entry JS file at app/javascript/packs/application.js

import Vue from 'expose-loader?Vue!vue'
console.log({ pack: Vue })

And in the application layout, under the javascript_pack_tag 'application', I have:

<script>
  try {
    console.log({ layout: Vue })
  } catch (error) {
    console.warn('Global Vue not found')
  }
</script>

Now in the browser console I get

{ pack: ƒ Vue(options) }
{ layout: Module
    default: ƒ Vue(options) }

I've also tried different configs in config/webpack/development.js for the expose-loader, such as:

  test: require.resolve('vue/dist/vue.esm.js')
// or
  test: require.resolve('vue/dist/vue.esm.js').default
// or
  test: require.resolve('expose-loader?Vue!vue')
// and different permutations of that.

Another approach I tried was to directly shove Vue into the window object from my application.js pack file. That works but seems wrong as well. Is there a better way?

Question

How do I expose the Webpacker managed Vue object so any non-Webpacker managed script can see it? i.e. make it available on the window object.

like image 778
DiegoSalazar Avatar asked Nov 06 '22 10:11

DiegoSalazar


1 Answers

I've managed to do it with following config rule in webpack

{
  test: require.resolve("vue/dist/vue.esm.js"),
  loader: "expose-loader",
  options: {
    exposes: [{
      globalName: "Vue",
      moduleLocalName: "default",
    }]
  },
},

moduleLocalName just extracts Vue from property default and expose it with globalName so when you access window.Vue it will be there

like image 139
Mati Avatar answered Nov 15 '22 05:11

Mati