I have env var SERVER_URL=localhost:8000
config.js
export const SERVER_URL = process.env.SERVER_URL;
export { SERVER_URL as default };
and action:
function fetchData(apiUrl, timeout) {
return timeoutPromise(timeout || 15000, fetch(`${SERVER_URL}${apiUrl}`))
.then(checkHttpStatus)
.then(parseJSON);
}
but after use this fetchData I get http://localhost:8000/undefined/some_api
idk where from came this undefined
If you are using create-react-app, only environment variables prefixed with REACT_APP_ will be available.
Try console.log(SERVER_URL), that's where your undefined came from.
Create an environment variable REACT_APP_SERVER_URL instead and refer to it with process.env.REACT_APP_SERVER_URL in your app.
Inside config.js:
const SERVER_URL = process.env.SERVER_URL;
export default SERVER_URL;
Other file app.js:
import SERVER_URL from './config';
Related
Let's say we are creating a module called app by constructing a new vm.SourceTextModule object:
const context = {
exports: {},
console, // custom console object
};
const sandbox = vm.createContext(context);
const app = new vm.SourceTextModule(
`import path from 'path';
console.log(path.resolve('./src'));`,
{
context: sandbox,
}
);
According to the Node.js documentation to obtain the default export from path module we should "link" the imported dependencies of app module to it.
To achieve this we should pass linker callback to app.link method:
async function linker(specifier, referencingModule) {
// the desired logic...
}
await app.link(linker);
How to implement linker function properly so that we could import path module in newly created app module and use it:
await app.evaluate(); // => /home/user/Documents/project/src
P.S. We are using TypeScript, so I checked if we have installed types for path package.
package.json:
"#types/node": "^17.0.31",
I found https://github.com/nodejs/node/issues/35848 where someone posted a code snippet.
From there I've adapted the following linker callback:
const imports = new Map();
async function linker(specifier, referencingModule) {
if (imports.has(specifier))
return imports.get(specifier);
const mod = await import(specifier);
const exportNames = Object.keys(mod);
const imported = new vm.SyntheticModule(
exportNames,
() => {
// somehow called with this === undefined?
exportNames.forEach(key => imported.setExport(key, mod[key]));
},
{ identifier: specifier, context: referencingModule.context }
);
imports.set(specifier, imported);
return imported;
}
The code snippet from the GitHub issue didn't work for me on Node 18.7.0 as is, because the evaluator callback passed to the constructor of SyntheticModule is somehow called with this set to undefined. This may be a Node bug.
I also cached the imported SyntheticModules in a Map because if they have internal state, creating a new SyntheticModule every time will reset that state.
Guided by eslint's prefer-destructuring rule, I defined some constants like this:
const {
NODE_ENV,
API_URL,
} = process.env;
Is it possible to export these constants by prefixing the statement by export?
export const {
NODE_ENV,
API_URL,
} = process.env;
This would seem natural, but eslint-plugin-import complains about a violation of the import/named rule: API_URL not found in '../constants'. In fact, this usage of export is also not described on the relevant MDN page.
Do we then have to repeat all constants in a separate export statement?
const {
NODE_ENV,
API_URL,
} = process.env;
export {
NODE_ENV,
API_URL,
};
Is it possible to export these constants by prefixing the statement by
export?
export const {
NODE_ENV,
API_URL,
} = process.env;
Yes, this is totally valid according to the spec. You can use destructuring patterns in the declarations of exported consts.
This would seem natural, but
eslint-plugin-import
complains about a violation of the
import/named
rule: API_URL not found in '../constants'.
Sounds like that plugin is broken. In fact, your exact use case was reported as working before.
Article 15.2.2.3 of the spec says:
...
ExportDeclaration : export VariableStatement
ExportDeclaration : export Declaration
Article 13.1.4 says:
Declaration : LexicalDeclaration
Article 13.3 says:
LexicalDeclaration:
LetOrConst BindingList;
LetOrConst :
let
const
BindingList :
LexicalBinding
BindingList, LexicalBinding
LexicalBinding:
BindingPattern Initializer
Therefore this:
// ExportDeclaration
export // export
// Declaration
// LexicalDeclaration:
const // LetOrConst
// LexicalBindingList
// LexicalBinding
{ NODE_ENV, API_URL } // BindingPattern
= process.env; // Initializer
is totally valid JavaScript.
any idea how to mock an “import” for testing?
I use jest now.
ie:
//browser.js
export const browser = {
id: undefined
};
export const getBrowser = function() {
return browser;
};
//fetch-data.js
//code that uses the browser and I wanna test
import {getBrowser} from './../components/browser';
export const fetchData = function() {
const browser = getBrowser();
return Object.assign({dontcare:1}, browser);
};
//My test... Im using jest
import {fetchData} from './../fetch-data.js';
expect(fetchData()).toBe({......});
};
now in the test file I want to mock the response of the browser component…
Any ideas?
Thanks!
Got to resolve it in the end with the help of one of the posts but in a different way with Sinnon.js
1) I import the browser component in my test:
import * as browserModule from './../components/browser';
2) now in my tests I'll mock the methods I want:
sinon.stub(browserModule, 'getBrowser').returns({id: 1});
3) all good from here, I call my test object and it gets the proper mocked responses :)
you need to find a way to inject the the getBrowser function into the fetchData
export const fetchData = function(injectedFunction) {
const browser = injectedFunction !== undefined? injectedFunction() || getBrowser();
return Object.assign({dontcare:1}, browser);
};
this way you can now
//your test... Im using jest
import {fetchData} from './../fetch-data.js';
import {getBrowser} from './../components/browser';
let mockBrowser = mock(getBrowser);// <choose your mock library>
// mock the behavior then inject it to the fetchData
expect(fetchData(mockBrowser)).toBe({......});
};
that's why it is good to apply dependency injection in your code to be able to test it with ease
for me you can use http://sinonjs.org/ for test spies, stubs and mocks
Your function in fetch-data.js is dependent upon exports from browser.js.
You would find that browser and getBrowser both are undefined depending on your jest configuration.
Since browser.js is ready for export, you can use jest.requireActual(moduleName) to import and use that module infetch-data.js. I would do this in the following way:
jest.mock("./browser", () => {
const br = jest.requireActual("browser");
return {
...br,
browser: {id:'changed value'}
};
})
This seems dumb, but I have it setup like this:
in config/index.js:
module.exports = {
API_LOCATION: 'http://localhost:8080/api/'
}
then in src/app.js I have:
import Vue from 'vue'
import VueRouter from 'vue-router'
import VueResource from 'vue-resource';
Vue.use(VueRouter);
Vue.use(VueResource);
const App = require("./app.vue");
const home = require("./components/home.vue");
const config = require('../config');
window.config = config;
Then in src/components/home.vue, I have a script block that uses it like so:
<script>
module.exports = {
data: function() {
return {
obj: null
}
},
created: function() {
this.$http.get(config.API_LOCAITON + '/call').then(res => {
// Do some business
}, res => {
// Handle some error
});
}
}
</script>
This works but it strikes me as a bad idea to use window to handle an application configuration. What's the more canonical approach here?
Import it.
<script>
import config from "../config"
module.exports = {
data: function() {
return {
obj: null
}
},
created: function() {
this.$http.get(config.API_LOCATION + '/call').then(res => {
// Do some business
}, res => {
// Handle some error
});
}
}
</script>
Or just the location.
<script>
import { API_LOCATION } from "../config"
module.exports = {
data: function() {
return {
obj: null
}
},
created: function() {
this.$http.get(API_LOCATION + '/call').then(res => {
// Do some business
}, res => {
// Handle some error
});
}
}
</script>
PROD: config/prod.env.js append your VAR='"value"'
'use strict'
module.exports = {
NODE_ENV: '"production"',
API_LOCATION: '"https://production URL"'
}
DEV: config/dev.env.js append your VAR='"value"'
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
API_LOCATION: '"http://localhost"'
})
Your variable will available in process.env.API_LOCATION or
process.env.VAR_NAME
TL;DR; Global configuration in Vue is done using the .env and .env.production files that you create in the route folder of the app (next to package.json)
I can confirm that in Vue using the Vue CLI .env file gets loaded automatically when you run npm run serve
But keep in mind the following that I checked:
Variables in the .env files have to start with VUE_APP prefix to be automatically picked up and available as process.env.VUE_APP_MYVAR in the code
If you're defining JS objects such as 'VUE_APP_MY_OBJECT={a:100}then you'll have to parse it to JSON before using it in the codeJSON.parse(process.env.VUE_APP_MY_OBJECT)`
If you're not using Webpack you might have to fiddle a bit with it to pick these config files up. According to this answer it looks like webpack should do it automatically. Dunno
Simply set ip path(or localhost) in local storage when login successfull and get value from local storage where you need through out the project.
here how you set value in localstrage.
// Set value in IpAdress
localstorage.setItem('IpAddress','192.168.100.100:8080');
// Get value from IpAddress
localstorage.getItem('IpAddress');
in my case whole path looks like:
localstorage.getItem('IpAddress')+/api/controller/method|
I'm working on a project that uses the value in process.env.APP_ENV in order to select the appropiate config file for the current environment:
import prodParams from './production';
import stgParams from './staging';
import devParams from './development';
let params = devParams;
switch (process.env.APP_ENV) {
case 'production':
params = prodParams;
break;
case 'staging':
params = stgParams;
break;
default:
params = devParams;
}
export default params;
I'm trying to test this with the following code (not yet with assertions):
import params from '../../../parameters';
...
it.only('should return the appropriate config ', (done) => {
process.env.APP_ENV = 'production';
console.log(params);
done();
});
However when I set environment variable process.env.APP_ENV as shown above it still reaches the module as undefined, so it always returns the development config instead of the production environment.
Setting aside the test part, the functionality is working fine, but I would like to test it regardless.
Any suggestions on how to fix this?
import statements are executed before any other code, so you can't make this work using import.
You can somewhat get it working with require, if you require the parameters file after you have set the environment variable:
process.env.APP_ENV = 'production';
let params = require('../../../parameters').default;
...
However, this still isn't great, because it'll work just once because of the cache that require maintains (a subsequent test which sets APP_ENV to a different value won't work).
A workaround would be to have parameters.js export a function that you'd call:
// parameters.js
export default function() {
let params = devParams;
switch (process.env.APP_ENV) {
...
}
return params;
}
// test.js
import getParams from '../../../parameters';
...
process.env.APP_ENV = 'production';
let params = getParams();
Or set APP_ENV externally:
$ env APP_ENV='production' mocha ...