I saw the following nodeJS code on a git hub repo:
var env = process.env.NODE_ENV || 'development'
, config = require('./config/config')[env]
, auth = require('./config/middlewares/authorization')
, mongoose = require('mongoose');
I've never seen the square brackets before [env] is this a mistake?
I thought args could only be passed in normal brackets ( ). I could not find documentation anywhere about this.
repo in question is here https://github.com/diki/nodejs-passport-boilerplate and its on line 17 of server.js.
Looking at their config.js example, that file exports an object with each environment as keys:
module.exports = {
development: {
db: 'mongodb://localhost/noobjs_dev',
root: rootPath,
// ...
},
test: {
db: 'mongodb://localhost/noobjs_test',
root: rootPath,
// ...
},
production: {}
}
The square brackets will select only the configs related to the environment defined in your NODE_ENV variable.
Assuming NODE_ENV holds the value development, this would be the same as doing this:
var config = require('./config/config').development;
Which is the same as this:
var config = require('./config/config')['development'];
The advantage of square brackets it that they allow you to select the key on the object dynamically.
Related
I have a react app where I wanted to import a javascript file from a third-party library but file is mark with shebang #!/usr/bin/env node.
I found (e.g. here How to Configure Webpack with Shebang Loader to Ignore Hashbang Importing Cesium React Component into Typescript React Component) I can load file by overriding webpack configuration and adding a new loader shebang-loader (I also have tried shebang-loader2) but overriding webpack in react app is recommended only with #craco/craco so I added it to package.json and tried add loader to existing webpack-config.js.
I produced this lines of code. File craco.config.js:
const throwError = (message) =>
throwUnexpectedConfigError({
packageName: 'craco',
githubRepo: 'gsoft-inc/craco',
message,
githubIssueQuery: 'webpack',
});
module.exports = {
webpack: {
configure: (webpackConfig, {paths}) => {
const shebangLoader = { test: /node_modules\/npm-groovy-lint\/lib\/groovy-lint.js$/, loader: "shebang-loader" }
const {isAdded: shebangLoaderIsAdded1} = addAfterLoader(webpackConfig, loaderByName('url-loader'), shebangLoader);
if (!shebangLoaderIsAdded1) throwError('failed to add shebang-loader');
return webpackConfig;
},
},
};
It resolves problem with shebang and it ignores #!/usr/bin/env node but now I still get error
Module parse failed: Unexpected token (14:16)
File was processed with these loaders:
* ./node_modules/shebang2-loader/index.js
You may need an additional loader to handle the result of these loaders.
| const { getSourceLines, isErrorInLogLevelScope } = require("./utils");
| class NpmGroovyLint {
> "use strict";
| options = {}; // NpmGroovyLint options
| args = []; // Command line arguments
It looks like it does not recognise "use strict" line.
Can anyone put some suggestions what should be a problem ?
After few hours of investigation, I have finally come to a resolution. Firstly I have to say that there is no option to use NpmGroovyLint in react-like applications that run in browsers because after I resolved mentioned problem up here I figured that NpmGroovyLint uses node libraries as perf_hooks which are not available in a browser enviroment.
But I can post code that resolves the problem described in my question. It was needed to add a plugin to babel-loader named 'plugin-proposal-class-properties'. Here is my snipped of craco config. You can use it as a recipe occasionally.
const {addAfterLoader, getLoaders, loaderByName, removeLoaders, throwUnexpectedConfigError} = require('#craco/craco');
const throwError = (message) =>
throwUnexpectedConfigError({
packageName: 'craco',
githubRepo: 'gsoft-inc/craco',
message,
githubIssueQuery: 'webpack',
});
module.exports = {
webpack: {
configure: (webpackConfig, {paths}) => {
const {hasFoundAny, matches} = getLoaders(webpackConfig, loaderByName('babel-loader'));
if (!hasFoundAny) throwError('failed to find babel-loader');
const {hasRemovedAny, removedCount} = removeLoaders(webpackConfig, loaderByName('babel-loader'));
if (!hasRemovedAny) throwError('no babel-loader to remove');
if (removedCount !== 2) throwError('had expected to remove 2 babel loader instances');
//add plugin proposal class properties to existing babel loader
const propClassOptions = {...matches[1].loader.options, ...{plugins: ["#babel/plugin-proposal-class-properties"]}};
const propClassLoader = {...matches[1].loader, ...{options: propClassOptions}};
const babelLoaderWithPropClassPlugin = {...matches[1], ...{loader: propClassLoader}};
const shebangLoader = {
test: /node_modules\/npm-groovy-lint\/lib\/groovy-lint.js$/,
use: [{loader: 'shebang2-loader'}, {...{loader: require.resolve('babel-loader')}, ...{options: propClassOptions}}]
}
const {isAdded: babelLoaderWithPropClassIsAdded} = addAfterLoader(webpackConfig, loaderByName('url-loader'), matches[0].loader);
if (!babelLoaderWithPropClassIsAdded) throwError('failed to add ts-loader');
const {isAdded: babelLoaderIsAdded} = addAfterLoader(webpackConfig, loaderByName('babel-loader'), babelLoaderWithPropClassPlugin.loader);
if (!babelLoaderIsAdded) throwError('failed to add back babel-loader for non-application JS');
const {isAdded: shebangLoaderIsAdded1} = addAfterLoader(webpackConfig, loaderByName('url-loader'), shebangLoader);
if (!shebangLoaderIsAdded1) throwError('failed to add shebang-loader');
return webpackConfig;
},
},
};
I used create-next-app to create my next.js project boiler plate. But as soon i run npm run dev i get the error:
ValidationError: Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
- configuration[0].node should be one of these:
false | object { __dirname?, __filename?, global? }
-> Include polyfills or mocks for various node stuff.
Details:
* configuration[0].node has an unknown property 'fs'. These properties are valid:
object { __dirname?, __filename?, global? }
-> Options object for node compatibility features.
* configuration[0].node has an unknown property 'devServer'. These properties are valid:
object { __dirname?, __filename?, global? }
-> Options object for node compatibility features.
- configuration[1].node should be one of these:
false | object { __dirname?, __filename?, global? }
-> Include polyfills or mocks for various node stuff.
Details:
* configuration[1].node has an unknown property 'fs'. These properties are valid:
object { __dirname?, __filename?, global? }
-> Options object for node compatibility features.
* configuration[1].node has an unknown property 'devServer'. These properties are valid:
object { __dirname?, __filename?, global? }
-> Options object for node compatibility features.
at validate (C:\Users\crisp\OneDrive\Documents\Next.js\next-startup\nextflix\node_modules\next\dist\compiled\schema-utils3\index.js:1:153657)
at validateSchema (C:\Users\crisp\OneDrive\Documents\Next.js\next-startup\nextflix\node_modules\next\dist\compiled\webpack\bundle5.js:137945:2)
at create (C:\Users\crisp\OneDrive\Documents\Next.js\next-startup\nextflix\node_modules\next\dist\compiled\webpack\bundle5.js:141384:24)
at webpack (C:\Users\crisp\OneDrive\Documents\Next.js\next-startup\nextflix\node_modules\next\dist\compiled\webpack\bundle5.js:141426:32)
at f (C:\Users\crisp\OneDrive\Documents\Next.js\next-startup\nextflix\node_modules\next\dist\compiled\webpack\bundle5.js:98978:16)
at HotReloader.start (C:\Users\crisp\OneDrive\Documents\Next.js\next-startup\nextflix\node_modules\next\dist\server\hot-reloader.js:18:415)
at async DevServer.prepare (C:\Users\crisp\OneDrive\Documents\Next.js\next-startup\nextflix\node_modules\next\dist\server\next-dev-server.js:16:453)
at async C:\Users\crisp\OneDrive\Documents\Next.js\next-startup\nextflix\node_modules\next\dist\cli\next-dev.js:22:1 {
errors: [
{
keyword: 'anyOf',
dataPath: '[0].node',
schemaPath: '#/anyOf',
params: {},
message: 'should match some schema in anyOf',
schema: [Array],
parentSchema: [Object],
data: [Object],
children: [Array]
.....
My next.config.js looks as follows.
module.exports = {
webpack: (config) => {
config.node = {
fs: 'empty'
}
return config
}
};
Nothing has changed yet. This is the default. May you please explain to me why am i getting this error.
Any help input will be appreciated.
Can you check any of the dependecies on Nextjs 11 need to be updated.
In my case updating next-transpile-modules to Version: ^8.0.0 resolved the issue.
You are running webpack 5, which only supports __dirname, __filename and global.
Your config assumes webpack 4, which supports many more properties including Node core libraries.
You need to pick which version of webpack you want to run and make sure that your config matches.
Next.js has now webpack-5 enabled by default.
If you don't wanna switch back to webpack-4 (for obvious reasons), your configuration should look something like this:
module.exports = {
webpack: (config, { isServer }) => {
if (!isServer) config.resolve.fallback.fs = false;
return config;
}
};
I saw the answer you posted, there you are configuring path and url also. But you actually don't need to manually configure them as Next.js handles it for you.
For dns, you may do something like this:
module.exports = {
webpack: (config, { isServer }) => {
if (!isServer) {
const fallback = config.resolve.fallback;
fallback.fs = false;
fallback.dns = function () {
if (!arguments.length) return;
const callback = arguments[arguments.length - 1];
if (callback && typeof callback === 'function') callback(null, '0.0.0.0');
};
// or after installing `node-libs-browser`
// fallback.dns = require.resolve('node-libs-browser/dns');
}
return config;
},
};
Refs:
To v5 from v4 | webpack
Automatic Node.js Polyfills Removed
resolve.fallback
next/build/webpack-config.ts
Webpack 5 Adoption
After JDB's answer i had a clear hint. I configured my next.js app to use webpack4 after reading this. Here is my new next.cofig.js:
module.exports = {
webpack5: false,
webpack: (config) => {
config.node = {
dns: "mock",
fs: "empty",
path: true,
url: false,
};
return config;
},
};
Just update the Node version. I was receiving this error also when I tried to create a new next.js app. I had node version 14.16 installed but it seems Next needs ^14.17.0. After updating to 14.18.0 I created a new next app and it ran fine with the default next.config file.
I create a NodeJS server and trying to setup environment variables dynamically. But I'm facing a weird problem. I create a env.js file and here is the related code:
const environment = {}
environment.dev = {
port: 3000,
envName: 'dev'
}
environment.prod = {
port: 5000,
envName: 'prod'
}
const currentEnvironment = typeof process.env.NODE_ENV === 'string'
? process.env.NODE_ENV
: 'dev'
console.log('current environment: ', currentEnvironment) // get currentEnvironment: prod
console.log('environment obj: ', environment) // get environment obj correctly
console.log('getting obj from environment obj: ', environment[currentEnvironment]) // But get undefined
const environmentToExport = typeof environment[currentEnvironment] === 'object'
? environment[currentEnvironment]
: environment.dev
module.exports = environmentToExport
I can't figure out why I'm getting undefined in environment[currentEnvironment].
And here is the package.json scripts from where I'm passing environment variable. I'm using windows by the way.
"scripts": {
"dev": "SET NODE_ENV=dev & nodemon index",
"prod": "SET NODE_ENV=prod & nodemon index"
}
Note: I'm using exported port number while creating server. But incase of getting undefined, I'm always exporting dev environment ! Hope you understand my problem.
I want to import config.js which includes project's API keys. But It returns undefined.
//config.js
var config = {
fbAPI: "key"
}
-
//nuxt.config.js
const cfg = require('./config')
env: {
fbAPI: cfg.apiKey
}
Is this problem about run-time or am I missing something?
You missed modules.export at the end of config.js. The file should look following:
var config = {
fbAPI: "key"
}
module.exports = config;
I have a ApiCaller.js module which generate calls to our api server to get data. It has const field API_URL which points to server url.
This API_URL const changes for dev and prod environments.
So when I need to deploy to dev environment I need to change that url (API_URL) manually to point to dev-api-server and vice-versa.
I want these configuration parameters outside the code and during build process I want to change them dynamically so that I can build with different settings.
I am using webpack to bundle my javascript, html, css files.
You can store your API_URL in webpack config:
// this config can be in webpack.config.js or other file with constants
var API_URL = {
production: JSON.stringify('prod-url'),
development: JSON.stringify('dev-url')
}
// check environment mode
var environment = process.env.NODE_ENV === 'production' ? 'production' : 'development';
// webpack config
module.exports = {
// ...
plugins: [
new webpack.DefinePlugin({
'API_URL': API_URL[environment]
})
],
// ...
}
Now in your ApiCaller you can use API_URL as defined variable, which it will be different depend on process.env.NODE_ENV:
ajax(API_URL).then(/*...*/);
(edit) If I have more than production/development config for different environment constants?
Imagine that you have API_URL like in above answer, API_URL_2 and API_URL_3 which should support different environment settings production/development/test
var API_URL = {
production: JSON.stringify('prod-url'),
development: JSON.stringify('dev-url')
};
var API_URL_2 = {
production: JSON.stringify('prod-url-2'),
development: JSON.stringify('dev-url-2'),
test: JSON.stringify('test-url-2')
};
var API_URL_3 = {
production: JSON.stringify('prod-url-3'),
development: JSON.stringify('dev-url-3'),
test: JSON.stringify('test-url-3')
};
// get available environment setting
var environment = function () {
switch(process.env.NODE_ENV) {
case 'production':
return 'production';
case 'development':
return 'development';
case 'test':
return 'test';
default: // in case ...
return 'production';
};
};
// default map for supported all production/development/test settings
var mapEnvToSettings = function (settingsConsts) {
return settingsConsts[environment()];
};
// special map for not supported all production/development/test settings
var mapAPI_URLtoSettings = function () {
switch(environment()) {
case 'production':
return API_URL.production;
case 'development':
return API_URL.development;
case 'test': // don't have special test case
return API_URL.development;
};
};
// webpack config
module.exports = {
// ...
plugins: [
new webpack.DefinePlugin({
'API_URL': mapAPI_URLtoSettings(),
'API_URL_2': mapEnvToSettings(API_URL_2),
'API_URL_3': mapEnvToSettings(API_URL_3)
})
],
// ...
}
(edit 2)
If you pass string as a environment constant you should use JSON.stringify.
You don't need to define new webpack.DefinePlugin multiple times. You can do it in one object passed to new webpack.DefinePlugin - it looks cleaner.
You could set the define plugin to define a PRODUCTION variable as follows (or alternatively to true if you use different configuration files for the builds):
new webpack.DefinePlugin({
PRODUCTION: process.env.NODE_ENV === 'production'
})
Then in your code you will write something like:
var API_URL = PRODUCTION ? 'my-production-url' : 'my-development-url';
During compilation webpack will replace PRODUCTION with its value (so either true or false), and this should allow UglifyJS to minify our expression:
var API_URL = <true/false> ? 'my-production-url' : 'my-development-url';
The worst case scenario is uglify not being able to minify the conditional expression leaving it as is.