properly use ENV Variables in vue-cli - vue.js

So I'm brand freaking new to Vue-Cli and I'm following a tutorial on using a Vue frontend with a Rails backend. Im configuring Axios to handle my requests.
My problem:
Im trying to set an ENV_VAR on my API_URL constant, at this point when I try to console.log the API_URL I get the following error:
Uncaught ReferenceError: process is not defined
at <anonymous>:1:13
I have the following to config/dev.env.js
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
ENV_API_URL: '"http://localhost:3000/api/fuzeisp/v1"'
})
and I am trying to call that ENV in src/backend/axios/index.js
import axios from 'axios'
const API_URL = process.env.ENV_API_URL
const securedAxiosInstance = axios.create({
baseURL: API_URL,
withCredentials: true,
headers: {
'Content-Type': 'application.json'
}
})
I have tried to read the docs, but for some reason i cant make heads or tails of this! any assistance here would be greatly appreciated! Please, If you need more information i would be happy to provide it for you!
Thanks in advance.

The vue cli is using the dotenv to parse .env files with their content, adding their content to the process.env object. However, these variables will only be available at build-time (since process.env is a global property of the node environemnt).
Code at client-side will not have access to the process object at all. However, vue cli helps out! It reads process.env variables at build time and replaces them with their corresponding values - so you can use them in your client side code. NOTE: It only replaces those variables prepended with VUE_APP_; e.g. VUE_APP_BASE_URL=www.myapp.com.
Read more about it here

so I was able to log the output of VUE_APP_ENV_API_URL by adding the following in my App.vue file:
<script>
export default {
name: 'App',
mounted () {
console.log(process.env.VUE_APP_ENV_API_URL)
}
}
</script>

Related

Vue 3 external component/plugin loading in runtime

I am designing an architecture for the Vue 3 app with distributed module-based ownership. Module system will be represented with plugins (seems like the most appropriate solution allowing vuex module and vue-router dynamic injects). Each such module/plugin will be developed by dedicated team working within isolated repos. We cannot use npm package-per-plugin approach as deployment process should be isolated as well, and with npm approach core app team will have to rebuild app each time npm package plugin has updates. This means we will have to load such plugins/pages at runtime via http.
So far this approach by Markus Oberlehner seems like some sort of the way to go - it uses custom Promise based solution for webpack's missing "load external url script at runtime" functionality. While it works fine with Vue 2, Vue 3 gives VNode type: undefined error.
The above mentioned article offers the following webpack external component loading solution:
// src/utils/external-component.js
export default async function externalComponent(url) {
const name = url.split('/').reverse()[0].match(/^(.*?)\.umd/)[1];
if (window[name]) return window[name];
window[name] = new Promise((resolve, reject) => {
const script = document.createElement('script');
script.async = true;
script.addEventListener('load', () => {
resolve(window[name]);
});
script.addEventListener('error', () => {
reject(new Error(`Error loading ${url}`));
});
script.src = url;
document.head.appendChild(script);
});
return window[name];
}
But above, as I said, does not work with Vue 3 defineAsyncComponent mechanism.
// 2.x version WORKS
const oldAsyncComponent = () => externalComponent('http://some-external-script-url.js')
// 3.x version DOES NOT WORK
const asyncComponent = defineAsyncComponent(
() => externalComponent('http://some-external-script-url.js')
)
So I have two questions:
Are there any known better solutions/suggestions for above architectural specification?
Is there any working webpack dynamic external import solutions tested with Vue 3 out there?
UPD: Here is small reproduction repo
We solved this problem together via chat.
Components built via the Vue 3 vue-cli rely on Vue being available in the global scope. So in order to render components loaded via the technique described in my article, you need to set window.Vue to a reference to Vue itself. Then everything works as expected.
update:
If import vue from vue/dist/vue.esm-bundler and set to global, then no need to change webpack / Vite config, and no need to load vue from cdn.
import * as Vue from 'vue/dist/vue.esm-bundler';
window.Vue = Vue;
Besides setting window.Vue, some other webpack or Vite configuration should also be set, otherwise some error is presented in console: vue warn invalid vnode type symbol(static) (symbol)
Vue3 + webpack:(https://github.com/vuejs/vue-next/issues/2913#issuecomment-753716888)
// index.html:
<script src="https://cdn.jsdelivr.net/npm/vue#3.0.4"></script>
// vue.config.js
configureWebpack: config => {
...
config.externals = { vue: 'Vue' }
...
}
Vue3 + vite:(https://github.com/crcong/vite-plugin-externals)
// vite.config.js
import { viteExternalsPlugin } from 'vite-plugin-externals'
export default {
plugins: [
viteExternalsPlugin({
vue: 'Vue'
}),
]
}

Vue.js environment variables not working with axios on Heroku

I have deployed a Vue.js application to heroku an api also hosted on heroku.
The VueJS app uses axios to connect to the api. I have set a config variable in heroku:
VUE_APP_ROOT_API = https://[my-express-api].herokuapp.com/api
Here is my base axios call:
import axios from 'axios'
const token = localStorage.getItem('token')
export default () => {
console.log(process.env.VUE_APP_ROOT_API)
return axios.create({
baseURL: process.env.VUE_APP_ROOT_API,
headers: {
'Content-Type': 'application/json',
token: token,
},
validateStatus: function () {
return true;
}
})
}
However, the console log reveals that the variable is undefined and axios is using the Vue app url as the base for api calls (https://[my-vue-app].herokuapp.com/undefined/) instead of the one specified in the config variable.
Resolved this. It turns out that my config variable was being compiled into the code at build time, so once I deployed to trigger a rebuild, the new config var worked. Adding/Updating config vars will automatically restart the dynos, but that doesn't rebuild any compiled code.
For me, appending the build command in my package.json with '--mode production' before pushing to heroku fixed the issue.
https://forum.vuejs.org/t/production-env-on-app-deployed-in-heroku/71077
Good luck!

Unable to use axios in js function

We are building an application using VueJS, are new to its concepts. Facing an error when we try to make a call using axios from a js function.
The error is "export 'default' (imported as axios) was not found in ./axios.js"
Please let us know what we might be doing wrong. Appreciate your help.
import Vue from 'vue';
import axios from './axios.js';
export const MY_CONST = 'Vue.js';
export let memberList = new Vue({
el: '#members',
data: {
members: []
},
mounted: function () {
this.getAllMembers();
},
methods: {
getAllMembers: function () {
var me = this;
axios.get("https://xxxxx.com/services/api.php")
.then(function (response) {
me.members = response.data.members;
});
}
}
});
Assuming you've installed axios as a dependency or devDependency in your package.json and installed it via npm or yarn then I would suspect your issue is that you're looking for axios in a file called axios.js in the same directory as the calling component. You should instead look for the package axios like this:
import axios from 'axios';
If you're indeed trying to export axios from a custom file with configuration or something then you need to see what you're exporting from the file and make sure it is indeed axios. Though from the sound of your error that doesn't seem to be what your'e trying to do.

Populate router with external json

I would like to add routes from an external json file, which can change at runtime, to my Nuxt application. A similar topic can be found here.
I've overridden the default Nuxt router with my own implementation. If I import the routes async using axios + router.addRoutes(), I seem to loose the server side rendering. It seems like createRouter will have async support, but it's not in an official release of Nuxt yet.
How do I import a js/json file synchronously to my router.js below, so that I can populate the routes? I want to be able to configure the routes at runtime, so I don't want it to be a part of the bundle.
modules/router.js:
const path = require('path')
module.exports = function () {
this.nuxt.options.build.createRoutes = () => {}
this.addTemplate({
fileName: 'router.js',
src: path.resolve(`${this.options.srcDir}`, 'router.js')
})
}
nuxt.config.js:
modules: ['~/modules/router']
router.js:
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export function createRouter () {
const router = new Router({
mode: 'history',
routes: [/* ... */]
})
return router
}
You could try with sync-request.
It is a NPM package aimed to perform synchronous web requests. It is available here.
Please note that, as stated in the documentation of the package itself, it is not suitable for production environment, probably because of application hanging in case of missing data.
So await would be an answer but I guess you already tried that? So, something like this.
const routeFile = await fetch('pathToTheJsonFile');
const routes = await routeFile.json();
In case you can't make the method async, as a workaround maybe use jQuery. I don't like this but if there's no other option, for now, use async: false in jQuery get.
jQuery.ajax({
url: 'pathToYourJsonRoutes',
success: function (result) {
},
async: false
});

Add CloudKit JS to Vue Project

I'm trying to add CloudKit JS to a new Vue project. Ideally I'd be able to access CloudKit's functions from any component in my app. I'm brand new to Vue, so please go easy on me. :)
So far, I've tried putting the following in main.js:
var fetch = require('node-fetch')
var CloudKit = require("./cloudkit.js")
CloudKit.configure({
services: {
fetch: fetch
},
containers: [{
containerIdentifier: '...',
apiToken: '...',
environment: 'development'
}]
})
That gives me a script error in cloudkit.js:
TypeError: Cannot read property 'ArrayBuffer' of undefined
So then I read this SO post and tried this in App.vue:
export default {
name: 'App',
components: {
'master': Master
},
mounted() {
let CloudKit = document.createElement('script')
CloudKit.setAttribute('src', 'https://cdn.apple-cloudkit.com/ck/2/cloudkit.js')
document.head.appendChild(CloudKit)
}
}
I'm then able to configure CloudKit and use it inside App.vue, but I'm unclear on how to make CloudKit available in all my components without redefining it as I've done in the mounted() function above.
How can I import CloudKit and make it available in my Vue app globally?
I might be over-simplifying things, but I tried adding:
<script src="https://cdn.apple-cloudkit.com/ck/2/cloudkit.js"></script>
...to the index.html file in my Vue project, and it seems to work great. The CloudKit object is available in all of my components. ¯\_(ツ)_/¯
Your can add a new global property in vue as well :
Import CloudKit as you did then add this in your main.js : Vue.prototype.$CloudKit = CloudKit
Now, Cloudkit is available in your project with this.$CloudKit
More info here
PS: you may configure cloudkit in mounted in the app