Optional require in JS React Native / Expo - javascript

Problem
I want to add an optional configuration file to my expo app.
What I've tried
I tried to include the file like this:
const url = require('./config.json').url
This works if the file exists, but it has to also work when it doesn't exist. If I now delete the file, I can't compile my application since require resolves before runtime. Surrounding it with try-catch doesn't work either.
I also tried optional-require and require-optional from npm, but both require libraries not available in a react native app.
Goal
I would prefer to avoid filesystem checks and resolve it statically, but it needs to gracefully abort if the file doesn't exist.

Include a config_example.json file in your repo. Copy it to config.json at startup.

Related

Preserving node.js built-in imports for Electron in rollup

I am making a Electron app with Svelte and Typescript.
I started with this template for that exact purpose, but it disables node.js built-in imports (like fs) in the browser/electron frontend for security.
I do not need this improved security in my project, so I am trying to get node.js fs to work in the Electron browser.
I already modified the Electron Backend script that creates the Browser to re-enable nodeIntegration, and this works: using require("fs") in the Electron browser console logs the fs library.
Using this in the actual typescript frontend code does not work, however. From looking at the bundled JS, it seems like rollup is assuming that the import of fs is just available as a global variable, and trying to guess its name.
When building while importing fs and path, I get the following warnings:
(!) Missing shims for Node.js built-ins
Creating a browser bundle that depends on "path". You might need to include https://github.com/snowpackjs/rollup-plugin-polyfill-node
(!) Missing global variable names
Use output.globals to specify browser global variable names corresponding to external modules
fs (guessing 'fs')
path (guessing 'path')
The first warning suggests a 404 GitHub link that seems to be a polyfill for some Node built-in libraries. This isn't what I want, I want the real node.js fs library. It also informs me that I'm creating a browser bundle - I have tried setting the browser option of #rollup/plugin-node-resolve (used by the template) to false, but this did not help.
The second warning seems to simply inform that it's trying to guess global variable names - which it should not, it should keep the imports.
How do I allow importing Node.js modules here? The linked template project still closely resembles my current one.
Help is greatly appreciated.
Turns out that the deciding factor was the output.format of the rollup.config.js.
This was set to iife, which produced a result without require or import.
Changing it to cjs solves this problem.

laravel app.js very large file size

I have deployed a Laravel 5.3 application to Heroku. However, when loading /login, I noticed a very slow page load time. The problem seems to be a very large app.js file: /js/app.js. Here is a screenshot of the Network resource panel in DevTools: screenshot- Network panel. The 3rd resource from the top is the offending file.
I am not sure why this file has gotten so large. here is a link to the repository: https://github.com/AshMenhennett/Salon-Pricing.
I wasn't able to post anymore links, so do let me know if you would like direct links to specific files.
What should I be doing to mitigate this issue?
The most obvious thing you can do is to run npm run prod. This will compile the assets for production use. But in most cases, you must be looking at other solutions beyond running npm run prod. If your production file is too large, you must check your dependencies. Remove unnecessary dependencies and ensure that you don't use a lot of external libraries. For example, if you are using bootstrap, you should rely on Bootstrap's alerts in order to show alerts rather than using a Vue package to show alerts. I admit that sometimes you will need to use an external library to make your website interactive but to achieve that, you will have to sacrifice the performance. So your best bet in order to reduce the app.js file is to use the minimal external dependencies in your package.json.
The second thing you can do is use minimum HTML in your components' templates. A lot of components with heavy HTML/CSS will contribute to a larger app.js file. This is yet another approach that will result in a smaller app.js file.
Lastly, you should consider using Vue's component slots to pass HTML contents to your components. This will leave the HTML in your static files and only javascript data (API calls, props, etc.) will be compiled in the app.js file. This is an effective approach to build a smaller app.js file.
Edit: You can remove JQuery and Bootstrap scripts from the bootstrap.js file and can include these dependencies separately. It is always a good idea to have a few more scripts rather than having a very large script. i.e. browsers do parallel downloading and thus using JQuery and Bootstrap dependencies separately is a good idea.
From the looks of your link you've not created a production version of your assets, and currently all the source maps are in your app.js file, which will be adding a lot of the file size, the css and js output are also not compress/minified either.
Assuming you're using laravel elixir, you just need to run gulp --production and this will remove the source maps, compress the js and css outputs, etc.
For people that are using Laravel Mix you just need to run npm run prod to compress and remove source maps from app.js itself.
You need to load the components asynchronously
Webpack has an awesome feature to create chunks of code. The key to this is to use async components. These components get loaded completely asynchronously whenever the component is present on the page you just loaded.
Let's do it.
In resources/js/app.js
I changed
Vue.component('jobs', require('./pages/employer/jobs/Index.vue').default);
To
Vue.component('jobs', () => import('./pages/employer/jobs/Index.vue'));
and in webpack.mix.js
mix.webpackConfig({
output:{
chunkFilename:'js/vuejs_code_split/[name].js',
}
});
Now by running npm run watch or prod each component file is saved public/js/vuejs_code_split/[name].js
And the main app.js is automatically calling those components when required.

Breaking a React-Native application into plugable modules

I am looking to write a React-Native application. I want to be able to download new modules at run-time on the device to extend functionality. There would be some core logic that knows how to request new modules based on some form input like a dbs. I do not want to bundle everything into a single monolithic bundle which is what I believe happens now with the built in packager.
This would something similar to how RequireJS works in browser. What I need to know is:
How do I build independent modules? react-native bundle doesn't seem to allow me to select which root modules to begin with and only works on root project
How can I at run-time request new functionality be injected into the current JavaScript environment?
React native starts by pointing at a JS bundle. This means that you would at least have to restart the app to reload the js bundle (assuming that you're reading it from a server and not from the ios device itself).
If you did have a way to update the js files on the server (through some sort of web service that updated based on things the user does) then restarting the app could theoretically reload the JS and provide new functionality to the app.
I was able to get something pretty close to this in JS only. First I had to expose a few more options in the current react-native bundler, mainly, the url (to change the "main" module) and blacklist (to keep from bundling react-native in second bundle) options to their packager (http://github.com/facebook/react-native/blob/master/packager/README.md).
I then had to write a custom fetcher that would download the second bundle and use eval() to evaluate it in the current environment.
The one rub is that I had to add __d('react-native',[],require('react-native')) in the first bundle which I think work like define() from require.js. This exports 'react-native' as an unmangled name that the modules which I plug in can access via normal require() statements. It's a bit confusing at first but from what I can tell they React-native packager works a little like r.js (see http://requirejs.org/docs/optimization.html).

IONIC Error with Cordova file-transfer plugin

I am using the following version of IONIC and Cordova;
IONIC;
1.5.5
Cordova;
5.1.1
Build my mobile application.
But when ever I finish building it and run it I keep getting the following exception:
Uncaught module cordova-plugin-file.ProgressEvent not found
Could someone please help me out ?.
I had the same issue today and in my case this was because the version of the file-transfer plugin was not compatible with the File plugin I use.
The file transfer plugin requires the cordova-plugin-file.ProgressEvent (see FileTransfer.js in the file transfer plugin directory)
But if you're still using an older version of the file plugin (in my case org.apache.cordova.file instead of cordova-plugin-file) then it can't resolve that.
So either you update your plugins so you use the cordova-file-plugin or you change the code of the FileTransfer plugin, this is not advised because when the plugins are reinstalled you will loose this change. But if for whatever reason you can't use the newer file plugin you can use this method.
On line 25 of the FileTransfer.js file change
ProgressEvent = require('cordova-plugin-file.ProgressEvent');
to
ProgressEvent = require('org.apache.cordova.file.ProgressEvent');
If that doesn't solve it, try to look up the correct module name in your File plugin directory's config.xml file (look for the ID property) and use that instead (don't forget to append ProgressEvent)
To elaborate on my point of not changing the code of the FileTransfer plugin you can however copy the plugin code and put it somewhere on your disk and use that plugin instead of the hosted one (which is loaded and used if you just use the plugin's ID)

Concatenate NPM package into one JS file

I am trying to get Swig (the template language) working on Parse Cloud Code with Express. Parse Cloud Code is a Node/Express host that doesn't allow NPM. Ridiculous, I know. I can still load external files into code with requires statements however, so I think that there's hope I can get this working.
So my question is how do I get the whole entire Swig package into a single JS file that I can include from my Parse Express app like so:
var swig = require("./cloud/swig.js");
Worth noting that Parse breaks normal require statements so that the NPM package as-is doesn't work without modifying each and every single file in the node_modules folder to have cloud in its path (which is why my above path has cloud in it). Parse also chokes while uploading lots of small files. Concatenation is a need on this platform.
I have tried playing with browserify for hours, but no combination of anything I do makes exposes the Swig object when I load the browserified file with the require statement. I think it may be the right option since the Browserified file includes all the files from Swig, but it doesn't expose them externally.
My question is either can this be done in browserify, and if so, how? Or is there another way to concatenate a NPM repo down to one file so it can be more easily included from this platform?
Thanks so much.
Browserify is not the right tool for the job.
As the name implies, browserify is intended to be used to generate files you want to execute in the browser. It walks the require calls from an entrypoint (i.e. some JS file you pass to browserify) and bundles them in an object that maps their names to functions wrapping the modules. It does not expect a require function to already exist and doesn't make any use of it. It substitutes its own implementation of require that only does one thing: look up names from the bundle, execute the matching function and return its exports.
You could theoretically require a browserify bundle, but it would just return an empty object (although it might mess with globals). And in all likelihood it might break because the bundled modules think they are being executed in a browser. This won't do any good.
The only sane option if you want to stick with the host, is to copy over the node_modules folder from your local project folder. This may not work if your computer and the server are not 100% compatible (e.g. 32-bit vs 64-bit, Debian vs RedHat, OSX/Windows vs Linux) but this mostly depends on your exact dependencies (basically anything that is built with node-gyp can be a problem).
Node.js uses the node_modules folder when looking up dependencies in require calls automagically. If you can somehow get a node_modules folder with the right contents on the server, require("foo") will work as long as node_modules contains a module foo.
Ultimately, you are trying to use npm modules in Parse Cloud code and currently it's not possible:
https://parse.com/questions/using-npm-modules-in-cloud-code
But if you are only trying to use Swig, then as a work-around, you can consider using underscore template instead. Parse already includes underscore:
https://parse.com/docs/cloud_modules_guide#underscore

Categories