Pass variable from webpack entries - javascript

I have multiple entries like in webpack docs
module.exports = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
};
let's say every of these files (index.js) is the same and only thing that change is other routes import.
I would create one file to keep DRY principle but I would need to pass something to actually know which router I want to import.
For example pageOne/index.js is
import Vue from 'vue'
import axios from 'axios'
import App from '../App'
import { store } from '../store';
import VueProgressBar from 'vue-progressbar'
import Router from '../routers/router';
import interceptor from '../../config/httpInterceptor.js';
console.log('in main', window.location.href)
const routerInstance = new Router('main');
routerInstance.createRouter()
.then(router => {
interceptor();
if (!process.env.IS_WEB) Vue.use(require('vue-electron'));
Vue.http = Vue.prototype.$http = axios;
Vue.config.productionTip = false;
Vue.use(VueProgressBar, {
color: 'rgb(255, 85, 0)', failedColor: 'red', thickness: '5px'
});
new Vue({
components: { App },
router,
store,
template: '<App/>'
}).$mount('#app');
});
and in pageTwo/index.js only line that change is from
const routerInstance = new Router('main');
to
const routerInstance = new Router('second');
so it's bad to have three same js files where only one line is changing but I don't know how to refactor it so it's reusable. I would need to pass to file information about which page is being loaded for example it would be something like this
module.exports = {
entry: {
pageOne: './src/pageOne/index.js?page=main',
but now when in index.js I log
console.log('in main', window.location.href)
it is
http://localhost:9080/#/
So I'm not able to require different router basing on this. I need some other solution.
Edit
#Daniel Lizik in comment section suggested to use environment variable. He also said to use webpack config in order to set it. Considering that I would refactor my entry object to following:
module.exports = {
entry: {
pageOne: './src/index.js',
pageTwo: './src/index.js',
pageThree: './src/index.js'
}
};
I would need to configure webpack somehow to set environment variable right after webpack imported file.
Webpack probably loop over this object and import files. Right after it read this line
pageOne: './src/index.js',
I would need to set some env variable to 'pageOne' so when index.js is executed it can check this variable and import correct router.
However I have no idea how I could achieve that.

You don't need to pass the query param in the entry point configuration. You have to pass it from the browser. Then you can parse the query param and pass it to new Router(). You can use urijs node module for parsing the query param in a clean way.
import URI from "urijs";
...
const uriObj = new URI(url);
const page = uriObj.query(true)[page] || "main";
const routerInstance = new Router(page);
In your browser you enter the url with the page param like http://localhost:9080/page=second

Related

Error with WEB3js - NodeJs.utils in vite react ts app - How to resolve TypeError: callbackify is not a function

Hey I am playing around with web3 inside react as a client application (using vite react-ts) and trying to call web3.eth.net.getId() but this will throw me an error that callbackify is not a function I digged a little and found an old issue on the github which states that older versions of Nodejs.util (prior version 0.11) didn't have this function. So I checked the package.json where the error occurs (web3-core-requestmanager) it has "util":"^0.12.0", so callbackify should be available.
In fact when I am looking at their imports, they seem to be able to import it:
(following code is ./node_modules\web3-core-requestmanager\src\index.js
const { callbackify } = require('util');
but when they want to use it, callbackify is undefined
//RequestManager.prototype.send function
const callbackRequest = callbackify(this.provider.request.bind(this.provider));
I tried to play around with the dependencies and tried different versions of web3.js (1.7.3; 1.6.0; 1.5.1) all of them had the same util dependency (0.12.0).
My code in all this matter looks like this:
class Blockchain {
public blockchainBaseUrl: string;
public web3;
public provider;
public account: string = '';
public contract: any;
constructor() {
if (process.env.REACT_APP_BLOCKCHAIN_BASE_URL === undefined) {
throw new Error('REACT_APP_BLOCKCHAIN_BASE_URL is not defined');
}
this.provider = window.ethereum;
if (this.provider === undefined) {
throw new Error('MetaMask is not installed');
}
this.setUpInitialAccount();
this.addEthereumEventListener();
this.blockchainBaseUrl = process.env.REACT_APP_BLOCKCHAIN_BASE_URL;
this.web3 = new Web3(Web3.givenProvider || this.blockchainBaseUrl);
this.setContract();
}
async setContract() {
// error comes from the next line
const networkId = await this.web3.eth.net.getId();
this.contract = new this.web3.eth.Contract(
// #ts-ignore
Token.abi,
// #ts-ignore
Token.networks[networkId].address
);
}
}
I also was told that I should simply add a .catch() to web3.eth.net.getId() but this did nothing. Am I doing something wrong or is this a dependency problem? If anyone could point me in the right direction I would really appreciate it. Do I need to expose the util API to the browser somehow? To me, it seems that the API is simply not available.
This is should be the relevant part of my vite.config.ts:
import GlobalsPolyfills from '#esbuild-plugins/node-globals-polyfill';
import NodeModulesPolyfills from '#esbuild-plugins/node-modules-polyfill';
import { defineConfig } from 'vite';
import react from '#vitejs/plugin-react';
export default defineConfig({
plugins: [
react(),
],
optimizeDeps: {
esbuildOptions: {
plugins: [
NodeModulesPolyfills(),
GlobalsPolyfills({
process: true,
buffer: true,
}),
],
define: {
global: 'globalThis',
},
},
},
});
Here is my complete vite config
https://pastebin.com/zvgbNbhQ
Update
By now I think that I understand the issue - it seems that it is a VIte-specific problem and I need to polyfill the NodeJs.util API. I am already doing this (at least I thought). Perhaps someone can provide some guidance on what I am doing wrong with my config?
Update 2
I actually have now the util API inside the browser, but it is still giving me the same error. This is my new config:
https://pastebin.com/mreVbzUW I can even log it out:
Update 3
SO I am still facing this issue - I tried a different approach to polyfill I posted the update to the github issue https://github.com/ChainSafe/web3.js/issues/4992#issuecomment-1117894830
Had similar problem with vue3 + vite + we3
It's started from errors: process in not defined than Buffer is not defined and finally after I configure polyfill I came to callbackify is not defined
Did a lot of researches and finally solved this issue with next trick:
Rollback all polyfill configurations
Add to the head html file
<script>window.global = window;</script>
<script type="module">
import process from "process";
import { Buffer } from "buffer";
import EventEmitter from "events";
window.Buffer = Buffer;
window.process = process;
window.EventEmitter = EventEmitter;
</script>
vite.config.ts
import vue from '#vitejs/plugin-vue'
export default {
resolve: {
alias: {
process: "process/browser",
stream: "stream-browserify",
zlib: "browserify-zlib",
util: 'util'
}
},
plugins: [
vue(),
]
}
add these dependencies browserify-zlib, events, process, stream-browserify, util
Source https://github.com/vitejs/vite/issues/3817#issuecomment-864450199
Hope it will helps you

Load a CJS module config inside another file

I'm trying to load a config inside a node module but I'm not sure which is a good practice to do it, I have this scenario:
A config my.config.js:
module.exports = {
content: [
'./src/**/*.{tsx,ts}',
],
}
Then I have a module cli.mjs is supposed to load it:
import arg from 'arg'
import { readFile } from 'fs/promises'
import path from 'path'
let configPath = './my.config.js'
const args = arg({
'--config': String,
'-c': '--config',
})
if (args['--config']) {
configPath = args['--config']
}
console.log(readFile(path.resolve(configPath), { encoding: 'utf8' }))
This will just return a simple string with my config inside, not a javascript object:
`
module.exports = {
content: [
'./src/**/*.{tsx,ts}',
],
}
`
How should I load my config in the right way?
I've saw basically everyone use configs like that in TypeScript or CJS projects, but it's hard to me see how and where they parse these configs, probably I'm missing some basic information about this?

Vue Router doesn't seem to like function calls

In my router/index.js, I am trying to lazy-load the route. If I hard-code the string it is working but if I use a function (as shown) call to get that file path as a string value, it shows me an error in the console - Error: Cannot find module '../views/Login/Login.vue'. I'm using Vue 2.6.11 and Vue-router 3.5.1.
Where am I going wrong?
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
// const filePath = (filename, foldername) => '../views/' + foldername + "/" + filename + '.vue'
const routes = [
{
path: '/',
name: 'Login',
// THIS WORKS
component: () => import('../views/Login/Login.vue')
// THIS DOES NOT, EVEN THOUGH IT IS GETTING THE EXACT SAME VALUE
// component: () => import(filePath('Login', 'Login'))
},
]
const router = new VueRouter({
routes
})
export default router
If you want to lazy-load a route, it has to be statically analyzable, like this:
component: () => import('../views/Login/Login.vue')
In your other attempt:
component: () => import(filePath('Login', 'Login'))
The import is not statically analyzable by the build tool (probably webpack). The build tool is in charge of identifying which code is being used and which code is not (that's called tree-shaking).
As it can't resolve the actual import (it would be possible only at runtime since filePath could return anything), it considers that the vue file is never referred to, and should be removed from the build.
If your actual build tool is webpack, you have to follow webpack's instructions described here: https://webpack.js.org/api/module-methods/#dynamic-expressions-in-import which states that is possible to have dynamic imports when they have a statically analyzable pattern (e.g: template literals)
You should let webpack to know in which root folder it will load the component files, so you should move ../views/ to the import parameter instead of the returned value of your function :
const filePath = (filename, foldername) => foldername + "/" + filename + '.vue'
const routes = [
{
path: '/',
name: 'Login',
component: () => import('.../views/'+filePath('Login', 'Login'))
},
]

.env Nuxt JS doesn't resolve routes in generate option correctly

I'm trying to use Nuxt JS's 2.9.2 generate object to generate dynamic pages as static files using my .env file to pull a URL, I'm having difficuility in getting it to properly link up:
nuxt.config.js
require('dotenv').config();
import pkg from './package'
import axios from 'axios'
export default {
mode: 'universal',
env: {
blog_api: process.env.BLOG_API || "http://localhost:3000/articles/blogs.json"
},
/*
** Build directory
*/
generate: {
dir: 'dist-next',
routes: function () {
return axios.get(`${process.env.blog_api}`)
.then((res) => {
return res.data.blogs.map((blog) => {
return '/posts/view/' + blog.title
})
})
}
}
}
The above code, more specifically ${process.env.blog_api}, can't seem to resolve the routes, despite it working perfectly if I replace it with my own local domain.
.env
BLOG_API="http://my-local-domain.clone/articles/blogs.json"
EDIT:
Updated code with my config, http://my-local-domain.clone/articles/blogs.json is inside of static/articles
You should use dotenv module:
https://www.npmjs.com/package/dotenv
More Info about configuration with NUXT you have here:
https://samuelcoe.com/blog/nuxt-dotenv/
You probably want to set your env property in nuxt.config.js, for example:
module.exports = {
env: {
BLOG_API: process.env.BLOG_API_URL,
},
In your component, you can now use them :
makeAsyncCall({
to: process.env.BLOG_API,
})

How do I create a webpack import alias in React Static Boilerplate?

I have the following import:
// cwd: /project/pages/blog/category/red/index.js
import PageHeader from '../../../components/PageHeader';
And I want to be able to write it this way (anywhere in my project):
// cwd: /project/pages/blog/category/red/index.js
import PageHeader from 'components/PageHeader';
I've tried using webpack resolve option but I can't seem to make it work:
config.resolve = {
alias: {
components: [
path.resolve('../components/')
]
}
};
and
config.resolve = {
root: [
path.resolve('../')
]
};
Am I missing something ?
My app architecture is forked from React Static Boilerplate, so my webpack.config.js looks like this one
config.resolve = {
alias: {
components: path.resolve('../components/')
}
};
alias accepts key value pairs, with value being of type string. I am not sure if it works with array.
To answer more specificly it would good to know where PageHeader and your webpack config is:
assuming:
PageHeader is in /project/pages/components
and your webpack config is at the root level /project
then your resolve would look something like this:
config.resolve = {
alias: {
components: path.resolve('./pages/components')
}
};
again it depends on the path to your webpack config and your components directory. The path.resolve will change corresponding to that.
The problem seems related to React Static Boilerplate, more specifically when the building the static pages.
I found a workaround that does the job for now. I had to prepend a ~ to the alias so it doesn't get "treated" as a node_module..
config.resolve = {
alias: {
"~components": path.resolve(__dirname, '../components'),
"~decorators": path.resolve(__dirname, '../core/scripts/decorators'),
"~helpers": path.resolve(__dirname, '../core/scripts/helpers'),
"~i18n": path.resolve(__dirname, '../core/i18n'),
}
};
Usage:
import fetch from '~helpers/fetch';
import header from '~components/header';
More info about this on this Github issue.

Categories