Why is vue-splide not working with Nuxt2? - firebase

I'm trying to add Vue-Splide to my Nuxt project, after following the Vue-Splide documentation to install the plugin, and registering it as a Nuxt plugin I get the error Cannot use import statement outside a module.
nuxt.config.js
buildDir: '../functions/nuxt',
build: {
publicPath: '/public/',
vendor: [''],
extractCSS: true,
babel: {
presets: [
'#babel/preset-env'
],
plugins: [
["#babel/plugin-transform-runtime"]
]
}
},
plugins: [
{ src: '~/plugins/splide.client.js', mode: "client" }
],
splide.client.js
import Vue from 'vue';
import VueSplide from '#splidejs/vue-splide';
import '#splidejs/splide/dist/css/themes/splide-default.min.css';
Vue.use(VueSplide);
template
<splide :options="{ rewind: true }" class="banner-container">
<splide-slide class="slide" v-for="slide in slides" :key="slide.id">
<img :src="slide.imagen" :alt="slide.tombre" />
</splide-slide>
</splide>
After transpiling Vue-Splide I now get the error window is not defined, and the stacktrace shows it's happening on node_modules\#splidejs\splide\dist\js\splide.js, I tried surrounding the splide tags with <client-only></client-only>, but that didn't seem to work.
What else am I missing here?
Updating to include my dependencies
"dependencies": {
"#nuxtjs/firebase": "^7.6.1",
"#splidejs/vue-splide": "^0.3.5",
"firebase": "^8.9.1",
"isomorphic-fetch": "^3.0.0",
"nuxt": "^2.0.0"
},
"devDependencies": {
"#babel/plugin-transform-runtime": "^7.15.0",
"#babel/preset-env": "^7.15.6",
"#babel/runtime": "^7.15.4",
"#nuxtjs/tailwindcss": "^4.2.1",
"autoprefixer": "^10.4.0",
"babel-eslint": "^10.0.1",
"babel-plugin-module-resolver": "^4.1.0",
"eslint": "^4.19.1",
"eslint-friendly-formatter": "^4.0.1",
"eslint-loader": "^4.0.2",
"eslint-plugin-vue": "^7.19.1",
"firebase-tools": "^9.22.0",
"node-sass": "^6.0.1",
"postcss": "^8.3.11",
"sass-loader": "^12.3.0",
"tailwindcss": "^2.2.19"
}

The documentation of the vue-splide integration is clearly talking about Vue3 composition API.
Checking in the github issues of vue-splide, I found this one which is referencing a solution that you've linked above. Meanwhile, when trying this, those are the warnings that I do have in my CLI.
Those are also related to Vue3 (which is not compatible with Nuxt2, only Nuxt3 supports Vue3). Looking at the date of all the posts, it looks like it was matching somewhat the time-frame when Vue3 was still in a beta-limbo and probably not adopted by everybody.
At some point, I guessed that the package maybe lost some retro-compatibility with Vue2 in the next months. I then tried to install the version 0.3.5 of #splidejs/vue-splide rather than the latest one and it's working perfectly fine with it!
Here is the whole setup to have it working with Nuxt2
nuxt.config.js
plugins: [{ src: '~/plugins/splide.js', mode: 'client' }],
PS: no need for a transpile because this is not the issue at all here
/plugins/splide.js
import Vue from 'vue'
import VueSplide from '#splidejs/vue-splide'
import '#splidejs/splide/dist/css/themes/splide-default.min.css'
Vue.use(VueSplide)
/pages/index.vue
<template>
<client-only>
<Splide :options="{ rewind: true }">
<SplideSlide>
<img
src="https://images.unsplash.com/photo-1638204958375-4824be216720?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=776&q=80"
alt="Sample 1"
/>
</SplideSlide>
<SplideSlide>
<img
src="https://images.unsplash.com/photo-1638176061592-d8475d970c19?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=774&q=80"
alt="Sample 2"
/>
</SplideSlide>
</Splide>
</client-only>
</template>
It works perfectly fine
I've reported the issue in the github issue, if somebody wants to have more up-to date info or an official answer from the mantainer.
EDIT: we received a confirmation on the non retro-compatibility. Also, the usage of <client-only> is also required to prevent DOM mismatch.

Issue was caused by the configuration required for Firebase hosting if following Firebase's Server-Side Render Vue Apps with Nuxt.js video.
By removing the line buildDir: '../functions/nuxt' in the nuxt.config.js file the project runs fine locally, however, in order to deploy to Firebase you have to:
Replace publicPath: '/public/' with publicPath: '/', both in src/nuxt.config.js, and functions/index.js.
Run npm run build.
Copy the contents of src/.nuxt to functions/nuxt.
Copy the contents of src/.nuxt/dist/client and src/.nuxt/dist/server to public/.
For the moment I do not know if there's a way for vue-splide to work while building to the functions folder, as I already tried installing vue-splide on the functions project with no success.

Related

#meforma/vue-toaster clear function only works when pulled into local project folder, not from node_modules

As stated, the package #meforma/vue-toaster has a clear() function in the API here.
My vue and vite project setup:
main.js
import Toaster from '#meforma/vue-toaster'
app.use(Toaster, {
position: 'top',
useDefaultCss: false,
pauseOnHover: false
}).provide('toast', app.config.globalProperties.$toast)
Example.vue
<template>
<div class="view">
<div class="mt-10 flex gap-5">
<button class="btn btn-stealth" #click="showToast('default')">Default</button>
<button class="btn btn-primary" #click="showToast('primary')">Primary</button>
<button class="btn btn-success" #click="showToast('success')">Success</button>
<button class="btn btn-info" #click="showToast('info')">Info</button>
<button class="btn btn-warning" #click="showToast('warning')">Warning</button>
<button class="btn btn-danger" #click="showToast('error')">Error</button>
</div>
<div class="mt-10">
<button class="btn" #click="toast.clear">Clear Toasts</button>
<br><br>
<button class="btn" #click="clearToasts">Timeout Clear</button>
</div>
</div>
</template>
<script setup>
import { inject } from 'vue'
const toast = inject('toast')
// this works
function showToast (type) {
toast.show(`This is the ${type} type toast.`, {
type: type,
duration: false
})
}
// only works when vue-toaster is local in my projects src folder :S
function clearToasts () {
toast.clear()
}
</script>
package.json
{
"name": "test-project",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "vite --open",
"build": "vite build --out-dir dist",
"lint": "eslint src"
},
"dependencies": {
"#meforma/vue-toaster": "^1.3.0",
"#vitejs/plugin-vue": "^2.2.4",
"animate.css": "^4.1.1",
"axios": "^0.26.0",
"axios-auth-refresh": "^3.2.2",
"core-js": "^3.21.1",
"microtip": "^0.2.2",
"pinia": "^2.0.13",
"pinia-plugin-persistedstate": "^1.5.1",
"sass": "^1.49.9",
"vue": "^3.2.31",
"vue-meta": "^3.0.0-alpha.10",
"vue-router": "^4.0.13"
},
"devDependencies": {
"#tailwindcss/aspect-ratio": "^0.4.0",
"#tailwindcss/forms": "^0.5.0",
"#tailwindcss/line-clamp": "^0.3.1",
"#tailwindcss/typography": "^0.5.2",
"#vue/compiler-sfc": "^3.2.31",
"#vue/eslint-config-standard": "^6.1.0",
"autoprefixer": "^10.4.2",
"eslint": "^8.12.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-standard": "^4.1.0",
"eslint-plugin-vue": "^8.6.0",
"postcss": "^8.4.7",
"tailwindcss": "^3.0.23",
"vite": "^2.8.6"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"#vue/standard"
],
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
But, when I pull the package into the local src folder and import it via there, the clear works perfectly. No code changes other than moving where the code lives.
I have absolutely no idea why this is the case, if anyone has ever seen anything similar, it would be greatly appreciated.
I looked through all the code of the project github and created an issue there.
I thought it might be something to do with the event bus, but then again, it works when pulled from node_modules so hence why this is such a head scratcher for me.
Thanks!
Edit 1:
Updated code example that you can run locally to experience the same issue: https://codesandbox.io/s/vue3-toaster-test-forked-m64htx?file=/src/components/HelloWorld.vue:854-868
Specifically in the main.js, swapping where the vue-toaster is pulled in from causes the clear function to stop/start working. Clearing works when vue-toaster is located within my project /src but fails to work when pulled in from node_modules.
Edit 2:
Here is a stackblitz showing the same issue (using vite too): https://stackblitz.com/edit/vitejs-vite-uqcdgd?file=src%2Fmain.js,src%2FApp.vue
So after forking #meforma/vue-toaster, rewriting the Toaster in the composition API and changing the event bus to use mitt, even went as far as to publish it to npmjs so I could replicate everything as close as possible to how I use the package originally.... it turns out that my re-written package was having the exact same issue with Vite.
Digging in further, I noticed in my /node_modules/ there was a folder: /node_modules/.vite/deps/ which had files like: #shanehoban_vue-toaster.js... so I started googling and found out that perhaps I should exclude the package from Vite optimizations... like so:
vite.config.js
export default defineConfig({
optimizeDeps: {
exclude: [
"#meforma/vue-toaster"
]
},
....
And now, the clear... is working.
The original answer is a misunderstanding. So I edited it to follow the point of the question.
Problem
The package does NOT work when using it from node_modules.
The package does work when folks it into the project and use it directly
Reason
Vite only caches JS files from the package. We can see it in node_modules/.vite/deps/#meforma_vue-toaster.js
// The .vue file is point to original file
// node_modules/#meforma/vue-toaster/src/index.js
import Toaster2 from "/Users/admin/Work/test-projects/vite-demo-vue-plugin/node_modules/#meforma/vue-toaster/src/Toaster.vue";
// node_modules/#meforma/vue-toaster/src/api.js
import Toaster from "/Users/admin/Work/test-projects/vite-demo-vue-plugin/node_modules/#meforma/vue-toaster/src/Toaster.vue";
// The js file is cached here so Singleton pattern will breaks
// node_modules/#meforma/vue-toaster/src/helpers/event-bus.js
var Event = class {
constructor() {
this.queue = {};
}
...
}
The event-bus.js is cached in the .vite folder but the Toaster.vue file is not. So when the Toaster.vue uses the EventBus, it will call the instance from node_modules/#meforma/vue-toaster/ instead of the one in the .vite cached folder. And it breaks the Singleton pattern of the original package.
This bug might happen to any package with uncachable files mixed with JS files.
Workaround
This bug can be fixed only from the Vite side. So before Vite fixes it we need to exclude the package from the Vite cache as shanehoban's answer points out:
// vite.config.js
export default defineConfig({
optimizeDeps: {
exclude: [
"#meforma/vue-toaster"
]
},
....
Github issue

Nuxt.js & Firebase.services.analytics causes <v-img /> to be blank with no error

I cannot seem to get Firebase/Analytics to work with Nuxt.js. I don't get any errors, but when I use the I don't get any images loading.
I could use, and it loads fine. Seems to be a conflict with Nuxt/Vuetify/FirebaseAnalytics
nuxt.config.js
firebase: {
services: {
analytics: true
}
}
This creates the images to render blank. If I turn it to false, then items load as expected.
These are my dependencies
"dependencies": {
"#capacitor/cli": "^3.1.1",
"#capacitor/core": "^3.1.1",
"#capacitor/network": "^1.0.2",
"#nuxtjs/auth": "^4.9.1",
"#nuxtjs/firebase": "^7.6.1",
"#nuxtjs/pwa": "^3.3.5",
"#nuxtjs/universal-storage": "^0.5.9",
"core-js": "^3.9.1",
"firebase": "8.6.5",
"nuxt": "^2.15.3",
"vue-lodash": "^2.1.2"
},
Has anyone encounter this issue? Perhaps someone could expand if they know more? Would like to use Firebase Analytics in my setup.

Include node_modules css in Vuejs application that uses scss

I have deployed my application to aws and I see that the application renders fine, except that the syncfusion controls do not render correctly. Google chrome console does not show any errors.
The application renders correctly in my local machine.
To fix this, it was suggested I move the import '#syncfusion/**/styles/material.css' statements in the individual vue component to App.vue (as documented here). I however get a "Failed to resolve loader: sass-loader, You may need to install it" error(the application has node-sass, sass-loader installed already).
How should I include css files along with scss files, in my application?
Before: vocabulary.vue:
<script>
import '#syncfusion/ej2-base/styles/material.css';
import '#syncfusion/ej2-vue-inputs/styles/material.css';
package.json:
"devDependencies": {
"node-sass": "^4.12.0",
"sass-loader": "^7.1.0",
}
vue.config.js:
module.exports = {
publicPath: '/',
transpileDependencies: [
'vue-echarts',
'resize-detector'
],
configureWebpack: {
devtool: 'source-map',
optimization: {
splitChunks: {
chunks: 'all'
}
}
}
}
App.Vue:
<style>
#import "../node_modules/#syncfusion/ej2-base/styles/material.css";
#import "../node_modules/#syncfusion/ej2-vue-inputs/styles/material.css";
</style>
Deleting the npm packages and re-installing them again fixed the issue.

How to include Vuetify in WebStorm project

I'm struggling a lot with how to include Vuetify a default Vue.js project created using WebStorm. It's really to do with how the default Vue.js projects are set up in WebStorm rather than the editor itself as it seems to use an approach different to others I can find. I get errors of "Unknown custom element <v-alert>" (for example). I'm failing to find answers on how to do this because WebStorm's default set-up is different from all the how-tos I can find.
My App.vue file is as follows:
<template>
<div id="app">
<img alt="Vue logo" src="../../assets/logo.png">
<HelloWorld msg="Welcome to your Vue.js app"/>
<v-alert dismissible>Why does this show as an unknown custom element?</v-alert>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld,
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
My main.js file is as follows:
import Vue from 'vue'
import App from './App.vue'
// eslint-disable-next-line no-unused-vars
import Vuetify from "vuetify";
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
My package.json file is like so:
{
"name": "my-vue-app",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.6.4",
"deepmerge": "^4.2.2",
"sass": "^1.26.3",
"sass-loader": "^8.0.2",
"vue": "^2.6.11",
"vuetify": "^2.2.18"
},
"devDependencies": {
"#vue/cli-plugin-babel": "~4.2.0",
"#vue/cli-plugin-eslint": "~4.2.0",
"#vue/cli-service": "~4.2.0",
"babel-eslint": "^10.0.3",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.1.2",
"vue-template-compiler": "^2.6.11"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions"
]
}
I ran npm install vuetify which seemed to proceed correctly and I get no errors when building or serving it. But I don't know how to get my Vue app to import the Vuetify components.
All the documentation I can find talks about either instantiating the Vue app directly, which I'm not doing, or else if it talks about single component .vue files the examples all have module.exports which again, I don't have in the project built by WebStorm.
I've tried adding Vuetify as one of the imports in the script section of the App.vue and I've also tried setting Vuetify and v-alert as components in the components section of the App.vue file but can't get either to work. Thanks for any help.
I'm struggling a lot with how to include Vuetify a default Vue.js project created using Webstorm
Just follow the instructions from https://vuetifyjs.com/en/getting-started/quick-start/:
create a new project by either running vue create in terminal or using New > Project > Vue.js in IDE (use the default project setup)
in terminal, run vue add vuetify
My main.js file is as follows:
you didn't register Vuetify (Vue.use(Vuetify); if you don't like to follow the standard way (i.e. use vue add), try the instructions from https://vuetifyjs.com/en/getting-started/quick-start/#webpack-install

Webpack 2: compile SASS and ignore "Module not found: Error: Can't resolve './assets/image.png'"

I'm trying to use Webpack instead of Gulp as a task runner, in this case simply compiling all SCSS files as I was doing it with Compass before. The main objectives are:
run Autoprefixer and generate separate CSS file for each SCSS that is not a partial
don't bundle images or concatenate CSS files
keep image urls as is, e.g. background-image: url(assets/image.png)
don't throw errors if images cannot be found
#1 is solved and working, however it stops working and throws an error as soon as the SCSS links to an image as in #3 above:
ERROR in ./~/css-loader!./~/postcss-loader!./~/sass-loader/lib/loader.js!./scss/style.scss
Module not found: Error: Can't resolve './assets/image.png' in 'C:\Users\robro\projects\...\my-project\dev\styles\scss
# ./~/css-loader!./~/postcss-loader!./~/sass-loader/lib/loader.js!./scss/style.scss 6:15328-15369
# ./scss/style.scss
I'd like to "simply" ignore that error and not having to copy the missing files to my local hard drive. That's mostly just me being stubborn, thinking "Compass didn't need those images to be present, why does Webpack?"
Here's my setup:
webpack.config.js
const ExtractTextPlugin = require("extract-text-webpack-plugin");
var ExtractCSS = new ExtractTextPlugin('css/[name]');
module.exports = {
entry: {
'style.css': './scss/style.scss',
'admin.css': './scss/admin.scss'
},
output: {
filename: './css/[name]'
},
module: {
rules: [
{
test: /\.scss$/,
use: ExtractCSS.extract({
fallback: "style-loader",
use: [
"css-loader",
"postcss-loader",
"sass-loader"
]
})
},
{ test: /\.(jpg|jpeg|png|svg|gif|woff|woff2|otf|ttf)$/, use: 'ignore-loader' }
]
},
plugins: [
ExtractCSS
],
watch: true
};
package.json
{
"dependencies": {},
"devDependencies": {
"css-loader": "^0.26.1",
"extract-text-webpack-plugin": "^2.0.0-rc.3",
"ignore-loader": "^0.1.2",
"node-sass": "^4.5.0",
"postcss-loader": "^1.3.0",
"sass-loader": "^6.0.0",
"style-loader": "^0.13.1",
"webpack": "^2.2.1",
"webpack-dev-server": "^2.3.0"
}
}
As you can see, i tried using ignore-loader to stop sass-loader from complaining about missing images, but to no avail. To be honest, I'm not even sure this is how it's intended to be used.
As soon as I remove any line that links to images from the SCSS, everything is working just fine: style.css and admin.css get built, autoprefixed and dropped into css/ folder. Now I want to keep it that way, but also use styles like background-image: url(assets/image.png) without webpack complaining about those images not being present on the file system.
Case closed: Webpack is NOT a task runner. Blog posts naming Webpack as a successor to Grunt or Gulp or fail to explicitly point out that these tools may have some overlapping features but in the end have very different goals. Grunt and Gulp are task runners and Webpack is an asset bundler. Trying to make Webpack not bundle your assets defeats it's main purpose and one's better off choosing a different tool.

Resources