Vue3 top-level await Eslint fails - async-await

Following the official documentation: https://vuejs.org/api/sfc-script-setup.html#top-level-await
I'm trying to create an async component like that:
<template>
<p>Async data: {{asyncData}}</p>
</template>
<script setup>
import {ref} from 'vue'
const asyncData = ref(null)
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
await sleep(2000);
asyncData.value = 'abcd1234'
</script>
The component works fine.
The problem is: Eslint detects that error:
Parsing error: Cannot use keyword 'await' outside an async function
How can I deal with that?
In fact it's Vue who is forcing me to write an invalid code...

I see it can be solved updating Eslint config:
.eslintrc.cjs
module.exports = {
root: true,
parserOptions: {
sourceType: "module",
ecmaVersion: 2022,
},
...
};
But shouldn't be as default?

Related

Svelte Library [Ckeditor 5] works as node module but not locally

I'm trying to add Ckeditor5 to Sveltekit.
Using the node module works perfectly. I import the library onMount and use it.
// Works flawlessly
<script>
import { onMount } from 'svelte';
let Editor;
onMount(async () => {
const module = await import('#ckeditor/ckeditor5-build-balloon-block');
Editor = module.default;
Editor.create(document.querySelector('#editor'), {}).then((editor) => {
console.log(editor);
});
});
</script>
If I try to import a local build, however, module.default is always undefined. The same happens even when I just copy the node_module.
<script>
import { onMount } from 'svelte';
let Editor;
onMount(async () => {
// Import changed to local build
const module = await import('src/lib/ckeditor');
Editor = module.default;
Editor.create(document.querySelector('#editor'), {}).then((editor) => {
console.log(editor);
});
});
</script>
It's also worth noting that logging the local module just prints:
ModuleĀ {Symbol(Symbol.toStringTag): 'Module'} to the console.
Can you share your /src/lib/ckeditor file contents?
Sidenote. when accessing DOM elements, you can do the folowing instead of using document.querySelector
<script>
let editorEl;
onMount(()=>{
Editor.create(editorEl, {})
})
</script>
<div bind:this={editorEl}></div>

How can we pass parameters to Alpine.data in Alpine.js v3?

I am now using the newest version of Alpine which is v3.
Making reusable components needs to be registered using the Alpine.data.
This is the alpinejs.js
import Alpine from 'alpinejs'
import form from './components/form'
window.Alpine = Alpine
Alpine.data('form', form)
Alpine.start()
This is what I have in the components/form.js
export default (config) => {
return {
open: false,
init() {
console.log(config)
},
get isOpen() { return this.open },
close() { this.open = false },
open() { this.open = true },
}
}
This is the html part:
<div x-data="form({test:'test'})"></div>
This is the error I get in the console:
Any idea how to pass parameters to Alpine.data?
I stumbled over this question, searching for an answer but figured it out now. Maybe its still usefull to someone...
You have do define the parameter when registering the data component:
document.addEventListener('alpine:init', () => {
window.Alpine.data('myThing', (param) => MyModule(param));
});
Now you can use it in your module on init...
export default (param) => ({
init() {
console.log(param);
}
});
... when you init the component
<div x-data="deliveryDate({ foo: 'bar' })"></div>
This likely happens since you imported your script as a module. Therefore, you need another script that handles initialization of data.
I'm using a vanillajs vite setup and here's a working implementation with alpinejs:
index.html
<head>
<!-- Notice the type="module" part -->
<script type="module" src="/main.js" defer></script>
<script src="/initializer.js"></script>
</head>
<body x-data="greetingState">
<button #click="changeText">
<span x-text="message"></span>
</button>
<h2 x-text="globalNumber"></h2>
</body>
main.js
import Alpine from 'alpinejs';
window.Alpine = Alpine;
Alpine.start();
// const globalNumber = 10; // Wrong place
initialize.js
document.addEventListener('alpine:init', () => {
Alpine.data('greetingState', () => ({
message: "Hello World!",
changeText() {
this.message = "Hello AlpineJs!";
},
}));
});
const globalNumber = 10; // Correct place
Note that listening to the alpine:init custom event inside of a javascript module will break the app. The same happens if you try to display a variable from a script of type module, in this example globalNumber.

How to handle apollo errors in one place with react-hooks?

I'm using React with hooks + GraphQL.
My app.jsx:
import { onError } from 'apollo-link-error';
...
const httpLink = ...
const errorLink = onError(err => console.log(err))
const terminatingLink = split(...httpLink, errorLink)
const client = new ApolloClient({
link: ApolloLink.from([terminatingLink])
...
})
<ApolloProvider client={client}>
<ErrorProvider>
</ErrorProvider>
</ApolloProvider>
Error provider is used as a common state for errors, i.e. if mutation response is bad.
Currently I create onError handler for each(!) mutation and query, i.e. like this:
const [createTeam] = useMutation(createTeamQ, {
onError: (err) => { dispatchError(err) }
})
This looks like overcoding, since I do it too often.
But I can't figure out how to dispatch the error in AppolloClient only once in onError() function imported from 'apollo-link-error'. I can't use hooks there.
Should I use redux for this particular case?
Thanks in advance.

laravel + vue router cannot get parameters from url

I try to get parameters from url
let's say url contains:
localhost:8000/blog?q=hello
I want to grab hello to trigger function call
What I had declare in app.js in laravel webpack:
import VueRouter from 'vue-router';
Vue.use(VueRouter);
const router = new VueRouter({
mode: 'history',
routes: []
})
const app = new Vue({
router
});
export default app;
In blog page, I try to extract the parameter from url
new Vue ({
el: "#blog-content",
},
mounted: function() {
q = this.$route.query.q
console.log(q)
}
)
I npm run dev to compile and run the blog page it show error:
TypeError: Cannot read property 'query' of undefined
what is wrong? I am sure that Vue Router is properly installed in the application.
I think that the blog page that you use is not correct.
You recreate another Vue instance and in that case that new instance doesn't have a router passed to it. So I think that's why this.$router is undefined.
Also you don't pass the view Component to your router so it doesn't know what to look for with the specific url.
Here's your app.js file corrected
import VueRouter from 'vue-router';
Vue.use(VueRouter);
import Blog from './views/Blog';
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/blog',
name: 'blog',
component: Blog
},
]
});
The blog view page template : views/Blog.vue
<template>
<div class="wrapper">
My blog page
</div>
</template>
<script>
export default {
data() {
return {
myvariable : ''
}
},
mounted() {
let q = this.$route.query.q;
console.log(q);
},
};
</script>
Now it should works correctly :)
Edit : Also you don't need to export the app variable in your app.js
Remove the following line export default app; at the end of the file

finally() not working in Vuejs another app

Recently I did this tutorial.
In this app I can successfully run a vuejs app and axios.then.catch.finally or this.form.then.catch.finally.
But I added npm to my old project that was recently upgraded to laravel 5.7.
In my app I can't add finally function. If i do, it says:
Uncaught TypeError: axios.post(...).then(...).catch(...).finally is not a function
My app.js:
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
// require('./bootstrap');
import Vue from 'vue'
window.Vue = Vue
window.axios = require('axios');
import { Form, HasError, AlertError } from 'vform'
window.Form = Form;
Vue.component(HasError.name, HasError)
Vue.component(AlertError.name, AlertError)
Vue.component('pagination', require('laravel-vue-pagination'));
//select 2
import vSelect from 'vue-select'
Vue.component('v-select', vSelect)
//sweet alert 1
import swal1 from 'sweetalert';
window.swal1 = swal1;
import swal from 'sweetalert2'
window.swal = swal;
const toast = swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000
});
window.toast = toast;
/**
* Next, we will create a fresh Vue ap
*
*
* plication instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
Vue.component('example-component', require('./components/ExampleComponent.vue'));
Vue.component('timetable-component', require('./components/TimetableComponent.vue'))
/* filter active and inactive */
Vue.filter('activeInactive', function (value) {
if(value==1){
return 'Active'
}else{
return 'Inactive'
}
})
const app = new Vue({
el: '#app',
data:{
},
methods:{
},
mounted(){
}
});
I think my app.js is exactly the same as the tutorial app.js for Form request.
Another thing is that in the tutorial he did not use axios import anywhere but he smoothly used it. But without import, I can't use axios.then.
How did he use it without importing axios?
How can I use finally with then.catch?
a componenet:
loadSite() {
axios
.get("/api/site/list")
.then(({ data }) => {
console.log(data);
this.siteList = data;
})
.catch(function(error) {
console.log(error);
}).finally(()=>{
});
},
As document, to make finally works, you need to add promise.prototype.finally
npm install axios promise.prototype.finally --save
and then
const axios = require('axios');
require('promise.prototype.finally').shim();
axios
.get('http://www.example.com/user')
.then((response) => {
console.log(response.data);
return response;
})
.finally(() => {
console.log('this will always be called');
});
I have the same issue, just solved it by includeing this file
<script src="https://polyfill.io/v3/polyfill.min.js?features=Promise.prototype.finally" defer></script>

Resources