Running Web Server in File (file://) protocol - javascript

I am using Quasar to make an Vue SPA web app/page. In this case, this web app should be ran only by clicking the index.html file, which is created by Quasar packager. The package will only be distributed locally and will NOT be hosted in a domain.
Now my question is. Since I will be using XMLHttpRequest to open local files in the bundle (xml files), I need to open a web server.
Is there any way I can auto-start (programatically) a web server just by double-clicking on the index.html (file:// protocol)?
I was thinking something like this (but I still couldn't get it to work due to error Cannot statically analyse 'require(…, …)' in line 74):
const LocalWebServer = require('local-web-server')
const ws = LocalWebServer.create({
port: 9000,
directory: 'public'
})
/* shut down */
ws.server.close()
https://github.com/lwsjs/local-web-server/wiki/API-reference
Thanks!

No, a html file will not be able to launch an executable and open a tcp port.

In theory, it should be possible to make a Quasar PWA working from a USB key if you make all your data static and calls to it local.
Basically you’re looking at creating a snapshot, or several snapshots of all of the api calls made by your app. Which means, if your API can request « products », you need to export them all in a .json so you can perform « queries » locally, to a global object.
This means all of your axios requests (which are XMLHttpRequests sugar-coated anyway) or equivalents must be replaced by static data, for example: file://[some_path_of_your_choice]/products.json, categories.json, anything_the_app_requires.json, etc.
Then any « by id » request the app makes, i.e. « show product detail page, which id is in the current file:/// URL », the app fetches the ID in the global objects you’re going to declare, once you’ve stringified the .json files mentioned above.
.json files are accessed through file:/// (path is relative to index.html)
You turn them into global JS objects (all views may need access).
(optional) you initialize them in $state (if the app requires state management)
don’t worry too much about performance bottlenecks, except the browser ones.
You may have to concatenate all of your vue files into a single one.

Related

Static website access of environmental variable: "process is not defined"

I have a static website developed through 11ty (Node based SSG), which contains a Contact form that sends a request to a nodemailer API with the data. Both are hosted on Render, as a Static Website and Web Service respectively, and they share a basic auth password which I've stored in each project as an environmental variable.
The Web Service accesses the variables just fine. However, the static website's event presents me with the error in the title "process" isn't defined, as in "process.env.VARIABLE_NAME" which is how I'm accessing them. I tried including a secret .env file in the project with the same key and including dotenv in the project, but no change.
I assume the nature of the static site is making it so the environmental variable isn't being processed/applied somehow. What possible steps could I be missing here?
EDIT: Although it seems it might be possible for me to do this through methods such as command line arguments (which then get injected into the code during the build process), that wouldn't work for my case since the password had to be secret in the generated source files. The dotenv package didn't work in my case. Finally, I've opted to discard this password-based authentication instead and simply use honeypot fields to prevent spam and CORS Origin headers in the API to control request source.
Your static site is running in a different context than your web service (which acts like a server). Since your static site is run from a users browser, it does not understand node-specific functionality like loading files or accessing your process environment.
Adding your password to your static site would also create a security risk, because a user could just see your password, take it, and run their own requests without any security your site may have.
A usual approach to this would be to create an API of your own that takes in a request from your static site and talks to the API directly or a technology stack that takes the page rendering to a server (like ServerSideRendering). This way, YOUR system takes care of calling the API while your users requests are restricted.

Why do we need to run a local server for running a pure html/css/js app?

Why can't we just run the web app by running/opening the index.html?
Why does the file:///C:/[...address]/index.html not loading the css/js correctly like http://localhost:3000/?
Here are a few notes that we should consider:
1- Diffrent Protocols
I should mention that there are two protocols:
File protocol which is prefixed by file:///
HTTP(network) protocol which is prefixed by http://
So they are two different protocols therefore the browsers treated them differently.
2- Different path resolver
Root relative links e.g. src="/js/modal.js" are available when using a server to run our app(to simply run the app on HTTP protocol)
server based:
Home -> http://127.0.0.1:5500/home.html
Home -> http://127.0.0.1:5500/home.html
file based:
Home -> file:///C:/Users/MyUser/Desktop/home.html
Home -> file:///C:/home.html
3- Cookies and local storage
Based on Mozilla
localStorage data is specific to the protocol of the document. In particular, for a site loaded over HTTP (e.g., http://example.com), localStorage returns a different object than localStorage for the corresponding site loaded over HTTPS (e.g., https://example.com).
For documents loaded from file: URLs (that is, files opened in the browser directly from the user’s local filesystem, rather than being served from a web server) the requirements for localStorage behavior are undefined and may vary among different browsers.
In all current browsers, localStorage seems to return a different object for each file: URL. In other words, each file: URL seems to have its own unique local-storage area. But there are no guarantees about that behavior, so you shouldn’t rely on it because, as mentioned above, the requirements for file: URLs remain undefined. So it’s possible that browsers may change their file: URL handling for localStorage at any time. In fact some browsers have changed their handling for it over time.
And Based on Mozilla and WikiPedia and IETF, Cookies are small blocks of data created by a web server while a user is browsing a website, So, it is strictly an HTTP mechanism which will be accessible when we use a web server to run our web app.
4- CORS
Based on Cross origin policy You can not send ajax request on file.
finally
There are quite a few features that I haven't listed here(e.g. service worker, and security features) That can't be used with file type.

Javascript frontend configuration at runtime

I have a vue.js SPA which I want to deploy on different servers without recompiling the frontend for each deploy. The SPA connects to a backend, with a url yet unknown to the spa. Is there a way I can dynamically tell the frontend at runtime where the backend is?
Many articles and forum threads suggest to just use different config files for different environments and build them in at build time, but that is not an option for me because I simply don't know where the frontend/backend will be deployed when building it.
EDIT: The project is an open source project, so I can't really make an assumption about how people will deploy it. I've always kind of "assumed" it would be deployed on a seperate sub domain, with the frontend being reachable at / and the backend with a proxy at /api because that's how I set up my server.
However, I've seen people deploying the api at a totally different sub domain (sometimes even with different ports) than the frontend or on a sub path or even a mixture between the two.
Things I've considered so far:
Putting the config in a conf.js which would then expose the backend url via window.config.backendUrl or similar and load that file in my index.html from a <script> tag
Slightly similar to 1.: Put the config in a config.json and making a fetch request to it once the application loaded, then exposing the result of it in window.config.backendUrl
Inserting a <script>window.config.backendUrl = 'http://api.example.com'</script> in my index.html.
Serving the frontend with a custom made web server (based on express or similar) which parses either env or a different config file and then creates the <script> tag from 3. dynamically
Always "assuming" where the backend will be with some kind of list to work up, like "First look at /api then at ./api then at api.current-host.com etc."
Bundling the frontend with the backend - that way I would always "know" where the backend relative to the frontend is.
Yet all of theses options seem to me a bit hacky, I think there has to be a better way.
My favourite is the third option because it is the best trade off between configurability and performance IMHO.
If I was in the same situation I would have considered the following 2 approaches:
Deploying a JSON file with the same name but with different contents - so the frontend can always fetch its configuration by making AJAX call to /config.json but this file will depend on where you deploy and will be generated during the deployment step
Using a single API endpoint with a fixed/constant URL (completely separate from your backends) - so that frontend always calls this API endpoint to get its configuration at startup and the actual URL of the corresponding backend for its further operation.
Basically (2) is just the dynamic version of the static configuration in (1).

How to fetch data only once in a Next.js app and make it accesible to all the app, both in server and client

I'm working on a Next.js app that needs to fetch a config file from a remote server before initializing. I want to request the config file just once per call to the server before rendering the app server side. After that, I would like to be able to get the same config in the client without having to make a second request to the remote server from the browser.
I have tried to achieve this by using getInitialProps function either in _app or _document files and then use the React's Context API to make the configuration visible to every component but unless I'm wrong, this will run the code that requests the configuration both in server (on the first call from the browser) and client (on every page navigation).
I have also tried to create a server.js file, request the configuration from there and store in a variable within a ES6 module. However, I couldn't make this approach work because apparently the Next.js React app can't access the same modules than the server.js because they are actually two different apps. Again, I could be wrong.
Basically I would like to know if Next.js offers any kind of "bootstrapping place" where I can perform app initialization tasks that generate data that can be sent to the React app Next.js will initiate.
You are correct in that anything in getInitialProps in _app.js or _document.js will be run on every server request. Once you get your config, you can pass it down to the components in pages as props. From there, I think you have two choices:
Now that the app is bootstrapped, run the rest of the app as a SPA client-side. This would prevent any future SSR from happening. Obviously, you lose the benefits of SSR and the initial page load is likely longer, but then it would be snappy afterwards.
After getting the config in _app.js, send it as a cookie (assuming it's not too big to be a cookie?). On future requests to the server, the cookie will be sent automatically and you would check the cookie first - if it doesn't exist, get the config. If it does exist, skip that more expensive bootstrapping because the app is bootstrapped.
So I think it really depends on whether you want a single page application bootstrapped on the server but then entirely client side after that (option 1) or server side rendering per page while minimizing expensive bootstrapping (option 2).
Nothing prevents you from sending multiple cookies from the server if that makes sense for your app and bootstrapping. And remember not to make it a HTTP-Only cookie because you'll want to read that cookie client side - after all, that's what you're looking for - the client side configuration generated on the server.
Despite we ended up leaving Next.js for this and other reasons that made us decide Next.js was not the best option for our use case, we kind of mitigated this problem as follows while be sticked to it, I hope it makes sense to anyone. Also, by now maybe Next.js provides a better way to do this so I would read the Next.js docs before using my approach. Final note: I don't have access to the code anymore since I change to a different company so maybe there are some points that won't be 100% as we made it.
There is goes:
We created a module that was responsible to request the config file and keep the results in a variable. At the moment of importing this module, we ensure that the variable is not already present in window.__NEXT_DATA__. If it is, we recover it, if it's not, we request it to the remote server (this will be helpful in the clint side rendering).
We created a server.js file as described by Next.js docs. In this file we make the call to get the config file and store it in memory.
In the body of the function passed to createServer we add the config file into the req object to make it accesible to the app in the getInitialProps functions server side.
We made sure that the getInitialProps using the config file returns it, so that it will be passed to the components as props and also serialized by Next.js and made available to the client in the __NEXT_DATA__ global Javascript variable.
Given that the config ended up in the __NEXT_DATA__ variable in the server, using the trick described in the step 1 makes the app not request the config for a second time.

Angular - how to test Internet upload speed without backend?

I want to upload file into folder from which my Angular app is served while running on localhost. I'm not able to find any solution without using backend.
For example I just want to upload an image file and that file should copy in specified folder of the project. This should be done only with Angular without using any Backend script or hitting any API endpoint.
Depending on your webhost, you can make your assets-folder accessible via FTP.
Making a FTP-call from javascript (angular is javascript) isn't that difficult. And there are plenty of example and questions about it on the internet (like this)
Why you wouldn't do that:
The credentials for your ftp-connection will be accessible in the compiled javascript-code. With a little bit of effort, everyone can find it.
Each gate you open through the webhosts firewall, is a extra vulnerability. Thats why everybody will recommend you to add an API endpoint for uploading files so that you keep holding the strings of what may be uploaded.
Edit:
As I read your question again and all the sub-answers, I (think) figured out that you are building an native-like app with no back-end, just an angular-single page front-end application. An I can understand why (you can run this on every platform in an application that supports javascript), but the problem you are encountering is only the first of a whole series.
If this is the case, I wouldn't call it uploadingas you would store it locally.
But the good news is that you have localstoragefor your use to store temporary data on the HDD of the client. It isn't a very large space but it is something...
The assets folder is one of the statically served folders of the Angular app. It is located on the server so you can't add files to it without hitting the server (HTTP server, API, or whatever else...).
Even when running your app on localhost, there's a web server under the hood, so it behaves exactly the same than a deployed application, and you can't add files to the assets folder via the Angular app.
I don't know what exactly you want to do with your uploaded files, but:
If you want to use them on client side only, and in one user session, then you can just store the file in a javascript variable and do what you want with it
If you want to share them across users, or across user sessions, then you need to store them on the server, and you can't bypass an API or some HTTP server configuration
Based on your clarification in one of your comments:
I'm trying to develop a small speed test application in which user can upload any file from his system to check upload and download speed.
The only way to avoid having you own backend is to use 3rd party API.
There are some dedicated speed test websites, which also provide API access. E.g.:
https://myspeed.today
http://www.speedtest.net
https://speedof.me/api.html
Some more: https://duckduckgo.com/?q=free+speedtest+api
Note, that many of these APIs are paid services.
Also, I've been able to find this library https://github.com/ddsol/speedtest.net, which might indicate that speedtest.net has some kind of free API tier. But this is up to you to investigate.
This question might also be of help, as it shows using speedtest.net in React Native: Using speedtest.net api with React Native
You can use a third party library such ng-speed-test. For instance here is an Angular library which has an image hosted on a third party server (ie GitHub) to test internet speed.

Categories