composition api doesn't work with Nuxt-TS - javascript

Created nuxt app using npx create-nuxt-app. Followed documentation at https://typescript.nuxtjs.org, however i have an issue using #vue/composition-api:
example component.vue:
<template>
<div>
{{ msg }}
</div>
</template>
<script lang="ts">
import { createComponent, ref } from '#vue/composition-api'
export default createComponent({
setup() {
const msg = ref('hello')
return {
msg
}
}
})
</script>
Doesn't work, throws an error "Property or method "msg" is not defined on the instance but referenced during render." because it doesn't see my ref. I've added composition API as plugin in "plugins/composition-api.ts":
import Vue from 'vue'
import VueCompositionApi from '#vue/composition-api'
Vue.use(VueCompositionApi)
Then in nuxt.config.ts:
plugins: ['#/plugins/composition-api']

My bad, forgot about TS-runtime in nuxt:
npm i -S #nuxt/typescript-runtime
Then you need to update package.json: https://typescript.nuxtjs.org/guide/runtime.html#installation

Related

How to create component library in vuejs

Motivation
Create vuejs library with components (buttons, headers,...) for re-using it in more projects so they looks the same in different projects.
My not working idea
I would like to reach something like this:
When you have these files
/src/components/TestComponent.vue - vue SFC
/src/main.js
/src/package.js
Where:
TestComponent.vue:
<template>
<div class="test-component">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: 'test-component',
props: {
msg: String
}
}
</script>
<style scoped>
</style>
/src/main.js export that component:
import testComponent from './components/TestComponent.vue'
export { testComponent }
packake.json contains build description which should create library:
{
"name": "#my/test-lib",
"scripts": {
"build": "vue-cli-service build --target lib --name test-lib src/main.js",
...
So I can build it via npm run build and afterwards npm publish to private repo and afterwards use component TestComponent in another project like this:
<template>
<div>
<test-component msg="TEST"></test-component>
</div>
</template>
<script>
import { testComponent } from "#my/test-lib"
export default {
name: "usage-test",
components: {
testComponent
}
};
</script>
<style scoped>
</style>
---> Except it doesnt work. It fails on Cannot find module '#my/test-lib'. My guess is that I am doing export somehow wrong. Can someone provide a hint?
Working idea
TestComponent.vue looks exactly the same as above
main.js use #vue/web-component-wrapper:
import Vue from "vue";
import wrap from "#vue/web-component-wrapper";
import testComponent from "./components/TestComponent.vue";
const wrappedTestComponent = wrap(Vue, testComponent);
window.customElements.define("test-component", wrappedTestComponent);
But this solution has a limitation. When usage - it accepts only String props. So no Objects by nature (I am not counting ser / deser brittle solution)

Vue 3 dynamic component inside setup template

I have following problem.
<script setup lang="ts">
import { RouterView } from "vue-router";
import defaultLayout from "#/layouts/default.vue";
import { useDefaultStore } from "#/stores/default";
let { getLayout } = useDefaultStore();
</script>
<template>
<component :is="getLayout">
<RouterView />
</component>
</template>
I use Pinia as the store. I checked getLayout its getting defaultLayout
I know in Vue.js 2 you had to register it:
export default {
components: {
defaultLayout
}
}
How do i do it now?
You can't descructure the store like that, you have to use Pinias storeToRefs() (https://pinia.vuejs.org/core-concepts/#using-the-store). Maybe it has something to do with that, I can't tell without the code of the store.
I'd recommend using this plugin https://github.com/JohnCampionJr/vite-plugin-vue-layouts if you're using Vite and need layouts.
Use defineAsyncComponent
defineAsyncComponent(() => import("#/layouts/default.vue"))
or register the component globally in your main.js:
app.component('defaultLayout', defaultLayout)

[Vue warn]: Failed to resolve component when tried to create global component

I new on Vue Typescript. I've tried to create global components but I got a warning and component not loaded on the template. This how I tried to create global components
App.vue
import { createApp } from "vue"
import App from "./App.vue"
import "./registerServiceWorker"
import "./globalComponents"
import router from "./router"
import store from "./store"
createApp(App)
.use(store)
.use(router)
.mount("#app")
globalComponents.ts
import { createApp } from "vue"
const app = createApp({})
// Forms
app.component("ui-input", () => import("#/components/core/ui/Input.vue"))
Input.vue
<template lang="pug">
.ui-input
input(v-model="$attrs" v-on="$listeners")
</template>
<script lang="ts">
import { defineComponent } from "vue"
export default defineComponent({
inheritAttrs: false
})
</script>
Hope you all can help me, Thanks in advance
As of Vue 3, if you create an app using createApp, it will be a standalone Vue App instance. So if you need to add a global component then you will need to add it on the app object created from createApp, here's the code for that:
const app = createApp({});
app.component('my-component-name', MyComponent) // <-- here you can register.
app.mount("#app");
But if there are a lot of components then adding them in the main.ts file will be a mess, so we can create another file, like you did, so:
Your current globalComponents.ts
import { createApp } from "vue"
const app = createApp({})
// Forms
app.component("ui-input", () => import("#/components/core/ui/Input.vue"))
The Problem
But notice here's a mistake. What is it? You created another app using createApp. As I referred earlier that if you need to create a global component, you can only create on the same instance.
Fix
As we know the problem here is that we are creating another instance, which is again a new and standalone instance, so we need to figure out the way we can have the same app instance in globalComponents.ts as well, so we will pass the app from main-ts to globalComponents.ts, like:
globalComponents.ts
import { App } from "vue";
// register components
export const registerComponents = (app: App): void => {
app.component("ui-input", () => import("#/components/core/ui/Input.vue"));
}
And now you can call registerComponents in main.ts as:
main.ts
const app = createApp(App)
.use(store)
.use(router);
registerComponents(app); // <-- here you go
app.mount("#app");
You will still get something like:
[Vue warn]: Invalid VNode type: undefined (undefined).
You can read more here about how to define an async component in vue 3. To fix that error you will need to wrap your import in defineAsyncComponent as:
globalComponents.ts
import { defineAsyncComponent } from "vue";
// register components
export const registerComponents = (app) => {
app.component(
"ui-input",
defineAsyncComponent(() => import("#/components/Input.vue"))
);
};

Vue plugin with Typescript - Cannot read property '_init' of null

I need to create Vue plugin containing a few reusable components. I want to create this using TypeScript. There are my files:
components/SampleButton.vue
<template>
<button>Sample button</button>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
name: 'sample-button',
});
</script>
main.ts
import SampleButton from './components/SampleButton.vue';
export {
SampleButton,
};
export default {
install(Vue: any, _options: object = {}): void {
Vue.component(SampleButton.name, SampleButton);
},
};
shims-vue.d.ts
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
}
Plugin building is successful, but when I try to user the plugin in my app I get an error:
import MyPlugin from 'my-plugin'
Vue.use(MyPlugin)
Please help me find a mistake :)

Vue.js using local javascript file functions in component: Uncaught TypeError: __WEBPACK_IMPORTED_MODULE_0__.writeSomething is not a function

I am trying to import a local JS file into a single file component in a Vue application. My application is a scaffold generated by vue-CLI (ver 3.8.2).
Here are my relevant code snippets (all other code in application is unchanged from generated code):
/path/to/app-vue/src/components/HelloWorld.vue
<template>
<div class="hello">
<Module1/>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import Module1 from './Module1.vue';
#Component({
components: {
Module1,
}
})
export default class HelloWorld extends Vue {
#Prop() private msg!: string;
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
/path/to/vue-app/src/components/Module1.vue
<template>
<div class="module1">
Module2
</div>
</template>
<script>
import { Component, Prop, Vue } from 'vue-property-decorator';
import Module2 from './Module2.vue';
#Component({
components: {
Module2,
},
})
export default class Module1 extends Vue {
}
</script>
/path/to/vue-app/Module2.vue
<template>
<div id='demo'>
</div>
</template>
<script>
import foo from '../assets/js/foo';
foo.writeSomething('#demo');
</script>
/path/to/vue-app/src/assets/js/foo.js
function writeSomething(el) {
elem = window.document.getElementById(el);
elem.innerHTML = 'Hello World!';
}
export default {
writeSomething
}
When I run npm run serve and navigate to '/' in the browser, I get the following error messages in the console:
"export 'default' (imported as 'mod') was not found in
'-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Module2.vue?vue&type=script&lang=js&'
And in the browser DevTools console, I get the following stack trace:
Uncaught TypeError: _assets_js_foo__WEBPACK_IMPORTED_MODULE_0__.writeSomething is not a function
at eval (Module2.vue?df9f:9)
at Module../node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/Module2.vue?vue&type=script&lang=js& (app.js:1078)
at __webpack_require__ (app.js:767)
at fn (app.js:130)
at eval (Module2.vue?35cf:1)
at Module../src/components/Module2.vue?vue&type=script&lang=js& (app.js:3448)
at __webpack_require__ (app.js:767)
at fn (app.js:130)
at eval (Module2.vue?6104:1)
at Module../src/components/Module2.vue (app.js:3436)
How do I load local javascript files into a Single File Component, and use functions defined in the loaded Javascript (within the component)?
You need to explicitely export the function and import it using its name.
Module2.vue
import { writeSomething } from '../assets/js/foo.js';
writeSomething('#demo');
export default { ...
foo.js
export function writeSomething(el) {
elem = window.document.getElementById(el);
elem.innerHTML = 'Hello World!';
}
If you are using typescript, make sure that you can import js modules
you can also export a default module
function writeSomething(el) {
elem = window.document.getElementById(el);
elem.innerHTML = 'Hello World!';
}
export default {
writeSomething
}
and import it as
import foo from '../assets/foo.js';
// ...
foo.writeSomething('#demo');
Export default should specify a name like below:
export default writeSomething;
Named Exports
Can export multiple values
MUST use the exported name when importing
Default Exports
Export a single value
Can use any name when importing
You can see more about Named Export and Default Export here

Categories