What is the right way to import vue package in nuxt? - vue.js

I try to import this package into my nuxt project.
All my coding experiments can be found here. I will refer to different branches.
There are several ways to do so:
Just import it right in the page like here (master branch)
This way worked well. You can go to the uploading page via a button on a home page.
Until you manually refresh the page
Then you will get this error SyntaxError Cannot use import statement outside a module
The same error happens when you try to build it.
Import it via plugins (like in plugin-use branch with or without vendor option in build)
I've got the same error.
Import it via plugins with some options (like in plugin-options branch)
Then the package loads only when you refresh the page and only in dev mode.
If you will go to that button on a home page (referenced before) - there will be an empty page.
Import it through modules (like in modules branch).
Then the nuxt cannot load at all, this error happens SyntaxError: Invalid or unexpected token
Could you comment on each method and why it doesn't work?
How to import it correctly?

The final answer is following (I've looked up the projects which use this package).
There was a project which run on Nuxt.
These are changes which you should add to #tamzid-oronno 's answer
//vue-upload-multiple-image.js
import Vue from 'vue'
import VueLazyload from 'vue-lazyload'
import VueUploadMultipleImage from 'vue-upload-multiple-image'
Vue.use(VueLazyload) // this is from the package installation guide
Vue.component('VueUploadMultipleImage', VueUploadMultipleImage)
And list it in plugins the same way.
//nuxt.config.js
plugins: [
{ src: '~plugins/vue-upload-multiple-image', ssr: false }
]
Thus you will be able to use the package without importing it in pages as tags. This was implemented in plugin_plus_lazy branch.
Both tags will work vue-upload-multiple-image and VueUploadMultipleImage.
//your-index-file.vue
<template>
<div id="my-strictly-unique-vue-upload-multiple-image" style="display: flex; justify-content: center;">
<vue-upload-multiple-image
#upload-success="uploadImageSuccess"
#before-remove="beforeRemove"
#edit-image="editImage"
:data-images="images"
idUpload="myIdUpload"
editUpload="myIdEdit"
dragText = "Drag an image here"
browseText = "(or click here to browse)"
primaryText = "Default Image"
markIsPrimaryText = "Set as default image"
popupText = "This image will be set as default"
dropText = "Drag and drop"
accept = image/jpeg,image/png,image/jpg,image/tif,image/tiff
></vue-upload-multiple-image>
</div>
</template>
<script>
export default {
name: "AppUpload",
data(){
return{
file:"",
images: []
}
},
methods:{
uploadImageSuccess(formData, index, fileList) { },
beforeRemove (index, done, fileList) { },
editImage (formData, index, fileList) { },
}
}
</script>
<style scoped>
</style>
To create a static version and test it on your local machine do the following:
$ npm run generate
# test the project
$ npm install http-server
$ cd dist
$ http-server -p 3000
I still have a question - why does it work? :)

Use it as plugin.
In the plugins folder, make a file named vue-upload-multiple-image.js
//vue-upload-multiple-image.js
import Vue from 'vue'
import {VueUploadMultiple} from 'vue-upload-multiple-image'
Vue.use(VueUploadMultiple)
List it under plugins block on nuxt.config.js
//nuxt.config.js
plugins: [
{ src: '~plugins/vue-upload-multiple-image', ssr: false }
]
Thus you will be able to use the package on any component of your project

Related

How to Use TinyMCE with NuxtJS

I am trying to build a blogging platform and i need to use a text editor and i have considered CKeditor and TinyMCE but there is no video or good instruction on how to use it with NuxtJS.
If anyone can help me it will be appreciated.
Please do not use a CDN but rather the solution that is here.
With something like this
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<editor
api-key="no-api-key"
:init="{
height: 500,
menubar: false,
plugins: [
'advlist autolink lists link image charmap print preview anchor',
'searchreplace visualblocks code fullscreen',
'insertdatetime media table paste code help wordcount'
],
toolbar:
'undo redo | formatselect | bold italic backcolor | \
alignleft aligncenter alignright alignjustify | \
bullist numlist outdent indent | removeformat | help'
}"
/>
</div>
</template>
<script>
import Editor from '#tinymce/tinymce-vue'
export default {
name: 'app',
components: {
'editor': Editor
}
}
</script>
Tinymce and CKeditor both have NPM packages and CDNs. This means you have two ways of using them in a Nuxt app.
Including the package via script tag (CDN)
As stated in the "Getting started" guide of those packages, you can simply import them using a script tag. In Nuxt, you can do this by adding it to your nuxt.config.js head option.
// nuxt.config.js
[...]
head: {
scripts: [
{ src: "https://cdn.tiny.cloud/1/no-api-key/tinymce/5/tinymce.min.js", referrerpolicy: true }
]
},
[...]
// example.vue
[...]
mounted() {
tinymce.init()
}
[...]
Using this solution you have to pay attention that tinymce is only accessed on the client-side, as it will not be available on the server-side.
Adding the package as a plugin
This is usually preferable, as it helps with bundle size analysis and allows your package manager to manage the text editors version.
You can also add the respective package as a plugin. Install the package using npm or yarn.
npm i tinymce
Afterward, simply create a .js-file in the plugins directory like so:
// plugins/tinymce.js
import tinymce from "tinymce"
export default tinymce
Register the plugin in your nuxt.config.js
// nuxt.config.js
plugins: [
{
src: "~/plugins/tinymce.js",
mode: "client", // This way the plugin will only be initiated on the client side
}
]
Now you can use the plugin within your app, accessing tinymce, just like in example.vue above.
Dynamically import the package within individual components
Another option is importing the npm package in the component directly. This may improve performance as the package is only imported when it is needed. If the package supports SSR, you can simply import it like you would any other package at the top of the script tag.
If your package does not support SSR (like most text editors), you can import it dynamically after checking whether the process is running on the client-side or by only importing it within hooks or methods that run on the client-side exclusively. (Solution by #kissu)
See this question for dynamic imports: How to make a dynamic import in Nuxt?

Web3js fails to import in Vue3 composition api project

I've created a brand new project with npm init vite bar -- --template vue. I've done an npm install web3 and I can see my package-lock.json includes this package. My node_modules directory also includes the web3 modules.
So then I added this line to main.js:
import { createApp } from 'vue'
import App from './App.vue'
import Web3 from 'web3' <-- This line
createApp(App).mount('#app')
And I get the following error:
I don't understand what is going on here. I'm fairly new to using npm so I'm not super sure what to Google. The errors are coming from node_modules/web3/lib/index.js, node_modules/web3-core/lib/index.js, node_modules/web3-core-requestmanager/lib/index.js, and finally node_modules/util/util.js. I suspect it has to do with one of these:
I'm using Vue 3
I'm using Vue 3 Composition API
I'm using Vue 3 Composition API SFC <script setup> tag (but I imported it in main.js so I don't think it is this one)
web3js is in Typescript and my Vue3 project is not configured for Typescript
But as I am fairly new to JavaScript and Vue and Web3 I am not sure how to focus my Googling on this error. My background is Python, Go, Terraform. Basically the back end of the back end. Front end JavaScript is new to me.
How do I go about resolving this issue?
Option 1: Polyfill Node globals/modules
Polyfilling the Node globals and modules enables the web3 import to run in the browser:
Install the ESBuild plugins that polyfill Node globals/modules:
npm i -D #esbuild-plugins/node-globals-polyfill
npm i -D #esbuild-plugins/node-modules-polyfill
Configure optimizeDeps.esbuildOptions to use these ESBuild plugins.
Configure define to replace global with globalThis (the browser equivalent).
import { defineConfig } from 'vite'
import GlobalsPolyfills from '#esbuild-plugins/node-globals-polyfill'
import NodeModulesPolyfills from '#esbuild-plugins/node-modules-polyfill'
export default defineConfig({
⋮
optimizeDeps: {
esbuildOptions: {
2️⃣
plugins: [
NodeModulesPolyfills(),
GlobalsPolyfills({
process: true,
buffer: true,
}),
],
3️⃣
define: {
global: 'globalThis',
},
},
},
})
demo 1
Note: The polyfills add considerable size to the build output.
Option 2: Use pre-bundled script
web3 distributes a bundled script at web3/dist/web3.min.js, which can run in the browser without any configuration (listed as "pure js"). You could configure a resolve.alias to pull in that file:
import { defineConfig } from 'vite'
export default defineConfig({
⋮
resolve: {
alias: {
web3: 'web3/dist/web3.min.js',
},
// or
alias: [
{
find: 'web3',
replacement: 'web3/dist/web3.min.js',
},
],
},
})
demo 2
Note: This option produces 469.4 KiB smaller output than Option 1.
You can avoid the Uncaught ReferenceError: process is not defined error by adding this in your vite config
export default defineConfig({
// ...
define: {
'process.env': process.env
}
})
I found the best solution.
The problem is because you lose window.process variable, and process exists only on node, not the browser.
So you should inject it to browser when the app loads.
Add this line to your app:
window.process = {
...window.process,
};

Vue: icons are not displayed when css.extract: false

When building a Vue library (component), according to Vue docs, you can set css.extract: false in vue.config.js to avoid the users having to import the CSS manually when they import the library into an app:
vue.config.js
module.exports = {
css: {
extract: false
}
}
However, when you do that, the icons are not displayed in the production build.
In this case I'm using #mdi/font and weather-icons. Neither of them load:
To reproduce
You can reproduce this with this Vue library (component):
Create new Vue project with vue create test
Clone the repo and put in the same directory as the Vue test project
In vue-open-weather-widget set css.extract: false in vue.config.js;
And comment out CSS import:
import 'vue-open-weather-widget/dist/vue-open-weather-widget.css'
Build vue-open-weather-widget with yarn build
Import it into the test Vue app with yarn add "../vue-open-weather-widget";
Serve the test app yarn serve
I have looked at your lib (nice component BTW). I created a build with css: { extract: false } and first looked at the behavior when importing vue-open-weather-widget.umd.js directly into an HTML file. And that worked without any problems.
The thing is that the fonts remain external in the dist after the build. And it seems that there is a problem to find the fonts when your component is loaded in a Webpack project (in our case Vue CLI project). I don't know why the fonts are not referenced correctly. But I have found another, and possibly a better solution.
As it is stated in the MDI docs, the use of the web fonts can negatively affect the page performance. When importing only one icon, all of them are imported, which in turn increases the bundle size. In such a small component this is more than suboptimal, especially for the component users. Therefore here is the alternative solution, also suggested by MDI:
Use #mdi/js instead of #mdi/font
Remove all #mdi/font references in your code and install deps:
npm install #mdi/js #jamescoyle/vue-icon
Replace all icons with SVG(e.g. in MainView.vue). Note that on this way only icons are included in the bundle that are used in your components:
...
<span #click="state.settings.view = 'settings'">
<svg-icon type="mdi" :path="mdiCogOutline"></svg-icon>
</span>
...
import SvgIcon from '#jamescoyle/vue-icon'
import { mdiCogOutline } from '#mdi/js'
...
components: {
SvgIcon
},
data () {
return {
mdiCogOutline: mdiCogOutline
}
},
Adjust vue.config.js:
module.exports = {
css: {
extract: false
}
}
Build component:
# i would also include --formats umd-min
vue-cli-service build --target lib --formats umd-min --name vue-open-weather-widget src/main.js
Now your dist contains only 192.68 KiB vue-open-weather-widget.umd.min.js and the component is ready to use over CDN or in a Vue CLI Project, without importing any CSS or fonts. I have tested both cases. Here is how it looks like:
Hope it helps you! Feel free to ask if you have further questions.

Oction-vue in nuxt: unexpected identifier

I would like to use the icons from Octicon, my project is written in nuxt.js, so I decided to use this Octicon Component for Vue.js.
I created a file called octicon.js and added it to /plugins and registered it in nuxt.config.js. When I start my app, I get the message "unexpected identifier".
/plugins/octicion.js :
import Vue from 'vue'
import octicon from 'vue-octicon/components/Octicon.vue'
// Pick one way betweem the 2 following ways
// only import the icons you use to reduce bundle size
import 'vue-octicon/icons/repo'
// or import all icons if you don't care about bundle size
import 'vue-octicon/icons'
Vue.use(octicon);
In MyComponent.vue I use it like
<template>
<div>
<octicon name="repo-forked" label="Forked Repository"></octicon>
</div>
</template>
nuxt.config.js looks like
plugins: [
"#/plugins/bootstrap-vue",
"#/plugins/octicon.js"
],
My Browser shows me:
Where is my error?
Two things you probably need to do. The plugin is only required on the client side so you should specify this in nuxt.config.js:
plugins: [
"#/plugins/bootstrap-vue",
{ src: '~/plugins/octicon.js', mode: 'client' }
]
Secondly you may need to add it to the transpile build option, also in nuxt config.js:
build: {
transpile: ['octicon.js']
}
You may also want to wrap the <octicon> tag in a <no-ssr> tag.

VUE CLI-3 Project not working on IE-11

I have created an project in vuejs using vue-cli3. It working fine on chrome browser but in IE-11 version blank screen is shown with the following error in console as mentioned in this link: https://drive.google.com/file/d/1QaNwK1ekI2BwFsFyjvgbSsvwHBCmlcAD/view?usp=drivesdk
On clicking console error that I have pointed in above screenshot, it opens a screen as display in given link https://drive.google.com/file/d/1_QXVjcw3cmqeC70LfNyLcr__rnXVIZIh/view?usp=drivesdk with the error in mini-toastr package:
Here is my babel.config.js file code:
module.exports = {
presets: [
['#vue/app', {
polyfills: [
'es6.promise',
'es6.symbol'
]
}]
]
}
and .browserslistrc file code :
> 1%
last 2 versions
not ie <= 8
I am not getting where I am doing a mistake. Is anything I am missing? If anyone need some more info please let me know. Thanks!
I finally ended up with the solution of above issue. To run project on IE-11 version just follow the 2 steps:
Install babel-polyfill using command "npm install --save babel-polyfill".
Import babel-polyfill in your main.js or index.js file at the top of above all imported packages. For e.g Here is your main.js file.
Note: If you import babel-polyfill at the end it does't work.
import 'babel-polyfill'
import Vue from 'vue'
import Vuetify from 'vuetify'
import router from './router'
// include script file
import './lib/DemoScript'
// include all css files
import './lib/DemoCss'
Vue.use(Vuetify)
new Vue({
store,
router,
render: h => h(App),
components: { App }
}).$mount('#app')
Another solution: use the power of vue-cli-3 to leverage browser support: https://cli.vuejs.org/guide/browser-compatibility.html#modern-mode
Just one option when building and you're done once you've chosen browserslist to support :-)
This should work well for building an app.