React dynamic image importing in development - node.js

I am building a React application which needs to display images dynamically which are stored, by the thousands, on a server-side file system. All of my attempts to successfully implement this have failed, including many which were taken from responses to similar questions.
Some details:
I used create-react-app to initialize my application. I am running in development mode (have not run npm-build). I'm using Express.js (Node.js) as a web-server, which I interact with through a proxy (only '/api' http requests use the proxy). My js code which attempts to 'require' the images is in the 'src' folder. The images are located in an 'images' folder in the default 'public' folder.
I thought I had found the solution when reading this page from create-react-app, as it states to use the public folder when 'You have thousands of images and need to dynamically reference their paths'. The page further instructs to use '%PUBLIC_URL%' or 'process.env.PUBLIC_URL' to access the 'public' folder. When using either of these I receive an 'Error: Cannot find module' message. Upon checking I notice that 'process.env.PUBLIC_URL' contains an empty string, and quickly notice that PUBLIC_URL is ignored in development mode.
I find this to be tremendously confusing, given that the 'Using the Public Folder' page is apparently describing the development phase of production, and yet it advises the use of something which is meaningless during development. Adding to my confusion, it appears as if the contents of that page resolved the issue for nearly all of those who have encountered a similar requirement in the past (example: 1, example: 2; both fail for me). Likewise, all attempts to to construct relative paths to the 'public' folder from the 'src' folder have yielded error messages. Failed code example:
let img = process.env.PUBLIC_URL + '/images/Team.jpg';
<img src={require(`${img}`)} alt="X" />
Error: Cannot find module '/images/Team.jpg'
I never imagined showing images in React would be so difficult. Any help is truly very much appreciated.

I think you are correct, you just don't need the require, return <img src={process.env.PUBLIC_URL + '/img/logo.png'} />; as you can see their docs
If you open in your browser http://localhost:PORT/images/Team.jpg that should open.
That's the reason process.env.PUBLIC_URL is empty in development, because they resolve everything inside this folder directly.

Related

How to host SPA files and embed too with axum and rust-embed

I'm having hard time understanding how to embed SPA (single page application) files with rust-embed and axum.
I have no trouble without rust-embed using a single line of code with axum (from here):
app.fallback(get_service(ServeDir::new("./app/static")).handle_error(error_handler))
It works because all files are correctly downloaded. But:
FIRST PROBLEM
What is missing for a properly SPA handling is the redirect on the index.html if for example the user reloads the page on a SPA nested route.
Example: I'm on the page: /home/customers which is not a file nor a dir but just a fake javascript route and if I reload the page axum gives me 404 (Not found).
SECOND PROBLEM
I need to embed those files in my final executable. In Golang this is "native" using embed: directive.
I saw that in Rust this is well done with rust-embed but I cannot complete my task for SPA.
The need is that every path typed by the user (and that is not an existent file such as .js or .css which obviously must be downloaded by the browser) leads to the "index.html" file in the root of my static dir.
If I use the example axum code I can see the route:
.route("/dist/*file", static_handler.into_service())
which has /dist/*file and I don't need that /dist because the index.html calls many files with custom paths, such as /_works, menu, images.
If I remove the dist part I get this error:
thread 'main' panicked at 'Invalid route: insertion failed due to conflict with previously registered route: /index.html'
Can you help me understand how to properly accomplish this task?
Thanks.
I had a similar issue, building with Vue and Axum/Rust.
Here's how I solved Problem one
Install the tower_http crate
use axum::routing::get_service to serve the build SPA.
//example implementation
...
//static file mounting
let assets_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("views");
let static_files_service = get_service(
ServeDir::new(assets_dir).append_index_html_on_directories(true),
)
.handle_error(|error: std::io::Error| async move {
(
StatusCode::INTERNAL_SERVER_ERROR,
format!("Unhandled internal error: {}", error),
)
});
...
Mount the static file rendering
//mount the app routes and middleware
let app = Router::new()
.fallback(static_files_service)
.nest("/api/v1/", routes::root::router())
.layer(cors)
.layer(TraceLayer::new_for_http())
.layer(Extension(database));
Check out the full source code here. Another thing is, Axum seems to have breaking changes in subsequent versions as I found out here, so you might need to check the doc/example that corresponds to the version of Axum you are using :)

How to make the Rust Game of Life WebAssembly work as a static website?

I have gone through the tutorial for the Rust Game of Life and have a working game in a web browser, but it only works from the demo web server that comes bundled with it. I can start the server with npm start and it runs the webpack-dev-server on port 8080. When I access the site through that port, it works fine. However, if I try to copy the site to a web server like Apache, it does not load correctly. The error I am currently getting from it is:
Error importing `index.js`: TypeError: Error resolving module specifier “wasm-game-of-life”. Relative module specifiers must start with “./”, “../” or “/”. bootstrap.js:5:23
<anonymous> http://www.north-winds.org/gol/bootstrap.js:5
From the tutorial, the root of the website is a folder called www/ in the repository and the generated wasm module from the Rust program is placed under pkg/. There is a symbolic link from www/node_modules/wasm-game-of-life that points up to ../../pkg/ and I've replaced that symlink with an actual copy of the top-level pkg/ folder so that the website is entirely contained inside the www/ folder and then placed that folder on my website at http://www.north-winds.org/gol/, however, accessing it returns the error above. What do I need to modify to make it work stand-alone?
As I understand it, this WebAssembly Game-of-Life is basically a stand-alone client-side app and should not require anything beyond a web server that can provide static files with the appropriate mime-types attached. I don't see anything special that should be required. I did see mention of WebSockets somewhere, but I don't know why that is required for this app. I compared this to the "Hello, World" WebAssembly example for C from https://webassembly.org/ and it ended up with a .wasm file generated from the C source code, and a single JavaScript and HTML supporting file to execute it. The files worked correctly when simply copied to static web server location. This is what I'd like for the Rust example.
Some relevant code from the Rust Game-of-Life is as follows. The top-level HTML file includes this among other lines:
<script src="./bootstrap.js"></script>
The bootstrap JavaScript file contains only this:
import("./index.js")
.catch(e => console.error("Error importing `index.js`:", e));
And the index.js file that it references has this among other glue logic for the Wasm:
import { Universe, Cell } from "wasm-game-of-life";
// Import the WebAssembly memory at the top of the file.
import { memory } from "wasm-game-of-life/wasm_game_of_life_bg";
What's missing to make this work standalone?
The www and pkg folders contain the source files you need, but you do not have a static site yet. The create-wasm-app template uses Webpack, so you need to build the final output by running npm run build in the www folder. This will create a subfolder named dist which contains the actual static files that can be placed on your web server.

Cloud Foundry - Folder structure and relative paths

This is somewhat related to an issue I'm having with CF on IBM Cloud here. My question after playing around with the folder structures is how exactly is CF building the app when it comes to relative paths?
For example, if i have the following folder structure
when I add <script type = 'text/javascript' src = '../index.js'></script> to the index.html file, I get GET https://simple-toolchain-20190320022356947.mybluemix.net/index.js net::ERR_ABORTED 404. This error does not happen when I move index.js into the public folder and change <script type = 'text/javascript' src = 'index.js'></script>.
The problem I have then is that when I try to require() any modules when the index.js file is in a sub-directory, it returns a Require is not defined error indicating that it is not getting the module from the node_modules cache which CF is suppose to build. Requiring any files in the same sub-directory also throws the same error. This does not seem to be a problem when the require() is used in the default app.js as the application loads without any errors.
I'm relatively new to the IBM Cloud Foundry tool but I'm following the same structure as when I pushed apps via Cloud9 IDE and didn't have any such issues there. I feel I might be missing something ridiculously simple like configuration of endpoint or package.json. However, I've been searching around for days and can't seem to find a solution.
Appreciate if you have any pointers. Thanks!
Due to my lack of understanding, I was trying to use require() on the client side hence the errors. Going to figure out how to use Browserify now. ;)

Loading a js file valid throughout project Node.js

So, currently I am working on a project in Reactjs that displays a customised modal.
The configuration of the modal is fetched through a configurationLoader.js file.
Since, it is developed in React, my components are divided across different files.
Currently, what I am doing is, loading the full configuration file and extracting the relevant information when required.
What I find redundant is, I have to require the configuration file at the start of every .js file.
Is there a way, where I export my module once, and its valid globally? .i.e. I don't have to require it again and again?
Globals are registered in the window object for the browser and in the global object in node. So you could do:
window.myConfiguration = require('configurationLoader')
or
global.myConfiguration = require('configurationLoader')
depending on where your code will run. Then you should be able to access myConfiguration anywhere in your code without needing to require it.

How to test an AngularJS/SocketStream/Node.js app using Karma

I am working on an AngularJS application that is delivered by a SocketStream/node.js server.
I have an AngularJS service that calls api functions on the SocketStream server and progress has been good so far.
But now the time has come to start writing the first tests and the first testing framework that came to mind is Karma/Jasmine, since this is the recommend AngularJS set up.
So far so good, but since my AngularJS modules are imported using 'require' (SocketStream's version, not require.js) and server api calls are part of the test, I need to configure Karma to load SocketStream (at least its client side).
I took a good look at 'https://github.com/yiwang/angular-phonecat-livescript-socketstream' but when I run this example I get run time errors, possibly because I have later versions of variuous dependencies installed.
I managed to get 'required' resolved by packing my SocketStream app by adding 'ss.client.packAssets()' to app.js and run 'SS_PACK=1 node app.js', but when I start karma it logs an error message saying:
'Chrome 23.0 (Linux) ERROR
Uncaught TypeError: undefined is not a function
at /the...path/client/static/assets/app/1368026081351.js:25'
'1368026081351.js' is the SocketStream packed assets file. If I don't load it the error message is something like 'require is undefined', so my best guess is that the error is happening somewhere inside the SocketStream require code. Also because I run karma in DEBUG mode and can see all the files being served.
I have been trying different approaches as to find out what is happening but to now avail. So my questions are:
Is anybody else successfully testing AngularJS/SocketStream using Karma?
Does anybody have any suggestions as to how I can fix, or at least debug this problem?
Are there any alternatives/better solutions?
Time to answer, sort of, my own question:
Sort of, because I came to the conclusion that Karma and node.js/SocketStream have a lot of overlap, so I decided to see if I can omit Karma altogether and deliver the Jasmine testing platform through SocketStream. It turns out that that is possible and here's how I did it:
I defined a new SocketStream route and client in my 'app.js' file:
ss.client.define( 'test', {
view: 'SpecRunner.html',
css: ['libs/test'],
code: ['libs', 'tests', 'app'],
tmpl: 'none'
});
ss.http.route( '/test', function(req, res) {
res.serveClient( 'test' );
});
I downloaded jasmine-standalone-1.3.1.zip and copied 'SpecRunner.html' to the 'client/views' folder. I then edited it to make it load AngularJS and all SocketStream client files, like all other views:
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular-resource.min.js"></script>
<SocketStream/>
I removed the 'script' tags that import the sample source files ( 'Player.js' and 'Song.js' ) and specs but let the last 'script' block in place unmodified.
I then created a new folder inside 'client/css/libs' called 'test' and copied 'jasmine.css' in there unmodified.
Then I copied 'jasmine.js' and 'jasmine-html.js' renamed to '01-jasmine.js' and '02-jasmine-html.js' but otherwise unmodified, into '/client/code/libs'.
Now Jasmine is in place and will be invoked by using the '/test' route. The slightly unsatisfactory bit is that I haven't found an elegant place to store my spec files. They only work so far if I place them inside the 'libs' folder. Anywhere else and they are served by SocketStream as modules and are not run.
But I can live with that for now. I can run Jasmine tests without having to configure a special Karma setup.

Resources