I want to use the nconf module to retriever configuration data from a file(s) according to a policy and export the properties in the JSON configuration files as a module like so:
import * as config from 'ConfigData'
console.log(config.MyProperty)
The ConfigData module is just wrapping nconf defining the policy of the naming scheme of the config files and what order to load the files.
var myconfig = new nconf.Provider({
env: true,
argv: true,
stores: [
{ type: 'file', file: path.join(__dirname, 'config.json')},
{ type: 'file', file: path.join(__dirname, 'default-config.json')}
]
});
How do I export the config properties in the JSON file and how does the client code use it?
Related
in my project i am using cypress with plain javascript. i am facing the challenge of importing the modules (page objects) via aliases instead of spaghetti code like ../../../../folder/page.js.
I don't use typescript or react.js and don't have a src folder/directory.
my tests run locally in the browser or via a docker image (pipeline).
I would like to transform from this:
import { LoginPage } from "../../pages/loginPage.js";
to something like this:
import { LoginPage } from "#Pages/loginPage.js";
but I always get an error:
Error: Webpack Compilation Error
./cypress/e2e/accountOverview/accountOverviewPageTest.spec.js
Module not found: Error: Can't resolve 'Pages/loginPage.js' in 'C:\Users\User\automated_frontend_tests\automated_frontend_tests\cypress\e2e\accountOverview'
resolve 'Pages/loginPage.js' in 'C:\Users\User\automated_frontend_tests\automated_frontend_tests\cypress\e2e\accountOverview'
Parsed request is a module
using description file: C:\Users\User\automated_frontend_tests\automated_frontend_tests\package.json (relative path: ./cypress/e2e/accountOverview)
Field 'browser' doesn't contain a valid alias configuration
Looked for and couldn't find the file at the following paths:
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\cypress\e2e\accountOverview\node_modules]
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\cypress\e2e\node_modules]
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\cypress\node_modules]
[C:\Users\node_modules]
[C:\node_modules]
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\node_modules\Pages\loginPage.js]
[C:\Users\User\automated_frontend_tests\node_modules\Pages\loginPage.js]
[C:\Users\User\node_modules\Pages\loginPage.js]
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\node_modules\Pages\loginPage.js.js]
[C:\Users\User\automated_frontend_tests\node_modules\Pages\loginPage.js.js]
[C:\Users\User\node_modules\Pages\loginPage.js.js]
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\node_modules\Pages\loginPage.js.json]
[C:\Users\User\automated_frontend_tests\node_modules\Pages\loginPage.js.json]
[C:\Users\User\node_modules\Pages\loginPage.js.json]
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\node_modules\Pages\loginPage.js.jsx]
[C:\Users\User\automated_frontend_tests\node_modules\Pages\loginPage.js.jsx]
[C:\Users\User\node_modules\Pages\loginPage.js.jsx]
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\node_modules\Pages\loginPage.js.mjs]
[C:\Users\User\automated_frontend_tests\node_modules\Pages\loginPage.js.mjs]
[C:\Users\User\node_modules\Pages\loginPage.js.mjs]
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\node_modules\Pages\loginPage.js.coffee]
[C:\Users\User\automated_frontend_tests\node_modules\Pages\loginPage.js.coffee]
[C:\Users\User\node_modules\Pages\loginPage.js.coffee]
# ./cypress/e2e/accountOverview/accountOverviewPageTest.spec.js 5:17-46
I have tried several solutions, including:
//webpack.config.js
module.exports = {
resolve: {
alias: {
"#pages": path.resolve(__dirname, "cypress/pages/*"),
},
},
};
//testspec file
import { LoginPage } from "#pages/loginPage.js";
const loginPage = new LoginPage();
#Uzair Khan:
I tried your solution, but it still didn't work. The error message remains the same. It seems that the IDE does not search in the correct folder, but only in ...\node_modules\#page\loginPage.js which makes no sense.
If I enter const loginPage = new LoginPage(), the module LoginPage() cannot be found by the IDE either. Something is wrong with the solution. Do I still have to install any packages via NPM?
In your webpack.config.js file add resolve.alias which you want to make alias. It looks like something this below:
resolve: {
alias: {
'#page': path.resolve(__dirname, '{path you want to make alias}')
}
}
Since you are using cypress, you have to update the resolve path in cypress.config.js. Here is mine cypress.config.js
import { defineConfig } from 'cypress'
import webpack from '#cypress/webpack-preprocessor'
import preprocessor from '#badeball/cypress-cucumber-preprocessor'
import path from 'path'
export async function setupNodeEvents (on, config) {
// This is required for the preprocessor to be able to generate JSON reports after each run, and more,
await preprocessor.addCucumberPreprocessorPlugin(on, config)
on(
'file:preprocessor',
webpack({
webpackOptions: {
resolve: {
extensions: ['.ts', '.js', '.mjs'],
alias: {
'#page': path.resolve('cypress/support/pages/')
}
},
module: {
rules: [
{
test: /\.feature$/,
use: [
{
loader: '#badeball/cypress-cucumber-preprocessor/webpack',
options: config
}
]
}
]
}
}
})
)
// Make sure to return the config object as it might have been modified by the plugin.
return config
}
And import in other file via that alias you set in cypress.config.js. Here is mine for example:
import page from '#page/visit.js'
const visit = new page()
When('I visit duckduckgo.com', () => {
visit.page()
})
I think both answers are nearly there, this is what I have for src files:
const webpack = require('#cypress/webpack-preprocessor')
...
module.exports = defineConfig({
...
e2e: {
setupNodeEvents(on, config) {
...
// #src alias
const options = {
webpackOptions: {
resolve: {
alias: {
'#src': path.resolve(__dirname, './src')
},
},
},
watchOptions: {},
}
on('file:preprocessor', webpack(options))
...
path.resolve() resolves a relative path into an absolute one, so you need to start the 2nd param with ./ or ../.
Also, don't use wildcard * in the path, you just need a single folder that will be substituted for the alias in the import statement.
If in doubt, check the folder returned (in the terminal)
module.exports = defineConfig({
...
e2e: {
setupNodeEvents(on, config) {
const pagesFolder = path.resolve(__dirname, './cypress/pages')
console.log('pagesFolder', pagesFolder)
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,
})
In my assets i've got a config.json file with an apiUrl
{
"apiUrl":"https://api.example.com"
}
I've got multiple environments, but one of them needs to be able to be altered after the build.
import * as config from '../assets/config.json';
export const environment = {
production: true,
appTheme: "blue-theme",
apiUrl: config.apiUrl
appName: "App",
};
in my typings.d.ts i've got
declare module "*.json" {
const value: any;
export default value;
}
When i do console.log(config) I get:
{
apiUrl:"https://api.example.com"
}
But when i do console.log(config.apiUrl) I get:
undefined
Can someone tel me what i'm doing wrong?
How to retrieve Json data
using by node
const config: any = require('../assets/config.json');
export const environment = {
production: true,
appTheme: "blue-theme",
apiUrl: config.apiUrl
appName: "App",
};
Using by http
How to extract JSON data from http.get in Angular 2 properly?
How to fetch JSON file in Angular 2
I want to be able to bundle my React app with Webpack such that distributed copies put onto a CDN can be sourced, called and initialised with a bunch of config relevant to a client.
After reading this and this, I'm setting up my webpack entry file as follows:
// ... React requires etc.
(() => {
this.MyApp = (config) => {
// some constructor code here
}
MyApp.prototype.init = () => {
ReactDOM.render(<MyReactApp config={MyApp.config} />, someSelector);
}
})();
The idea being that in my client, I can do something like the following:
<script src="./bundle.js" type="text/javascript"></script>
<script type="text/javascript">
MyApp.init({
some: "config"
});
</script>
And my MyApp#init function will render my React app inside some container on the client.
Am I thinking about this in the right way? Is there a simpler or more efficient way to go about this?
My error is Uncaught TypeError: Cannot set property 'MyApp' of undefined, since this inside the IIFE is undefined. I'd really like to understand both why this is happening and advice on how to fix it.
Thanks in advance!
So I kind of found a solution to this, as described here
If I change my webpack.config.js file to add the following attributes to the output object, i.e.
var config = {
// ...
output: {
// ...
library: 'MyApp',
libraryTarget: 'umd',
umdNamedDefine: true,
}
}
This specifies the file I'm bundling with webpack as a UMD module, so if I have a function in that file and export it...
export const init = (config) => {
ReactDOM.render(<MyReactApp config={config} />, someSelector);
}
I can then, in my client, do the following.
<script src="./bundle.js" type="text/javascript"></script>
<script type="text/javascript">
MyApp.init({
some: "config"
});
</script>
And my React app renders.
If anyone thinks this is a daft way of doing it, I'd love to hear it!
MORE INFORMATION ON WEBPACK CONFIG
Please bear in mind I haven't touched this code in a while. Given it's Javascript, the world has likely moved on and some practises may be outdated.
This is my React entrypoint file (src/index.js)
import 'babel-polyfill';
import React from 'react';
import { render } from 'react-dom';
import Root from './components/Root';
import configureStore from './lib/configureStore';
const store = configureStore();
export const init = (config) => {
render(
<Root store={store} config={config} />,
document.querySelector(config.selector || "")
);
}
This is my Webpack config (webpack.config.js)
var webpack = require('webpack');
var path = require('path');
var loaders = require('./webpack.loaders');
module.exports = {
entry: [
'webpack-dev-server/client?http://0.0.0.0:8080', // WebpackDevServer host and port
'webpack/hot/only-dev-server',
'./src/index.js' // Your appʼs entry point
],
devtool: process.env.WEBPACK_DEVTOOL || 'source-map',
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js',
library: 'Foo',
libraryTarget: 'umd',
umdNamedDefine: true,
},
resolve: {
extensions: ['', '.js', '.jsx']
},
module: {
loaders: loaders
},
devServer: {
contentBase: "./public",
noInfo: true, // --no-info option
hot: true,
inline: true
},
plugins: [
new webpack.NoErrorsPlugin()
]
};
As you can see, my Webpack config outputs my bundle.js which is what my front-end will ingest.
You have enclosure around your class.
MyApp needs to be exported or attached to the global window object before you can call it like that.
In your situation you are actually not calling MyApp.init() but you are calling window.MyApp.init(), but global object window does not have object MyApp attached to it.
// ... Simple attaching MyApp to the window (as a function)
window.MyApp = (config) => {
...
}
// ... Using class and export
class MyApp {
constructor(config){...}
}
export default MyApp
// or simply attach to the window
window.MyApp = MyApp
I would prefer to create class and export module using export. Then create another file just for attaching to the window. Since it is not considered best practice to attach classes to the window like that.
// Import module and attach it to the window
import MyApp from '.my-app'
window.MyApp = MyApp
You can look for advanced options of exporting modules as UMD, AMD...
I added a new layer in dojo build config as below:
releaseDir: "./my-build",
layers: {
"myLib": {
include: [
"myFile1",
"myFile2"
]
}
}
After build, nls created under my-build folder, and include all locale files
my-build/
-myLib.js
-nls
--myLib_en-us.js
In the html file, my dojoConfig is:
var dojoConfig = {
async: true,
cacheBust: false,
paths: {
"ah": "/hm-webapp/resources/scripts/ah",
"i18n": '/hm-webapp/resources/i18n'
},
baseUrl: "/hm-webapp/resources/scripts/dojo/",
locale: ""
};
and I am including my layer via a script tag:
<script src="/my-build/myLib.js">
</script>
But there is a
404 error for myLib_en-us.js
It seems that dojo automatically load nls files, but the request path is like this
--/nls/myLib_en-us.js
There is no subpath "my-build" for the nls request.
My question is how to change the nls path to the build path.
Thanks.