Loading local json file with require? - javascript

I've been googling for hours now, thought I just ask here. For some reason my 'require()' does not work. The recuirejs is included and as far as I can see my return value should be my data in the exact same order as my json file.
here is my code:
$(document).ready(async function() {
let data = await fetchData('./data/file.json');
console.log(data);
}
// fetch and return data
function fetchData(path) {
return require([path]);
}
I originally had this solution (which worked with a local host but I need it without a host):
function fetchData(path) {
return fetch(path).then(response => {
return response.json().then((data) => {
return data;
}).catch((err) => {
console.log(err);
})
});
}
It gives me several script errors and MIME type mismatches plus it logs this instead of my data:
s(e, t, i)
​ arguments: null
caller: null
​ >defined: function defined(e)
​ isBrowser: true
length: 3
name: "s"
​ >prototype: Object { … }
>specified: function specified(e)​
>toUrl: function toUrl(e)​
>undef: undef(i)
I don't know what else I should try.
Thank you!

RequireJS is not compatible with Node.js's require method. It is designed for AMD modules not CommonJS modules and it does not support the loading of plain JSON files. This is why your first attempt does not work.
Your second attempt does not work because file systems requests are treated as cross-origin requests.
The only way to load a JSON file when working on the load filesystem is to have the user select it with an <input type="file"> and then read it with JavaScript.
If you want to read hard-coded JSON then you might consider baking it into your app. The simple way to do that would be to just paste it in as a JS object literal. More complex programs might benefit from using a tool like Webpack (which would need a JSON loader) and pulling it into the JS at build-time rather than development time (the aforementioned pasting approach) or run time (which is impossible as mentioned in previous paragraphs).

You have two options:
Use a tool like Webpack to put all your frontend files into the bundle
Download JSON file from web server:
I assume you are using jQuery already, so:
$.get('https://petstore.swagger.io/v2/swagger.json').then(function(data) {
console.log(data.swagger);
});
In this case you have to make your json file available for webserver
$.get('/dist/data/file.json').then(function(data) {
console.log(data);
});

Related

Node.js Function not updating value after 1st invoke

I've recently taken interest in the Discord.js framework, and was designing a bot for a server. Apologies in advance for the messiness of the code.
The issue I'm facing is that after I first run the command, the the function is invoked, the value of ticketValue does not update to the update value in my JSON file.
const fs = require("fs");
module.exports = {
commands: ["ticket"],
minArgs: 1,
expectedArgs: "<message>",
callback: (message, arguments, text) => {
// Console Log to notify the function has been invoked.
console.log("FUNCTION RUN")
let jsondata = require("../ticketNum.json")
let ticketValue = jsondata.reportNews.toString()
// Turning the number into a 4 digit number.
for(let i = ticketValue.length; i<4;i++) {
ticketValue = `0${ticketValue}`
}
console.log(`#1 ${ticketValue}`)
// Creating the Discord Chanel
message.guild.channels.create(`report-incident-${ticketValue}`, {
type: 'text',
permissionOverwrites: [
{
id: message.author.id,
deny: ['VIEW_CHANNEL'],
},
],
})
// Adding one to the ticket value and storing it in a JSON file.
ticketValue = Number(ticketValue)+1
console.log(`TICKET VALUE = ${ticketValue}`)
fs.writeFile("./ticketNum.json",JSON.stringify({"reportNews": Number(ticketValue)}), err => {
console.log(`Done writing, value = ${ticketValue}`)
})
console.log(require("../ticketNum.json").reportNews.toString())
},
}
I believe this is due to something called require cache. You can either invalidate the cache for your JSON file each time you write to it, or preferably use fs.readFile to get the up-to-date contents.
Also worth noting that you are requiring from ../ticketNum.json but you are writing to ./ticketNum.json. This could also be a cause.
You seem to be using JSON files as a database and while that is perfectly acceptable depending on your project's scale, I would recommend something a little more polished like lowdb which stills uses local JSON files to store your data but provides a nicer API to work with.
You should only use require when the file is static while the app is running.
The caching require performs is really useful, especially when you are loading tons of modules with the same dependencies.
require also does some special stuff to look for modules locally, globally, etc. So you might see unintended things happen if a file is missing locally and require goes hunting.
These two things mean it's not a good replacement for the fs tools node provides for file access and manipulation.
Given this, you should use fs.readFileSync or one of the other read functions. You're already using fs to write, so that isn't a large lift in terms of changing the line or two where you have require in place or a read.

Return array with fast-csv in Node

I am attempting to parse a large file using the fast-csv library and return its values as an array to a config.js file. Please help as the value of countries in the config's model.exports section ends up being undefined.
Parser:
import csv from 'fast-csv';
export function getCountries() {
let countries = [];
csv.fromPath('./src/config/csv_configs/_country.csv')
.on('data',
function(data) {
countries.push(data);
})
.on('end', function () {
return countries;
});
}
Config:
import {getCountries} from '../tools/csv_parser';
let countryList = [];
module.exports = {
port: process.env.PORT || 8000,
token: '',
countries: getCountryList()
};
function getCountryList() {
if (countryList.length === 0) {
countryList = getCountries();
}
return countryList;
}
I understand this is due to me attempting to return a value from the anonymous function on(), however I do not know the proper approach.
You're correct that returning values from the callback in .on('end' is the source of your problem.
Streams are asynchronous. If you want to use this fast-csv library, you're going to need to return a promise from getCountries(). However, I'm assuming that's not what you want, since you're using the result in a config file, which is synchronous.
Either you need to read your csv synchronously, or you need to refactor the way your application works to be able to have your config be asynchronous. I'm assuming the second option isn't possible.
You probably want to look into using another CSV library that doesn't use streams, and is synchronous. Two examples from a quick Google search are:
https://www.npmjs.com/package/csv-load-sync
https://www.npmjs.com/package/csvsync
I haven't used either of these libraries personally, but it looks like they'd support what you're trying to do. I'm assuming your CSV file is small enough to all be stored in memory at once, if not, you're going to have to explore more complicated options.
As a side note, is there any specific reason that the data has to be in CSV format? It would seem to be much easier to store it in JSON format. JSON can be imported to your config file directly with require; no external libraries needed.

using WebAssembly in chrome extension

I have a chrome extension that includes a complicated function comp_func(data) which takes a lot of CPU by performing many bitwise operations. Because of that, I'm trying to use WebAssembly.
I've tried to follow several tutorials, for example this one and this one.
The first link says:
fetch('simple.wasm').then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, importObject)
).then(results => {
results.instance.exports.exported_func();
});
but I get an error:
Uncaught (in promise) TypeError: WebAssembly Instantiation: Import #0 module="env" error: module is not an object or function
I've tried a lot to use this approach, but it didn't work. I can't understand how to use WebAssembly that is loaded from the .wasm file.
So I've tried an easier approach:
The second link says to put this line in the html file:
<script src="index.js"></script>
and then just use the exported function:
var result = _roll_dice();
BUT, I'm in an extension so I only have a background.html file.
So I'm looking for a way to access the Module which was loaded in the background file.
And things get complicated, because the function comp_func(data) is called from a Worker.
This is what I've tried so far:
If I call chrome.extension.getBackgroundPage() I can access the Module
but I can't send it to the Worker:
Failed to execute 'postMessage' on 'Worker': # could not be cloned.
And if I try to stringify it first:
Uncaught TypeError: Converting circular structure to JSON
(I tried to un-circular it, didn't work...)
And I can't call chrome.extension.getBackgroundPage() from the Worker because I can't access chrome API from there.
So my questions are:
Did someone try to load .wasm file in chrome extension and succeed?
The second approach (loading the js file) sounds simpler but if you have a working example for this approach it would be great.
or 2. How to access the Module that has been loaded in background.html (from the second example)?
or 3. How to pass the functions that I needed from the js file to the Worker (via postMessage)?
To summarize, did someone try to use WebAssembly in a chrome extension and survive to tell?
EDIT:
I eventually left the approach of WebAssembly.
I also posted this question at bugs-chromium,
and after few month got an answer. Not sure if this is really working, but maybe this, along with the marked answer, will help someone.
I've been fiddling with WebAssembly recently, and found a way to make it work. Here are the script files:
main.js
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null, {file: "content_script.js"});
});
content_script.js
var importObject = { imports: { imported_func: arg => console.log(arg) } };
url = 'data:application/wasm;base64,' + "AGFzbQEAAAABCAJgAX8AYAAAAhkBB2ltcG9ydHMNaW1wb3J0ZWRfZnVuYwAAAwIBAQcRAQ1leHBvcnRlZF9mdW5jAAEKCAEGAEEqEAAL";
WebAssembly.instantiateStreaming(fetch(url), importObject)
.then(obj => obj.instance.exports.exported_func());
The data URL belongs to the common tutorial wasm sample (simple.wasm), which writes 42 on the console.
PS. If it seems like cheating or bad practice to you, this content_script.js also works:
var importObject = {
imports: {
imported_func: function(arg) {
console.log(arg);
}
}
};
var response = null;
var bytes = null;
var results = null;
var wasmPath = chrome.runtime.getURL("simple.wasm");
fetch(wasmPath).then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, importObject)
).then(results => {
results.instance.exports.exported_func();
});
Only if you include the code files in the web_accessible_resources section in manifest.json, though:
...
"web_accessible_resources": [
"content_script.js",
"main.js",
"simple.wasm"
],
...
Github: https://github.com/inflatablegrade/Extension-with-WASM
It can also be made compatible with Manifest V3.

Gulp plugin to include/exclude line of JS code depending on task ran

Are there any gulp plugins that when ran, can include/exclude a line of JavaScript.
For example, in one of my JS files I perform an HTTP GET to a local JSON file:
// To be used for localhost
$http.get('path-to-JSON-file.json')
.success(function (data) {
done(data);
})
But when i move to my .NET server, i need this to be a call to a method:
// To be used for .NET
$http.get('/MyData/GetMyDataJson').success(function (data) {
.success(function (data) {
done(data);
})
So, I'm happy to create 2 separate scripts tasks, one for a localhost version, and one for .NET.
I could use gulp-replace, but I really don't want to be placing code in my gulp.js file
I would use something like Mustache to generate your code, eg something like this:
Your main file
$http.get('{{action_get_data}}').success(function (data) {
.success(function(data) {
done(data);
})
Your gulp file:
var env="node";
var data={
"node":{"action_get_data":"path-to-JSON-file.json"}
".NET":{"action_get_data":"/MyData/GetMyDataJson"}
};
gulp.src("./templates/*.mustache")
.pipe(mustache(data[env]))
.pipe(gulp.dest("./dist"));
Note: However, there's a bit of overhead with this: you need to declare the variables in your file, fill an array in the gulpfile, wait for compilation everytime.
You can also use the same codebase and just use variables for the things that change between the different versions of the environment.
Note2: You can also fetch the environment data from a config file like this:
var data= require('data.json');
data.json
{
"node":{"action_get_data":"path-to-JSON-file.json"}
".NET":{"action_get_data":"/MyData/GetMyDataJson"}
}

GruntJS Configurable First Time Run

I am working on a Angular Demo Application and I want to automatize a lot of things.
It's some sort of a boilerplate, albeit a more complex one, and I want to make a config file in which we'll put API Keys and other stuff, and I want that file to be populated by Grunt with user interaction when the project is started for the first time.
Something like:
grunt build - it should ask the user directly in the console for the API keys, that will be inserted in the config file where I am defining some global constants for the entire App.
Is there such an example of functionality with Grunt ?
You can handle the questioning by using:
https://github.com/dylang/grunt-prompt
It is a nice little plugin that do one job and do it well. It put whatever value you have entered in the command line into variables: (example)
prompt: {
target: {
options: {
questions: [
{
config: 'key', // arbitrary name or config for any other grunt task
type: 'input', // list, checkbox, confirm, input, password
message: 'What is your API key?',
default: '', // default value if nothing is entered
when: function(answers) { return !grunt.file.exists('config.yml'); } // only ask this question when this function returns true
}
]
}
}
}
Then you can use the Grunt.file functions to write those values into files:
http://gruntjs.com/api/grunt.file#grunt.file.write
To orchestrate it, you will need to create a custom task: (example)
grunt.registerTask("my_config_task", function (arg) {
var key = arg || grunt.config('key');
grunt.file.write("config.yml", key);
});
grunt.registerTask('build', ['prompt', 'my_config_task']);
The writing will likely need refinement as you will, I guess, need to replace values and organise as a yml file or json object, etc...
Found one of the possible solutions while looking at the sources of grunt-bump. What are they doing is parsing the config file as a JSON object:
https://github.com/darsain/grunt-bumpup/blob/master/tasks/bumpup.js#L128
Replacing whatever values they need (as JSON) and overwrite the file with the object stringified:
https://github.com/darsain/grunt-bumpup/blob/master/tasks/bumpup.js#153
Seems to work well.

Categories

Resources