I have dummy template of package.json . I want to copy dummy package.json inside some folder (Application name folder) and update the name from from package.json . can we do this in node js.
here is my source package.json file
{
"name":"$name"
}
I tried like this
const fs = require('fs');
const prompt = require('prompt-sync')();
let appName = prompt('what is application name..?');
if(!appName){
appName='temp'
}
console.log(`Application name is ${appName}`);
if (!fs.existsSync(`${appName}`)){
fs.mkdirSync(`${appName}`);
}
fs.copyFile('./source/package.json', `${appName}/package.json`, (err) => {
if (err) throw err;
console.log('source.txt was copied to destination.txt');
});
when I run node index.js . it ask "application name" user enter application name let say example (abc). It create a folder abc and put package.json file which is working fine.
Now issue is I want the content of package.json is
{
"name":"abc"
}
can we replace the name variable ?
Let's say you have ./abc/package.json and its contents look like this:
{
"name": "$name",
"version": "0.1.0"
}
If you want to modify just the name field, you'll have to:
read the package data as JSON text
parse it as an object
modify the name property to your desired value
write it back to the file
A minimal example of doing that in a script might look like this:
./rename.mjs:
import {readFile, writeFile} from 'node:fs/promises';
const pkgPath = './abc/package.json';
const textEncoding = {encoding: 'utf-8'};
const json = await readFile(pkgPath, textEncoding);
const pkgData = JSON.parse(json);
pkgData.name = 'abc';
const prettyJson = JSON.stringify(pkgData, null, 2);
await writeFile(pkgPath, prettyJson, textEncoding);
After you run it:
node rename.mjs
The package contents will be updated:
{
"name": "abc",
"version": "0.1.0"
}
Ref:
fsPromises.readFile
fsPromises.writeFile
Related
I have to add unit testing to legacy code where I can make no changes inside the code hence can't refactor the code to add async/await or increase the jest version from 25.0.0
code file (sample code of actual implementation):
window.getUsers = function(){
$.get(url)
.then(data => {
data.forEach(val => {
$(".box-user .box-content").append("<h1>hello</h1>");
console.log('box users content code file',document.querySelector('.box-users > .box-content').innerHTML);
})
})
.catch(err => {})
}
test case i am trying to run
import path from 'path';
import '#testing-library/jest-dom/extend-expect';
const fs = require('fs');
const html = fs.readFileSync(path.resolve(__dirname, './code-file.html'),'utf8');
const $ = require('jquery');
const mockResponse = {
"data": [
{
"id": "test id",
"name": "test name",
"surname": "test surname",
"jobTitle": "test job title",
}
],
"length": 1
};
describe("code-file",()=>{
document.documentElement.innerHTML = html;
it("api mocking and appending html ",()=>{
$.get = jest.fn().mockImplementation(() => {
return Promise.resolve(mockResponse);
});
let {getUsers} = require("./code-file");
getUsers();
let boxUsersHtml = document.querySelector(".box-users > .box-content").innerHTML;
console.log('box users content testing file',boxUsersHtml)
})
})
as you can see inner html for testing code is empty while I do see inner html of code file to have some value. I believe this is due to the async behavior where in the test case is complete and the html has not been appended yet because it is present inside a then block.
need to know how to execute then block before any assertions(before console in the above code) are made without making changes in actual code.
done function did not help link for reference testing async code
I have the following object:
const basePoints = {}
which I need to fill with json files. Currently I do:
import WH11 from 'assets/WH11';
const basePoints = { WH11}
I have like a dozen of such Json files but only 2-3 can be used at a given time. INstead of importing and loading all the JSON files i don't need, I want to require/import based on a config file as shown below:
and my config.js:
const config = {
basePoints: {
"WH11": "West Gate",
"WH12": "West Gate Back Drop"
}
}
WH11, WH12 etc basically exist in json format in my assets directory:
assets/basepoints/WH11.json
{
"startingID" : 198
}
etc. Now there can a dozen or more of such json files. The user just adds the ones to be used for the month in config.js.
Is there a way to require/import the json file based on the config file. The app can't compile if I do:
Object.keys(config.basePoints).forEach(key => {
basePoints[key] = require('../assets/basepoints/' + key + '.json');
});
the error is unexpected require().
You can use the latest ES2020 feature - Dynamic Import
Syntax -
import('/modules/<module_name>')
.then(module => {
//
})
.catch(err => {
//
});
You can learn more about it in this MDN document (scroll down to the dynamic import section) -
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
I am using Gatsby as a Static Site Generator and using Netlify to deploy.
Netlify lets you set Environment Variables in its UI backend.
I've set a few env vars in the Netlify backend to be able to post subscribers to a mailing list.
DATA_NO = 'XXXX'
LIST_ID = '123456'
API_KEY = 'XXXXXXXXXXXXXXXXXXXXXXXXXX'
In my src files, I've got a component that responds to a onSubmit event and constructs a URL to post a new subscriber.
(axios is used as a package for sending HTTP requests, etc)
import React, { useState } from "react"
import axios from 'axios'
const Form = () => {
const [userEmail, setState] = useState({'email_address': ''})
const creds = 'anystring:'+ process.env.API_KEY
let URL = 'https://'+ process.env.DATA_NO +'.api.example.com/3.0'
URL += '/lists/'+ process.env.LIST_ID +'/members'
const submitSubscribe = async e => {
e.preventDefault()
const payload = {
'email_address': userEmail.email_address,
'status': 'subscribed'
}
try {
const response = await axios.post( URL , payload, {
headers: {
'Authorization': 'Basic ' + Buffer.from(creds ).toString('base64')
}
})
console.log('r', response)
console.log('r data', response.data)
} catch(err) {
console.log(err);
}
}
return (
<form name="newsletter-signup" method="post" onSubmit={submitSubscribe}>
{/*<input type="hidden" name="form-name" value="newsletter-signup" />*/}
<input type="email" placeholder="Email required" onChange={handleChange} value={userEmail.email_address} required />
<button type="submit" className="button primary-button-inverted">Send'</button>
</form>
)
}
So, what's happening is that on RUN time, my env vars are coming out as undefined.
I've been on the Netlify docs and they keep saying you need to interpolate the values to the client to be able to use them. I understand the logic here. These env vars need to be printed and bundled during build time, not invoked at run time.
The question I'm struggling with is HOW do I do this?
I have set up a .env.development file in the root of my project. I have tried prefixing my env vars with GATSBY_ but I still have the same trouble.
I tried using require('dotenv').config() but I'm not sure where exactly to put that (in my gatsby-node.js, gatsby-config.js) or do I need to include on the page with my component that is using these env vars.
I'd like to be able to set these vars up in one place (maybe two if testing in development) but I don't want to much tweaking involved to be able to use them in both development and production builds.
I also understand that Netlify or Gatsby can process these vars into a functions/ folder in my source code that I can somehow make use of but that seems like more than I need to just post a simple form.
Please help!
Update
Current code:
In my project root, I created two .env files, one for development and one for production. They each share the following format (remember, I am developing in GatsbyJS):
GATSBY_MC_API_KEY="xxxxxxxxxxxxxxxxxxxxxxxxx-xxxx"
GATSBY_MC_DATA_NO="xxxx"
GATSBY_MC_AUDIENCE_ID="xxxxxxxxxxx"
I've set up a separate config.js file in src/config/config.js to organize and validate my env vars (thanks #Baboo_). It looks like:
export const MC_API_KEY = process.env.GATSBY_MC_API_KEY;
export const MC_DATA_NO = process.env.GATSBY_MC_DATA_NO;
export const MC_AUDIENCE_ID = process.env.GATSBY_MC_AUDIENCE_ID;
const envVars = [
{name: "MC_API_KEY", value: MC_API_KEY},
{name: "MC_DATA_NO", value: MC_DATA_NO},
{name: "MC_AUDIENCE_ID", value: MC_AUDIENCE_ID}
]
export const checkEnvVars = () => {
const envVarsNotLoaded = envVars.filter((envVar) => envVar.value !== undefined);
if (envVarsNotLoaded.length > 0) {
throw new Error(`Could not load env vars ${envVarsNotLoaded.join(",")}`);
}
}
checkEnvVars()
However, when I run gatsby develop, the "Could not load env vars" error gets thrown.
You are doing it the right way.
What you have to do is indeed prefix your environment variables with GATSBY_, Gatsby will automatically load them. Then call them in your code:
const creds = 'anystring:'+ process.env.GATSBY_API_KEY
let URL = 'https://'+ process.env.GATSBY_DATA_NO +'.api.example.com/3.0'
tURL += '/lists/'+ process.env.GATSBY_LIST_ID +'/members'
Make sure to use the whole string process.env.GATSBY_LIST_ID instead of process.env[GATSBY_LIST_ID] because the object process.env is undefined.
Locally
Make sure to create to .env files, .env.development and .env.production. The former is used when you run gatsby develop and the latter when you run gatsby build.
You may already know that you shouldn't commit these files.
Netlify
Add the same environment variables in your deployment pipeline on Netlify. Here is the related doc. This way Netlify can build your webiste when being deployed.
Improvements
Instead of refering environment variables directly, create a file where they are loaded and if one of them cannot be retrieved, throw an error. This way you will be noticed when the loading fails and save debugging time.
Example:
// config.js
export const API_KEY = process.env.GATSBY_API_KEY;
export const DATA_NO = process.env.GATSBY_DATA_NO ;
const envVars = [
{name: "API_KEY", value: API_KEY},
{name: "DATA_NO", value: DATA_NO},
]
const checkEnvVars = () => {
const envVarsNotLoaded = envVars.filter(isUndefined);
if (envVarsNotLoaded.length > 0) {
throw new Error(`Could not load env vars ${envVarsNotLoaded.join(",")}`);
}
}
const isUndefined = (envVar) => typeof envVar.value === "undefined";
// component.js
import React, { useState } from "react"
import axios from 'axios'
// Import environment variables
import { API_KEY, DATA_NO } from "./config"
const Form = () => {
// ...
const [userEmail, setState] = useState({'email_address': ''})
const creds = 'anystring:'+ API_KEY
let URL = 'https://'+ DATA_NO +'.api.example.com/3.0'
You need to add a different env file for the two environments to make this work.
Meaning .env.development and .env.production.
I believe this to be primarily a question about regex, but I may be wrong.
Let's say I wanted to exclude the folder in my project root called art.
My output regex in the CLI looks like:
blacklistRE: /(all|the|other|matchers|art\.*)$/
But this leads to an error:
Unable to resolve "art/core/color" from "..\..\node_modules\react-native\Libraries\ART\ReactNativeART.js"
How can I exclude the top level art directory without affecting all child directories?
From the bundler's docs
blacklistRE
Type: RegExp
A RegEx defining which paths to ignore.
https://facebook.github.io/metro/docs/configuration/#blacklistre
The code of the function I'm calling:
It's short and self-contained in this file, if anyone better than me with regex might have any insight. https://github.com/facebook/metro/blob/8c53c38932c3e396109014ac707287fbdf2500d3/packages/metro-config/src/defaults/blacklist.js#L35-L44
My full code looks like:
const blacklist = require('metro-config/src/defaults/blacklist');
const regexStrings = [
// DEFAULTS
'.*\\android\\ReactAndroid\\.*',
'.*\\versioned-react-native\\.*',
'node_modules[\\\\]react[\\\\]dist[\\\\].*',
'node_modules[\\\\].cache[\\\\].*',
'packages[\\\\]electron[\\\\].*',
'node_modules[\\\\]electron.*',
'website\\node_modules\\.*',
'heapCapture\\bundle.js',
'.*\\__tests__\\.*',
'.*\\.git\\.*',
// CUSTOM
'art\\.*',
]
const constructBlacklistRE = () => {
const formedRegexes = regexStrings.map(piece => new RegExp(piece));
console.warn(formedRegexes);
return blacklist([...formedRegexes]);
};
const config = {
blacklistRE: constructBlacklistRE(),
}
This should work:
const blacklist = require('metro-config/src/defaults/blacklist');
const path = require('path');
const ignoreTopLevelFolders = [
'art'
// add more top level folders here
].map(f => new RegExp(`${ path.resolve(f) }/.*`));
module.exports = { resolver: { blacklistRE: blacklist(ignoreTopLevelFolders) } };
Im new to js and i dont understand how can i take an object from json file,
for example this file : local.json
{
"server": "myname",
"url": 10.0.0.1
}
I need to get the url to insert in in my js code like this, replace the 127.0.0.1 with what i have in json file at url:
import axios from 'axios';
import jsonFile from '../local.json';
const http = require("http");
const host = '127.0.0.1'; #should be 10.0.0.1 from json file
Your json file should be:
{
"server": "myname",
"url": "10.0.0.1"
}
(use double quotes)
and just use dot:
const host = jsonFile.url
In javascript, Specific Object value can be accessed by following three ways:
DOT (.) operator
const obj = {
"server": "myname",
"url": "10.0.0.1"
};
const url = obj.url;
console.log(url); // 10.0.0.1
Square bracket ([])
const obj = {
"server": "myname",
"url": "10.0.0.1"
};
const url = obj["url"];
console.log(url); // 10.0.0.1
De-structuring (>=ES6)
const obj = {
"server": "myname",
"url": "10.0.0.1"
};
const { url } = obj;
console.log(url); // 10.0.0.1
You need to use the "dot" syntax.
const host = jsonFile.url
I assume you need to get configurations to instantiate your server.
You may like to follow below steps to instantiate settings:
Install the dependency config
It allows you to define a json file of settings.
I define the structure
you create a directory inside your project called config inside you create a json file default.json
│
config
│--- default.json
│
inside the file you write your values
{
"server": "myname",
"url": "10.0.0.1"
}
and to access you do the following
file = index.js
const config = require ("config");
console.log (config.get ("url"));