Web3js fails to import in Vue3 composition api project - vue.js

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,
};

Related

Unable to load stencil components lib with Vue3 using Vite

I created a sample project to reproduce this issue: https://github.com/splanard/vue3-vite-web-components
I initialized a vue3 project using npm init vue#latest, as recommanded in the official documentation.
Then I installed Scale, a stencil-built web components library. (I have the exact same issue with the internal design system of my company, so I searched for public stencil-built libraries to reproduce the issue.)
I configured the following in main.ts:
import '#telekom/scale-components-neutral/dist/scale-components/scale-components.css';
import { applyPolyfills, defineCustomElements } from '#telekom/scale-components-neutral/loader';
const app = createApp(App);
app.config.compilerOptions.isCustomElement = (tag) => tag.startsWith('scale-')
applyPolyfills().then(() => {
defineCustomElements(window);
});
And the same isCustomElement function in vite.config.js:
export default defineConfig({
plugins: [vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('scale-')
}
}
})]
// ...
})
I inserted a simple button in my view (TestView.vue), then run npm run dev.
When opening my test page (/test) containing the web component, I have an error in my web browser's console:
failed to load module "http://localhost:3000/node_modules/.vite/deps/scale-button_14.entry.js?import" because of disallowed MIME type " "
As it's the case with both Scale and my company's design system, I'm pretty sure it's reproducible with any stencil-based components library.
Edit
It appears that node_modules/.vite is the directory where Vite's dependency pre-bundling feature caches things. And the script scale-button_14.entry.js the browser fails to load doesn't exist at all in node_modules/.vite/deps. So the issue might be linked to this "dependency pre-bundling" feature: somehow, could it not detect the components from the library loader?
Edit 2
I just found out there is an issue in Stencil repository mentioning that dynamic imports do not work with modern built tools like Vite. This issue has been closed 7 days ago (lucky me!), and version 2.16.0 of Stencil is supposed to fix this. We shall see.
For the time being, dropping the lazy loading and loading all the components at once through a plain old script tag in the HTML template seems to be an acceptable workaround.
<link rel="stylesheet" href="node_modules/#telekom/scale-components/dist/scale-components/scale-components.css">
<script type="module" src="node_modules/#telekom/scale-components/dist/scale-components/scale-components.esm.js"></script>
However, I can't get vite pre-bundling feature to ignore these imports. I configured optimizeDeps.exclude in vite.config.js but I still get massive warnings from vite when I run npm run dev:
export default defineConfig({
optimizeDeps: {
exclude: [
// I tried pretty much everything here: no way to force vite pre-bundling to ignore it...
'scale-components-neutral'
'#telekom/scale-components-neutral'
'#telekom/scale-components-neutral/**/*'
'#telekom/scale-components-neutral/**/*.js'
'node_modules/#telekom/scale-components-neutral/**/*.js'
],
},
// ...
});
This issue has been fixed by Stencil in version 2.16.
Upgrading Stencil to 2.16.1 in the components library dependency and rebuilding it with the experimentalImportInjection flag solved the problem.
Then, I can import it following the official documentation:
main.ts
import '#telekom/scale-components-neutral/dist/scale-components/scale-components.css';
import { applyPolyfills, defineCustomElements } from '#telekom/scale-components-neutral/loader';
const app = createApp(App);
applyPolyfills().then(() => {
defineCustomElements(window);
});
And configure the custom elements in vite config:
vite.config.js
export default defineConfig({
plugins: [vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('scale-')
}
}
})]
// ...
})
I did not configure main.ts
stencil.js version is 2.12.1,tsconfig.json add new config option in stencil:
{
"compilerOptions": {
...
"skipLibCheck": true,
...
}
}
add new config option in webpack.config.js :
vue 3 document
...
module: {
rules:[
...
{
test: /\.vue$/,
use: {
loader: "vue-loader",
options: {
compilerOptions: {
isCustomElement: tag => tag.includes("-")
}
}
}
}
...
]
}
...

Loading vuetify in a package that i use in a vuetify project

What is the correct way of loading vuetify into a package that i use in a vuetify project?
When serving projects it all seems to work fine but when i build the project i've got some issues with the css/sass
things i've tried:
With vuetify loader: the css is loaded twice so i can't overwrite sass variables
Without vuetify loader: the package doesn't have the vuetify css, so it looks horrible
Without vuetify loader with vuetify.min.css: the css is loaded twice so i can't overwrite sass variables, and the loaded css is all the css so it's huge
My package is called vuetify-resource, and this is the source code of the index.js (without the vuetify loader) At this point everything works on npm run serve But when i build the package doesn't have "access" to the vuetify css.
import Vue from 'vue';
import Vuetify from 'vuetify';
import VuetifyResourceComponent from './VuetifyResource.vue';
Vue.use(Vuetify);
const VuetifyResource = {
install(Vue, options) {
Vue.component('vuetify-resource', VuetifyResourceComponent);
},
};
export default VuetifyResource;
To solve my issue i had to do a couple of things.
Make peer dependencies of vuetify and vue
add vuetify to the webpack externals, so when someone uses the package, the package uses that projects vuetify
not longer import vue and vuetify in the index.js it's not needed, the project that uses the package imports that
import the specific components that you use in every .vue file
for example:
Vue.config.js
module.exports = {
configureWebpack: {
externals: {'vuetify/lib': 'vuetify/lib'},
},
};
index.js
import VuetifyResourceComponent from './VuetifyResource.vue';
const VuetifyResource = {
install(Vue, options) {
Vue.component('vuetify-resource', VuetifyResourceComponent);
},
};
export default VuetifyResource;
part of the component.vue
import { VDataTable } from 'vuetify/lib';
export default {
name: 'vuetify-resource',
components: {
VDataTable
},
Step 4 in Ricardo's answer is not needed if you use vuetify-loader, it will do the job for you.
And I would modify step 2 to also exclude Vuetify's styles/css from your bundle. If you don't exclude them you can run into styling issues when the Vuetify version differ between your library and your application.
Use a regular expression in vue.config.js like this: configureWebpack: { externals: /^vuetify\// }. That way, only your own styles are included in the library bundle.

document is not defined in nuxtjs on integrating jqxwidget

I'm integrating jqxWidgets(https://www.jqwidgets.com/vue/) into my nuxtjs app.
Here are the steps I did:
installed jqwidgest npm install --save jqwidgets-scripts
After I imported the jqxGrid on my page import JqxGrid from "jqwidgets-scripts/jqwidgets-vue/vue_jqxgrid.vue"; I received an error for document is not defined.
I created a plugin jqwidgets.js and added the following code:
import Vue from 'vue'
import jqGridWidget from "jqwidgets-scripts";
Vue.use(jqGridWidget)
in nuxtconfig.js I added the following in plugins:
plugins: [{src: "~/plugins/jqwidgets.js", ssr: false}]
and in build I added:
build: {
extend(config, ctx) {
},
transpile: [/^jqwidgets-scripts($|\/)/],
}
I am still getting the document is not defined error in node_modules/jqwidgets-scripts/jqwidgets/jqxcore.js
Does anyone know how to fix this?

How to setup a vue-cli with vuetify project to run with IE 11?

I spend a few days to setup a vue.js + vue-cli + typescript + vuetify project to run with IE 11 without success?
I found many posts on the net that explain how it should be done but without success. I tried to combine in almost all the ways possible the setup explained below without success, endind with many different errors up to a blank page
The application runs fine wit Chrome or FF
If someone has such an application running in IE 11 it would be greatly appreciated
Context (all the latest versions):
vue-cli
typescript
vue.js + vue-router + vuex + vuex-persistedstate
vuetify + vue-i18n + vuelidate
axios
Pardon me if some question seems stupid as I'm quite a newbie on babel/webpack dev..
What I've tried and questions :
(i've tried almost all the combinations the following)
Should I use npm install babel-polyfill --saveas explained in the vuetify setup for IE 11 here?
Should I addimport 'babel-polyfill'inmain.tsas explained in the vuetify setup for IE 11 here?
Or should I addimport '#babel/polyfill'inmain.tsas explained here
Should I use npm install #babel/preset-env --save-devas explained in the vuetify setup for IE 11 here or is it unnecessary due tovue-cli being used?
inbabel.config.js, should I replace the content initially created by vue-cli
presets: [
'#vue/app'
]
by as explained here
presets: ['#babel/preset-env']
or (as seen in many places)?
presets: [['#vue/app', useBuiltIns: 'entry' }]]
or add the 2 presets?
presets: [
['#babel/preset-env'],
['#vue/app', useBuiltIns: 'entry' }]
]
Should I add some plugins like explained here?
presets: ['#vue/app'],
plugins: ['#babel/transform-modules-commonjs']
Or change it like this as explained in the vue doc here?
presets: [
['#vue/app', {
polyfills: [
'es6.promise',
'es6.symbol'
]
}]
]
invue.config.js, should I add?
transpileDependencies: [
'vuetify',
'vue-i18n',
'vuelidate',
'axios'
]
[SOLUTION 2019-06-25]
We finally got it to work, the answer from #blackening was very helpful
It happened also that we had javsacript errors in IE 11 with google"reCaptcha"that disappeared after the following setup:
As a prerequisite,vue-cliis installed and the project is created by selecting`'Use Babel alongside TypeScript for auto-detected polyfills'
1) installcore-js#3
npm install core-js#3
2) editmain.tslike this:
import 'core-js/stable'
import Vue from 'vue'
import '#/plugins/vuetify'
{...}
3) editbabel.config.js
module.exports = {
presets: [
['#vue/app', { useBuiltIns: 'entry' }]
]
}
And that's it !
Now we are fighting with IE 11 CSS, but that's a know story... As a nexample, invue to apply a style only to IE, just code it like this
<style scoped>
/* Only for IE 11, wrap div text */
#media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
.ieMaxWidth90 {
max-width: 90vw; /* 90% view width */
}
}
</style>
I'll do a partial answer.
1) #vue/app and babel presets are included in vue-cli.
https://cli.vuejs.org/guide/browser-compatibility.html#polyfills
This is stated clearly in the vue-cli documentation. But it also specifies:
"If one of your dependencies need polyfills, you have a few options:
If the dependency is written in an ES version that your target environments do not support: Add that dependency to the transpileDependencies option in vue.config.js"
2) You still need to put the babel polyfill in each entry file.
Traditionally: import '#babel/polyfill' in your main.ts.
What babel-preset-env does is that it detects your browserlist then replaces that line with whatever polyfills it deems necessary.
3) #babel/polyfill is deprecated. Who knew.
Some people need extra heavy duty polyfills. That's me. Because internet exploder in office-js + being too used to bleeding edge tech. That's where core-js # 3 comes in.
My webpack build is fully custom for that purpose. But i ripped it out of the vue-cli and modified from there.
My babel loader config :
const BABEL_LOADER = {
loader: 'babel-loader',
options: {
plugins: ['#babel/plugin-syntax-dynamic-import'],
presets: [
// '#vue/app',
['#babel/preset-env', {
targets: {
ie: '11',
browsers: 'last 2 versions',
},
useBuiltIns: 'usage',
corejs: { version: 3, proposals: true },
}],
],
},
};
This is the top of my entry file:
import Vue from 'vue';
import App from './App.vue';
// ------------ Polyfill ------------
import 'core-js/stable';
The core-js replaces #babel/polyfill.
More reading on core-js: https://github.com/zloirock/core-js/blob/master/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md
npm install --save core-js
Top two lines of main.js:
import "core-js/stable";
import "regenerator-runtime/runtime";
In vue.config.js:
module.exports = {
...,
transpileDependencies: ['vuetify']
}
According to this tutorial, after installing the vuetify using the following command:
npm install vuetify --save
Then, import the Vuetify in the main.ts file, like this:
import Vue from 'vue';
import App from './App.vue';
import store from './store';
import Vuetify from 'vuetify';
import 'vuetify/dist/vuetify.min.css';
Vue.use(Vuetify);
Vue.config.productionTip = false;
After that, using this command to install babel-polyfill:
npm install --save babel-polyfill
Then, add the import at the top of the main.ts file, the final code as below:
import 'babel-polyfill';
import Vue from 'vue';
import App from './App.vue';
import store from './store';
import Vuetify from 'vuetify';
import 'vuetify/dist/vuetify.min.css';
Vue.use(Vuetify);
Vue.config.productionTip = false;
new Vue({
store,
render: (h) => h(App),
}).$mount('#app');
Finally, using "npm run serve" command to run the application, it works well in IE 11.

How to fix "This relative module was not found: * ./src/main.js in multi..." error when trying to npm run serve

When trying to run the application with npm run serve (on iOS), I am getting the following error:
This relative module was not found:
./src/main.js in multi (webpack)-dev-server/client?http://10.0.0.5:8081/sockjs-node ./node_modules/#vue/cli-service/node_modules/webpack/hot/dev-server.js ./src/main.js
Please bear with me, I am new to this.
I have tried a bunch of random stuff like checking for misspelling issues, reinstalling webpack, updating node, and nothing. I have no clue of what this error is about so I am not sure where to look at.
The main.js file looks like this:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store/store'
import './registerServiceWorker'
import * as VueGoogleMaps from "vue2-google-maps"
import VeeValidate from 'vee-validate'
import BootstrapVue from 'bootstrap-vue'
Vue.use(VueGoogleMaps, {
load: {
key: "AIzaSyCGiy39IZbj8oxvO4HHqSVjP5RmLSHl7mY",
libraries: "places" // necessary for places input
}
});
Vue.use(VeeValidate);
Vue.use(BootstrapVue);
Vue.config.productionTip = false;
new Vue({
router,
store,
beforeCreate() {
this.$store.commit('initialiseStore');
this.$store.dispatch('commons/initialize');
},
render: h => h(App)
}).$mount('#app')
I expect the live web server to display, but I am getting this compilation error and it is failing.
I faced a similar issue after and spent hours searching.
The issue occurred in my project when I tried to install vuetify using command vue add vuetify. Apparently, the in automatically changes the app entry property in webpack.config automatically.
You can either change the filename itself to main.js or change the webpack config through vue.config.js (by reading the vue cli documentation regararding webpack config).
You can check your webpack.config by using the command vue inspect.
],
entry: {
app: [
'./src/main.js'
]
}
}
I had a similar error, this worked for me but not sure you have the same issue. I found this in one of my webpack configuration files (usually named like webpack.dev.conf.js):
{
test: /\.js$/,
loader: 'babel-loader',
include: [
resolve('src'),
resolve('test'),
resolve('node_modules/webpack-dev-server/client')
]
},
I removed resolve('node_modules/webpack-dev-server/client') and it fixed that issue.
This is an old thread, but I ran across this recently after installing a new module to a Vue project. The problem went away when I updated all my other modules, too.