File Upload in Elm - elm

How does one upload a file (image or excel) in Elm?
Can't seem to find any examples.
The answer is fine even if the native code is used. Have seen Data in Elm-Html but it appears files and blobs are not supported. What is the way around this?

I am the author of the library MisterMetaphor refers to. It's easier to use than he explains though. Take a look at how I set up elm-package.json in the example: https://github.com/simonh1000/file-reader/blob/master/example/elm-package.json - just add "native-modules": true,.
I have written a blog to support the release of the code for 0.18 and show how uploads to e.g. S3 can be done in Elm.

The official way to do it is now https://package.elm-lang.org/packages/elm/file/latest/
This is an addition that came in Elm 0.19.
Now the official Http package supports it as well. Here is an example from https://package.elm-lang.org/packages/elm/http/latest/Http#request
import File
import Http
type Msg = Uploaded (Result Http.Error ())
upload : File.File -> Cmd Msg
upload file =
Http.request
{ method = "PUT"
, headers = []
, url = "https://example.com/publish"
, body = Http.fileBody file
, expect = Http.expectWhatever Uploaded
, timeout = Nothing
, tracker = Nothing
}

The other option to handle file uploads in Elm is to
get a base64-encoded value from the FileReader into your Elm app through a port.
Then, send that base64-encoded value to your server (e.g. in a JSON body).
A tutorial can be found here https://www.paramander.com/blog/using-ports-to-deal-with-files-in-elm-0-17 (it says it's for Elm 0.17, but it works unchanged in Elm 0.18).
The downsides of this approach are
your server needs to base64-decode the files it receives which increases server load a little, and
base64-encoding increases the amount of bytes that will go over the wire (compared to a file/blob).
The upside:
no need to use a package with native code.
From the Elm Http docs: "Right now it only supports strings, but we will support blobs and files when we get an API for them in Elm."

Use a library like file-reader.
There is a set of pretty comprehensive examples, you can start with this one.
There's a caveat, though. Since this library uses some native code, you can't get it from the official package repo. So you will have to resort to manually installing it.
For this purpose, I wrote this hacky elm-package install replacement. It expects an exact-dependencies.json file in the root directory of your project. You can get this file initially from the elm-stuff directory that elm-package creates when building your project. You then add a reference to the file-reader package to the exact-dependencies.json file like this:
{
"evancz/elm-effects": "2.0.1",
"evancz/virtual-dom": "2.1.0",
"evancz/elm-http": "3.0.0",
"evancz/start-app": "2.0.2",
"evancz/elm-html": "4.0.2",
"elm-lang/core": "3.0.0",
"simonh1000/file-reader": "1.0.0"
}
You will also need to add a reference to file-reader to your elm-package.json file:
{
"version": "1.0.0",
"summary": "helpful summary of your project, less than 80 characters",
"repository": "https://github.com/user/project.git",
"license": "BSD3",
"source-directories": [
"."
],
"exposed-modules": [],
"dependencies": {
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.1 <= v < 3.0.0",
"evancz/elm-html": "4.0.2 <= v < 5.0.0",
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"evancz/start-app": "2.0.2 <= v < 3.0.0",
"simonh1000/file-reader": "1.0.0 <= v < 2.0.0",
},
"elm-version": "0.16.0 <= v < 0.17.0"
}
After this, you run the elm-package install replacement and hopefully it will work.

Related

Bundle npm module 'cheerio' in K6 test

I am trying to create some tests using K6 framework from LoadImpact, but I am struggelig with including external NPM module following the instructions on their documentation site.
On loadImpacts documentations site they include a detailed example on just what I am after, modules that enable me to parse xml from a soap service response. But, I am unable to get this working! Now, I am a total javascript newbie, but I have been coding for many years and would really like to solve this.
The can be found here: https://docs.k6.io/docs/modules#section-npm-modules
can anyone get this working? I need to run this on servers isolated from the Internet, so I am totaly dependent on creating the packages and transfer the required files.
According to the documentation a package is created like this
-- bundle `cheerio` npm module
git clone git#github.com:cheeriojs/cheerio.git
npm install browserify index.js -s cheerio > cheerio.js
My first question: In the folder I am residing when running this command a 'cheerio.js' file is created along with a a 'cheerio' folder and a 'node_modules' folder.
the cheerio.js in my "root" directory only contains the following:
+ cheerio#0.22.0
+ index.js#0.0.3
+ browserify#16.2.3
updated 3 packages and audited 2829 packages in 2.221s
found 0 vulnerabilities
Back to LoadImpacts example on how to reference this package in a k6 javascript:
import cheerio from "./vendor/cheerio.js";
export default function()
{
const res = http.get("https://loadimpact.com/");
const $ = cheerio.load(res.body);
What file is this, and where in the structure generated by browserify can I find it? I have tried to change this to point to 'index.js' in the 'cheerio' folder or cheerio.js found in 'cheerio/lib'. I will then receive a complaint about the first line in cheerio.js which defines a "parse" variable it cannot find:
var parse = require("./parse'),
if I change this to
var parse = require("./parse.js')
it goes on to complain about missing 'htmlparser2' which I can also find in this structure, but it seems like the entire dependency structure is not working.
Can anybody give me some guidance on how to create a browserify package with dependencies for cheerio and how/what I need to copy to my k6 project to make this work like on the loadImpact site.
The k6 docs for this definitely need some clarification, which I'll later do. The vendor folder currently mentioned there isn't something special, the docs are just missing a step to copy the cheerio.js and xml2js.js files that were generated by browserify to a new vendor folder in your k6 project.
For now, I'll try to offer a simplified explanation on how to achieve the same thing in a simpler way:
Create a new empty folder and go to it in a terminal
Run npm install browserify cheerio there (ignore the npm warnings about missing package.json or description)
Run ./node_modules/.bin/browserify ./node_modules/cheerio/ -s cheerio > cheerio.js in that folder
The resulting cheerio.js file in the folder root should be the file you import from the k6 script:
import http from "k6/http";
import cheerio from "./cheerio.js";
export default function () {
const res = http.get("https://loadimpact.com/");
const $ = cheerio.load(res.body);
console.log($('head title').text())
}
That should be it for a single npm library.
And if you need to use multiple npm packages, it might be better to invest some time into bundling them in a single browserified .js file. For example, if you need both the cheerio and the xml2js libraries mentioned in the k6 docs, you can do something like this:
Create a new empty folder
Add something like the following package.json file in it:
{
"name": "k6-npm-libs-demo",
"version": "0.0.1",
"description": "just a simple demo of how to use multiple npm libs in k6",
"main": "npm-main.js",
"dependencies": {},
"devDependencies": {
"browserify": "*",
"cheerio": "*",
"xml2js": "*"
},
"scripts": {
"install": "./node_modules/.bin/browserify npm-main.js -s npmlibs > vendored-libs.js"
},
"author": "",
"license": "ISC"
}
Of course, if you need different libraries than cheerio and xml2js, you need to adjust the devDependencies options.
Add an npm-main.js file like this (again, adjusting for the libraries you want):
exports.xml2js = require('xml2js');
exports.cheerio = require('cheerio');
Open that folder in a terminal and run npm install. That should result in the creation of a vendored-libs.js file in the root of the folder, which you can use in k6 like this:
import http from "k6/http";
import { cheerio, xml2js } from "./vendored-libs.js";
export default function () {
const res = http.get("https://loadimpact.com/");
const $ = cheerio.load(res.body);
console.log($('head title').text())
var xmlString = '<?xml version="1.0" ?>' +
'<items xmlns="http://foo.com">' +
' <item>Foo</item>' +
' <item color="green">Bar</item>' +
'</items>'
xml2js.parseString(xmlString, function (err, result) {
console.log(JSON.stringify(result));
});
}

GraphQL response ERROR "URLSearchParams is not defined"

those are the dependencies I'm using
"dependencies": {
"express": "^4.16.3",
"express-graphql": "^0.6.12",
"graphql": "^0.13.2",
"lodash": "^4.17.10"
}
here is my schema.js file looks like
here is the code inside my server.js file
and I recieve this error
I was facing the same issue. Here's how I managed to fix it:
const { URLSearchParams } = require('url');
global.URLSearchParams = URLSearchParams;
lodash library find methods first parameter is the data source. so URLSearchParam is mistakenly typed. be careful about auto completions of some IDEs provide. so they may fill incorrect data as you type.
using a good JavaScript linter can point you that problem. I do recommend eslint.
in this situation the data source is the variable users so replacing URLSearchParam with users solved this problem.

Telerik platform Managing npm packages

hi i am building video streaming app through telerik platform. My app structure looks like :
my-project
app
- package.json
- app.js
node_modules
package.json
server.js
I have added firebase and bitmovin player plugin to my node_modules. Now the Telerik platform documentation says : to add require references to package.json file.
I do not get which package.json file needs to be opened . There are two files. The first one in the Project root which looks like:
{
"dependencies": {
"tns-core-modules": "2.5.1",
"bitmovin-player": "7.2.0-rc6",
"firebase": "4.1.2"
},
"devDependencies": {
"nativescript-dev-android-snapshot": "0.0.6",
"#types/firebase": "2.4.31"
}
}
The other package.json file is in the app folder looks like :
{
"name": "tns-template-blank",
"main": "app.js",
"version": "2.5.0",
"author": "Telerik <support#telerik.com>",
"description": "Nativescript blank project template",
"license": "Apache-2.0",
"keywords": [
"telerik",
"mobile",
"nativescript",
"{N}",
"tns",
"appbuilder",
"template"
],
"repository": {
"url": "https://github.com/NativeScript/NativeScript/commit/30aca890749e9e3fb9bd0f5ddc9de5b6995859bc"
}
}
and the app.js file looks like :
var application = require('application'),
mainModule = 'navigation/navigation';
application.start({
moduleName: mainModule
});
I do not get in which package.json file needs to be configured and where to enter the require reference for the module (like bitmovin player & firebase ) as mentioned in the telerik platform documentation which is shown in the picture above step no. 8.
please guide.
The first package.json (i.e. root package.json) is where any plugins go. If using the CLI, you can do tns plugin add nativescript-dom and it would then modify the package for you to be:
{
"dependencies": {
"tns-core-modules": "2.5.1",
"bitmovin-player": "7.2.0-rc6",
"firebase": "4.1.2",
"nativescript-dom": "2.0.0"
},
"devDependencies": {
"nativescript-dev-android-snapshot": "0.0.6",
"#types/firebase": "2.4.31"
}
}
The dependencies section is what needs to be changed; it needs the plugin name and the version you will be using. It that your package.json file is already correct for what you installed. You can also use http://plugins.nativescript.rocks for a list of plugins and their current versions.
A couple notes; based on you saying you needed bitmovin-player and firebase but using NativeScript; this won't work. The firebase and bitmovin-player you have referenced are not NativeScript plugins, so they won't work. To my knowledge bitmovin does not have NativeScript version (but my NativeScript-ExoPlayer plugin might be a good replacement) and then the NativeScript-Firebase I believe is the plugin you want for Firebase support in NativeScript.
I also see that you are using tns-core-modules 2.5.x; this means you want to get plugins that are 2.x compatible; the 3.x plugins will NOT work with TNS 2.x (and a large number of 2.x plugins won't work in 3.x).
When using a plugin (for example using my nativescript-dom) you do a var dom = require('nativescript-dom'); (or you can use const dom = ... as NativeScript can use ES6 grammer). You do not have to point to the actual js file inside the plugin. If the plugin is built correctly; it will automatically use the correct js file inside the plugin.
Finally in NativeScript the DevDependancies are for anything that is not being put into the application. In this case the android-snapshot plugin runs some build code during the build phase of the application.

React Native: Unable to resolve module fs

Unable to resolve module fs from /...mypath
I got this error when trying to import a node module into my react-native app.
The module used 'fs' in this way:
var fs = require('fs');
var list = JSON.parse(fs.readFileSync(__dirname + '/list.json', 'utf8'));
I ended up using 'rn-nodeify' to include fs into React Native. You can use most of the node core modules this method. Install it with npm:
npm install rn-nodeify
Then in package.json file, add the following line in "scripts" to specify which modules you want to include in your RN project. For example, I used fs, crypto and https, and the line goes
"postinstall": "node_modules/.bin/rn-nodeify --install crypto,fs,https --hack"
React Native applications do not run in the Node.js environment (it is only used by the packager to actually serve and compile your application bundle).
Since your app is running inside JS VM on either iPhone or Android, the only way to access filesystem is to use react-native-fs or any other 3rd party module that utilises bridge connection to talk to the platform specific native APIs.
it took me a while to find the issue, I'm sharing it as it might be useful for future reference (using react native with Expo):
One of my coworkers accidentally imported in one of our react components app.config.js in the project root to read some configuration rather than using expo-constants.
it was causing it to read the .env file from the react native wrapper that obviously doesn't have the fs lib.. this is the first line of our app.config.js:
import 'dotenv/config';
the correct way for reading settings inside app.config is:
import Constants from 'expo-constants';
const appConfig = Constants.manifest;
Install react-native-fs (follow the instructions at de link), so weather the error persist, enter at the directory ('./node_modules/tfjs-image-recognition-base/build/commonjs/env/) search by the file: (creatFileSystem.js) and edit:
fs = require('fs')
to:
fs = require('react-native-fs')
I don't know if this is recommended way, but was the only that worked for me.
If you want to import a json list just call it direct.
Example:
import subscriptionData from './assets/dataSource/subscriptionData.json';
or
var subscriptionData = require('./assets/dataSource/subscriptionData.json');
You don't need to convert it, and you can use to import your data or the way you want.
function installJson() {
console.log("Iniciando Importação");
subscriptionData.forEach(item => {
firestore().collection('subscription').add(item);
});
}
subscriptionData.json
[{
"code": 325,
"name": "bla bla bla"
},
{
"code": 356,
"name": "ble ble ble"
}]
Instead of:
const fs = require('fs');
Try:
const fs = require('react-native-fs');
worked in my case.

Create different versions form one bootstrap file with require.js

I develop an iPad/iPhone App web app. Both share some of the resources. Now I wanna build a bootstrap js that looks like this:
requirejs(['app'], function(app) {
app.start();
});
The app resource should be ipadApp.js or iphoneApp.js. So I create the following build file for the optimizer:
{
"appDir": "../develop",
"baseUrl": "./javascripts",
"dir": "../public",
"modules": [
{
"name": "bootstrap",
"out": "bootstrap-ipad.js",
"override": {
"paths": {
"app": "ipadApp"
}
}
},
{
"name": "bootstrap",
"out": "bootstrap-iphone.js",
"override": {
"paths": {
"app": "iphoneApp"
}
}
}
]
}
But this doesn't seems to work. It works with just one module but not with the same module with different outputs.
The only other solution that came in my mind was 4 build files which seems a bit odd. So is there a solution where i only need one build file?
AFAIK the r.js optimizer can only output a module with a given name once - in your case you are attempting to generate the module named bootstrap twice. The author of require.js, #jrburke made the following comment on a related issue here:
...right now you would need to generate a separate build command for each script being targeted, since the name property would always be "almond.js" for each one.
He also suggests:
...if you wanted just one build file to run, you could create a node program and drive the optimizer multiple times in one script file. This example shows using requirejs as a module and calling requirejs.optimize().
I took a similar approach in one of my projects - I made my build.js file an ERB template and created a Thor task that ran through my modules and ran r.js once for each one. But #jrburke's solution using node.js is cleaner.