Importing Vue 3 script setup components with WebStorm - vue.js

Is there a way to make automatic imports and code completion in WebStorm to work properly with Vue 3 components using <script setup>? Because I have met some troubles with it:
Let's say I have a component called FooBar.vue:
<script setup lang="ts">
import { ref } from 'vue'
const counter = ref(0)
</script>
Now I want to import it, but the code completion doesn't suggest it:
However, when I replace <script setup> with a regular <script>, everything works as expected
<script lang="ts">
import { ref } from 'vue'
export default {
setup() {
const counter = ref(0)
return { counter }
},
}
</script>
My theory is that WebStorm looks at the export statements to provide automatic imports and code completion. And since script setup does not have one, this leads to this problem. Is there any workarounds / ways to configure WebStorm to fix that?

WEB-54446 is fixed in 2022.3, the fix will be included in the next 2022.3 EAP

Related

Can i use multiple Vue Composable functions in one file? how do I structure it?

Can i use multiple vue composables in one file?
example:
<script>
export function arrayToInt(arr) {
...
}
export function arrayToUint(arr) {
...
}
</script>
then somewhere else:
import {arrayToInt, arrayToUint} from "./useBytesHelper"
because im getting a vue router parsing error right at the beggining when loading my app. and i might be doing this wrong
Considering that the file is JavaScript module (useBytesHelper.js) and not Vue SFC (useBytesHelper.vue), it's incorrect to use <script> tag there.
The rest is correct, it should be used as listed:
import {arrayToInt, arrayToUint} from "./useBytesHelper"

How to use Vue in an existing typescript application without modules?

I'm trying to use Vue in "progressive enhancement" mode in an existing site, which already uses Typescript extensively.
The vue tutorial shows code like this:
<script type="module">
import { createApp, reactive, ref } from 'vue'
createApp({
setup() {
const counter = reactive({ count: 0 })
const message = ref('Hello World!')
return {
counter,
message
}
}
}).mount('#app')
</script>
<div id="app">
<h1>{{ message }}</h1>
<p>Count is: {{ counter.count }}</p>
</div>
But I don't want to have javascript in the html file, I want to relocate that code to a proper typescript file. But when I do this, I get compilation errors no matter how I try to arrange this.
If I don't qualify anything, I get errors like Error TS2304 (TS) Cannot find name 'createApp'. This makes sense because the whole point of Typescript is to type check and not let you reference unknown things.
So I try to import Vue like this:
import { Vue } from '../../node_modules/vue/dist/vue.global.js';
and change the call to Vue.createApp(...). This causes the browser error Cannot use import statement outside a module
If I try instead:
let { Vue } = require('../../node_modules/vue/dist/vue.global.js')
I get require is not defined.
I tried getting the vue.d.ts typings from https://github.com/vuejs/vue/blob/dev/types/vue.d.ts and referencing the file with /// <reference path="../../Scripts/vue.d.ts" />" />, but this just doesn't work, giving Error TS2304 (TS) Cannot find name 'Vue'.
I have tried many, many permutations of this but all of them run into one error or another.
So the question is: how can I retrofit Vue into an existing Typescript app without modules?

Redirecting users after an action

I am trying to achieve having a redirection if the user logs in successfully. I was trying to call this.$router.push('/profile') with then the call back after login however I get an error stating Error Cannot read properties of undefined (reading '$router') I am not sure if there is a new flow to how to get this done since I am using composition with <script setup> syntax. I read the document reference online but still not seeing anything concrete as to how to do this type of navigation now. How can I achieve this with the new vue3 composition api? It seems I am missing something.
If you use setup() inside the script, you can't access the router with $router.
if you use vue3, this code can help you:
<script>
import { defineComponen } from 'vue'
import { useRouter } from 'vue-router'
export default defineComponent({
setup() {
const router = useRouter()
function login() {
router.push('/profile')
}
return {
login
}
}
})
</script>

How to make a dynamic import in Nuxt?

In my nuxt component I want to use the ace editor:
import Ace from "ace-builds/src-noconflict/ace"
when the component is mounted I am doing the following:
this.editor = Ace.edit...
Obviously the window is not defined on the server on page reload. But unfortunately I just can't find a solution to fix this issue.
Is there a way to import a package on the mounted() hook?
I already tried
const Ace = require("ace-builds/src-noconflict/ace")
But that doesn't quite seem to work. Do you have any ideas to solve this issue?
I already tried to register a plugin plugins/ace.js:
import Vue from "vue"
import Ace from "ace-builds/src-noconflict/ace"
Vue.use(Ace)
registered it in nuxt.config.js:
plugins: [
{ src: "~/plugins/ace", mode: "client" }
],
But how do I use Ace in my component now? It is still undefined...
Since the error was thrown during the import statement, I'd recommended using dynamic imports as explained in my other answer here.
async mounted() {
if (process.client) {
const Ace = await import('ace-builds/src-noconflict/ace')
Ace.edit...
}
},
From the official documentation: https://nuxtjs.org/docs/2.x/internals-glossary/context
EDIT: I'm not sure about Ace and it's maybe a drastic change but you may also give a look to vue-monaco which is elbow-to-elbow popularity wise (vanilla Monaco editor).
EDIT2: mounted actually only runs on the client so you could strip the process.client conditional. Meanwhile, I do let it here in case you want to run some logic in other hooks like created (which are run on both server + client). More info here.
EDIT3: not directly related to the question, but some packages expose a component which is only available on the client-side (no SSR support), in those cases you could import the component only on the client side and easily prevent any other errors.
Nuxt Plugin
IMHO you were on the right track with the "plugin" solution. Only mistake was the
Vue.use(Ace) part. This only works for vue plugins.
The plugin file could look somewhat like that:
import Ace from 'ace-builds/src-noconflict/ace'
import Theme from 'ace-builds/src-noconflict/theme-monokai'
export default ({ app }, inject) => {
inject('ace', {
editor: Ace,
theme: Theme
})
}
Then you could use this plugin and initiate the editor in a component this way:
<template>
<div id="editor">
function foo(items) {
var x = "All this is syntax highlighted";
return x;
}
</div>
</template>
<script>
export default {
data () {
return {
editor: {}
}
},
mounted () {
this.editor = this.$ace.editor.edit('editor')
this.editor.setTheme(this.$ace.theme)
}
}
</script>

Can't build Gridsome website with Vue2 Smooth Scroll

It works in develop mode but it does not build: 'ReferenceError: window is not defined'
I do understand it is a problem with SSR support, although it says it has support to it
I have tryed to implement some similar approaches of integration as seen here:
https://gridsome.org/docs/assets-scripts/#without-ssr-support
Import Vue-Navigation-Bar in Gridsome
I've tryed a lot of approaches in main.js and my template.vue files, but I'm failing to understand the logic for adapting the solution perfectly.
My last approach which worked on develop:
On my template.vue file:
<section id="cover"></section>
<ClientOnly><p class="text-light">Text <a :href="href" class="text-light under" v-smooth-scroll="{ duration: 1000, updateHistory: false }">click here</a></p></ClientOnly>
<script>
import Vue from 'vue'
import vueSmoothScroll from 'vue2-smooth-scroll'
Vue.use(vueSmoothScroll)
</script>
Also have tryed to set 'container' option to '#app' or '#body' added to the body, but it didn't work not even in develop.
OK, I could find it here:
https://github.com/gridsome/gridsome/issues/180#issuecomment-513550238
It doesn't need <ClientOnly></ClienteOnly> tags in template.vue file
In main.js, I have made this changes:
//import vueSmoothScroll from 'vue2-smooth-scroll'
//Vue.use(vueSmoothScroll);
export default function (Vue, { router, head, isClient }) {
...
if (process.isClient) {
const vueSmoothScroll = require('vue2-smooth-scroll').default;
Vue.use(vueSmoothScroll);
}
}