3
votes

I'm trying to build a vuejs (that uses vuetify 2.1.4) component library and import it into another application locally via npm link but I keep on getting multiple errors saying either

TypeError: Cannot read property 'rtl' of undefined

or

TypeError: Cannot read property 'lang' of undefined

Note. The basic component for testing called Test works as it doesn't include anything from Vuetify.

Here's a screenshot

enter image description here

App1 (App that's being built)

index.js

import Agent from '@/components/Agent'
import Test from '@/components/Test'

const AgentLibrary = {
  install(Vue, options = {}) {
    Vue.component(Test.name, Test)
    Vue.component(Agent.name, Agent)
  }
}

export default AgentLibrary

Agent.vue

<template>
  <v-container>
    <!-- Header -->
    <v-row>
      <v-col md="5" class="col-center-content">
        <h2>Agent Information</h2>
      </v-col>

      <v-spacer></v-spacer>

      <v-col md="3">
        <v-btn text rounded>Cancle</v-btn>
        <v-btn rounded>Save</v-btn>
      </v-col>
    </v-row>

    <!-- Form -->
    <v-row>
      <v-col md="5">
        <AvatarUploader />
      </v-col>

      <v-col md="7">
        <v-row>
          <v-col md="6">
            <v-select rounded placeholder="Agent Type" outlined></v-select>
          </v-col>
          <v-col md="6">
            <v-select rounded placeholder="No. Parents" outlined></v-select>
          </v-col>
          <v-col md="12">
            <v-text-field rounded placeholder="Licensekey" outlined disabled></v-text-field>
          </v-col>
        </v-row>
      </v-col>
    </v-row>
  </v-container>
</template>
<script>
import AvatarUploader from "@/components/AvatarUploader";

export default {
  name: "Agent",
  components: {
    AvatarUploader
  }
};
</script>
<style lang="scss" scoped>
span {
  font-size: 20px;
  color: rgb(162 162 162);
}
.col-center-content {
  display: flex;
  justify-content: center;
}
</style>

test.vue

<template>
<div>
    <h1>HELLO WORLD!</h1>
</div>
</template>
<script>
export default {
    name: "Test",
    mounted() {
        console.log("HELLO WORLD!")
    }
}
</script>
<style lang="scss" scoped>

</style>

package.json

{
  "name": "AgentComponents",
  "main": "dist/AgentComponents.umd.js",
  "module": "dist/AgentComponents.esm.js",
  "unpkg": "dist/AgentComponents.min.js",
  "browser": {
    "./sfc": "src/components/Agent.vue"
  },
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "lint": "vue-cli-service lint",
    "build": "vue-cli-service build",
    "build:plugin": "cross-env NODE_ENV=production NODE_OPTIONS='--max-old-space-size=8192' vue-cli-service build --target lib --inline-vue --name AgentComponents src/index.js"
  },
  "dependencies": {
    "core-js": "^2.6.5",
    "moment": "^2.24.0",
    "rollup": "^1.24.0",
    "vue": "^2.6.10",
    "vue-router": "^3.0.3",
    "vuetify": "^2.1.4",
    "vuex": "^3.0.1"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "^3.12.0",
    "@vue/cli-plugin-eslint": "^3.12.0",
    "@vue/cli-service": "^3.12.0",
    "cross-env": "^5.2.0",
    "babel-eslint": "^10.0.1",
    "eslint": "^5.16.0",
    "eslint-plugin-vue": "^5.0.0",
    "rollup-plugin-buble": "^0.19.8",
    "rollup-plugin-commonjs": "^10.1.0",
    "rollup-plugin-vue": "^5.0.1",
    "sass": "^1.17.4",
    "sass-loader": "^7.1.0",
    "vue-cli-plugin-vuetify": "^1.0.2",
    "vue-template-compiler": "^2.6.10",
    "vuetify-loader": "^1.2.2"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    "rules": {},
    "parserOptions": {
      "parser": "babel-eslint"
    }
  },
  "postcss": {
    "plugins": {
      "autoprefixer": {}
    }
  },
  "browserslist": [
    "> 1%",
    "last 2 versions"
  ]
}

avataruploader.vue

<template>
  <v-row>
    <v-col md="12" class="col-center-content">
      <v-avatar size="230" color="rgb(232 239 244)">
        <v-img aspect-ratio="1" width="200px" src="@/assets/user-alt.png"></v-img>
      </v-avatar>
    </v-col>

    <v-col md="12">
      <v-file-input
        ref="file"
        accept="image/png, image/jpeg, image/bmp"
        placeholder="Pick a logo"
        label="Your photo or company logo"
      ></v-file-input>
    </v-col>
  </v-row>
</template>
<script>
export default {
  name: "AvatarUploader"
};
</script>
<style lang="scss" scoped>
span {
  font-size: 20px;
  color: rgb(162 162 162);
}
.col-center-content {
  display: flex;
  justify-content: center;
}
</style>

App2 (App that is importing App1)

main.js

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

import vuetify from './plugins/vuetify';

import "AgentComponents"

console.log(AgentComponents.default)

Vue.use(AgentComponents.default)

new Vue({
     vuetify,
  render: h => h(App)
}).$mount('#app')

app.vue

<template>
  <v-app>
      <Agent/>
  </v-app>
</template>

<script>

export default {
  name: 'App',
  components: {
  },
  data: () => ({
    //
  }),
};
</script>

plugins/vuetify.js

import Vue from 'vue';
import Vuetify from 'vuetify/lib';

Vue.use(Vuetify);

export default new Vuetify({
  icons: {
    iconfont: 'mdi',
  },
});

I expected to see my Agent component in App1 displayed and working as usual (running npm run serve) when built and imported into App2 without any errors.

Errors being displayed in my chrome browser can be seen bellow: I see multiple of the errors shown bellow in the Chrome console when running

TypeError: Cannot read property 'rtl' of undefined
    at VueComponent.labelPosition (AgentComponents.umd.js?7204:17243)
    at Watcher.get (AgentComponents.umd.js?7204:5517)
    at Watcher.evaluate (AgentComponents.umd.js?7204:5626)
    at VueComponent.computedGetter [as labelPosition] (AgentComponents.umd.js?7204:5791)
    at VueComponent.genLabel (AgentComponents.umd.js?7204:17422)
    at VueComponent.genTextFieldSlot (AgentComponents.umd.js?7204:17541)
    at VueComponent.genDefaultSlot (AgentComponents.umd.js?7204:17422)
    at VueComponent.genInputSlot (AgentComponents.umd.js?7204:16327)
    at VueComponent.genInputSlot (AgentComponents.umd.js?7204:17422)
    at VueComponent.genControl (AgentComponents.umd.js?7204:16290)
TypeError: Cannot read property 'lang' of undefined
    at VueComponent.listData (AgentComponents.umd.js?7204:22317)
    at Watcher.get (AgentComponents.umd.js?7204:5517)
    at Watcher.evaluate (AgentComponents.umd.js?7204:5626)
    at VueComponent.computedGetter [as listData] (AgentComponents.umd.js?7204:5791)
    at VueComponent.staticList (AgentComponents.umd.js?7204:22317)
    at Watcher.get (AgentComponents.umd.js?7204:5517)
    at Watcher.evaluate (AgentComponents.umd.js?7204:5626)
    at VueComponent.computedGetter [as staticList] (AgentComponents.umd.js?7204:5791)
    at VueComponent.genList (AgentComponents.umd.js?7204:22596)
    at VueComponent.genMenu (AgentComponents.umd.js?7204:22624)
1
rtl and lang are normally in the html tag, is there a mix up with what Vue is given as the app in the HTML?Thomas Edwards
@ThomasEdwards I'm not really sure as of what you mean, rtl and lang aren't being specified anywhere so I'm assuming it's something that's coming from the Vuetify lib.Joakim Allen
From looking at the Vuetify source it would appear that these errors come from lines that access this.$vuetify.rtl and this.$vuetify.lang respectively. This suggests that this.$vuetify is undefined. Usually that indicates that you aren't passing vuetify to your new Vue but the code you've posted does seem to be correct in that regard.skirtle
@skirtle I've noticed that if I comment/remove the select field and the file input field I no longer get an error and the component works as intended. So I'm assuming that this is simply a bug within Vuetify and not really something that I can fix from my application.Joakim Allen
@Joakim I think it's unlikely this is a bug in Vuetify. When Vuetify is initialised it is supposed to add a $vuetify property to all components and those two components are assuming it will be there. Why that isn't happening here I don't know but it should be debuggable just by stepping through in the browser to see why it isn't doing what it normal does. Don't be afraid of the Vue/Vuetify code, if you do a bit of stepping through you'll learn a lot and may be able to solve this.skirtle

1 Answers

0
votes

This is happening because of the --inline-vue flag. It tells Vue to create its own instance and bundle it inside your library (see here for a detailed description).

When you instantiate Vue in your code, you do something like this:

new Vue({
    vuetify,
    ...
});

However, when Vue does this for you, it doesn't pass the vuetify plugin as an option to the Vue constructor.

One solution is removing the --inline-vue flag. But, I'm not sure this is relevant in your case.

I opened a Github issue/question on the Vuetify repo, https://github.com/vuetifyjs/vuetify/issues/10198, asking if they're planning on supporting this flag.