Unable to attach any file to an HTML - javascript

Based on the tutorials I tried to set up a basic server in NodeJS via HapiJS.
The initialization looks like this:
//globals
mainAddr = "MoriMachine";
mainPort = 3000;
require('./backend/app.js')
This is the content of app.js:
const Hapi = require('hapi');
const server = new Hapi.Server();
server.connection({host: mainAddr, port: mainPort });
server.register(require('inert'), (err) => {
if (err) { throw err; }
server.route({
method: 'GET',
path: '/',
handler: function (request, reply) {
reply.file('./public/index/index.html');
}
});
});
server.start((err) => {
if (err) { throw err; }
console.log(`Server running at: ${server.info.uri}`);
});
While index.html is similarly small:
<!DOCTYPE html>
<html>
<head>
<script src="index.js"></script>
</head>
<body>
<h1>HELLO WORLD!! -3-</h1>
<img src="test.jpg"></img>
</body>
</html>
In the project itself, there are init.js and three folders:
node_modules: for obvious reasons
backend: contains app.js
public: contains folder 'index' that contains the HTML, and the JS and the picture I tried to attach.
The problem is that whatever path I try, when I run the server, neither the JS or the picture are found.
What is the reason? An I missing to add some additional functionality?

The reason is that you only got one route that serves one specific file. When you access the route '/' your browser tries to access '/index.js' and '/test.jpg' and you are not responding to these routes.
One way to do is is to serve everything in your public directory, like this:
server.route({
method: 'GET',
path: '/{param*}',
handler: {
directory: {
path: 'public'
}
}
});
Now your index.js is accessible trough /index/index.js and your image is accessible trough /index/test.jpg
so make these changes to your html
<!DOCTYPE html>
<html>
<head>
<script src="/index/index.js"></script>
</head>
<body>
<h1>HELLO WORLD!! -3-</h1>
<img src="/index/test.jpg"></img>
</body>
</html>
Note that in this way your index.html is also accessible trough /index/index.html
for more detaisl look at: http://hapijs.com/tutorials/serving-files?lang=en_US#directory-handler

Related

CDN caching for React.JS SSR

I have the below code to do my server-side rending:
// Load in our HTML file from our build
fs.readFile(
path.resolve(__dirname, '../build/index.html'),
'utf8',
(err, htmlData) => {
// If there's an error... serve up something nasty
...
// Pass all this nonsense into our HTML formatting function above
const html = injectHTML(htmlData, {
html: helmet.htmlAttributes.toString(),
title: helmet.title.toString(),
meta: helmet.meta.toString(),
headScript: helmet.script.toString(),
link: helmet.link.toString(),
body: routeMarkup,
scripts: extraChunks,
state: JSON.stringify(store.getState()).replace(/</g, '\\u003c')
});
// We have all the final HTML, let's send it to the user already!
res.send(html);
It is working fine. However, all my static assets are loaded from ../build. I want to connect a CDN, such as S3 to cache assets.
To do this, I need to prepend the CDN url to links to static assets so <script src="/static/js/main.7e3b844f.chunk.js"></script> becomes <script src="https://cdn.mydomain.com/static/js/main.7e3b844f.chunk.js"></script>
The urls of interest are inside htmlData. I could use regular expressions to replace /static/css with ${prefix}/static/css and the same for /static/js.
Are there better alternatives than running a regex? Suggestoins?
I ended-up doing the below before injecting HTML with body, meta etc:
const prefix =
process.env.REACT_APP_STAGE === 'production'
? 'https://prod-cdn.mydomain.com'
: '';
const processedHtmlData = htmlData.replace(
/(\/static)/g,
`${prefix}$1`
);
const html = injectHTML(processedHtmlData, {
html: helmet.htmlAttributes.toString(),
title: helmet.title.toString(),
meta: helmet.meta.toString(),
headScript: helmet.script.toString(),
link: helmet.link.toString(),
body: routeMarkup,
scripts: extraChunks,
state: JSON.stringify(store.getState()).replace(/</g, '\\u003c')
});
It works.

How to load local JavaScript file with JSDOM?

I am unable to use JSDOM (version 13.0.0) to load scripts from the local filesystem with a relative path.
I have taken a look at the following questions but they do not answer my question:
jsdom can't load local html and javascript (I have already followed the runScripts and resources suggestion there).
File foo.js:
var jsdom = require('jsdom')
var html = `<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script src="bar.js"></script>
</head>
<body>
<div>Test</div>
</body>
</html>`
global.window = new jsdom.JSDOM(html, { runScripts: "dangerously", resources: "usable" }).window
console.log('foo')
File bar.js:
console.log('bar')
Here is the error I get:
$ node foo.js
foo
Error: Could not load script: "bar.js"
at onErrorWrapped (/Users/lone/so/node_modules/jsdom/lib/jsdom/browser/resources/per-document-resource-loader.js:41:19)
at Object.check (/Users/lone/so/node_modules/jsdom/lib/jsdom/browser/resources/resource-queue.js:72:23)
at request.then.catch.err (/Users/lone/so/node_modules/jsdom/lib/jsdom/browser/resources/resource-queue.js:124:14)
at process._tickCallback (internal/process/next_tick.js:68:7)
at Function.Module.runMain (internal/modules/cjs/loader.js:746:11)
at startup (internal/bootstrap/node.js:240:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:564:3) Error: Tried to fetch invalid URL bar.js
at ResourceLoader.fetch (/Users/lone/so/node_modules/jsdom/lib/jsdom/browser/resources/resource-loader.js:84:29)
at PerDocumentResourceLoader.fetch (/Users/lone/so/node_modules/jsdom/lib/jsdom/browser/resources/per-document-resource-loader.js:16:42)
at HTMLScriptElementImpl._fetchExternalScript (/Users/lone/so/node_modules/jsdom/lib/jsdom/living/nodes/HTMLScriptElement-impl.js:92:30)
at HTMLScriptElementImpl._eval (/Users/lone/so/node_modules/jsdom/lib/jsdom/living/nodes/HTMLScriptElement-impl.js:161:12)
at HTMLScriptElementImpl._poppedOffStackOfOpenElements (/Users/lone/so/node_modules/jsdom/lib/jsdom/living/nodes/HTMLScriptElement-impl.js:126:10)
at OpenElementStack.pop (/Users/lone/so/node_modules/jsdom/lib/jsdom/browser/htmltodom.js:17:12)
at Object.endTagInText [as END_TAG_TOKEN] (/Users/lone/so/node_modules/parse5/lib/parser/index.js:2153:20)
at Parser._processToken (/Users/lone/so/node_modules/parse5/lib/parser/index.js:657:55)
at Parser._processInputToken (/Users/lone/so/node_modules/parse5/lib/parser/index.js:684:18)
at Parser._runParsingLoop (/Users/lone/so/node_modules/parse5/lib/parser/index.js:440:18)
How can I load a local JavaScript file while using JSDOM?
JSDOM doesn't know where to look for that file locally while executing. So running your example you can follow any of this two approaches.
1st Approach
You have to wait for the script file to load and execute.
Create a three files index.html,index.js and test.js into the same folder.
index.html
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
abc
<script src='index.js'></script>
</body>
</html>
index.js
document.body.textContent = 123;
test.js
'use strict';
const { JSDOM } = require('jsdom');
const options = {
resources: 'usable',
runScripts: 'dangerously',
};
JSDOM.fromFile('index.html', options).then((dom) => {
console.log(dom.window.document.body.textContent.trim());
setTimeout(() => {
console.log(dom.window.document.body.textContent.trim());
}, 5000);
});
// console output
// abc
// 123
2nd Approach
Set the external scripts base root folder in JSDOM env.
js/index.js
console.log('load from jsdom');
var loadFromJSDOM = 'load from jsdom';
test.js
'use strict';
const { JSDOM } = require('jsdom');
JSDOM.env({
html: "<html><body></body></html>",
documentRoot: __dirname + '/js',
scripts: [
'index.js'
]
}, function (err, window) {
console.log(window.loadFromJSDOM);
}
);
Read more from these references
https://github.com/jsdom/jsdom/issues/1867
jsdom.env: local jquery script doesn't work
Great answer from front_end_dev. It helped me a lot and I will share how my code works with this solution to be more clear. Maybe will help others.
import "#testing-library/jest-dom";
import { logDOM } from "#testing-library/dom";
import { JSDOM } from "jsdom";
import fs from "fs";
import path from "path";
const html = fs.readFileSync(path.resolve(__dirname, "../index.html"), "utf8");
let dom;
let container;
jest.dontMock("fs");
function waitForDom() {
return new Promise((resolve) => {
dom = new JSDOM(html, {
runScripts: "dangerously",
resources: "usable",
url: `file://${path.resolve(__dirname, "..")}/index.html`,
});
dom.window.document.addEventListener("DOMContentLoaded", () => {
resolve();
});
});
}
beforeAll(() => waitForDom());
beforeEach(() => {
container = dom.window.document.body;
});
afterEach(() => container = null)
it("should ", () => {
logDOM(container);
});

Keycloak login returns 404 using JavaScript adapter

I'm using Keycloak's bower package to create a very basic demo HTML/JS app. I have Keycloak running locally and keycloak.init() seems to work (no error triggered). However when I call keycloak.login() a 404 is returned. Might the login URL be wrongly created by the adapter?
The URL returned by keycloak.createLoginUrl() is
https://<keycloak url>/realms/<realm>/protocol/openid-connect/auth?client_id=account&redirect_uri=file%3A%2F%2F%2FUsers%2Fjgallaso%2FProjects%2Fdemos%2Fkeycloak-simple-web-client%2Findex.html&state=b167dc0b-3e5b-4c67-87f7-fd5289fb7b8f&nonce=1e2cb386-51db-496a-8943-efcf4ef5d5e1&response_mode=fragment&response_type=code&scope=openid
And this is my entire code:
<head>
<script src="bower_components/keycloak/dist/keycloak.min.js"></script>
</head>
<body>
<button id="login">Login</button>
</body>
<script>
var keycloak = Keycloak({
url: 'https://keycloak-keycloak.192.168.37.1.nip.io',
realm: 'demo',
clientId: 'account'
});
keycloak.init()
.success(authenticated => {
document.getElementById("login")
.addEventListener("click", () => { keycloak.login(); });
}).error(err => {
console.log("init, error: " + err);
});
</script>
</head>
Response is a plain:
ERROR 404: Not Found
You have 2 posibilities :
invoque login automatically in init method
login manually after call init without params
1)
<head>
<script src="bower_components/keycloak/dist/keycloak.min.js"></script>
</head>
<body>
<button id="login">Login</button>
</body>
<script>
var keycloak = Keycloak({
url: 'https://keycloak-keycloak.192.168.37.1.nip.io',
realm: 'demo',
clientId: 'account'
});
keycloak.init('login-required')
.success(function(authenticated) => {
}).error(err => {
console.log("init, error: " + err);
});
</script>
</head>
2)
keycloak.init().success(function(authenticated) {
if(authenticated == true){
alert('usuario logeado');
}else{
alert('usuario no logeado');
keycloak.login();
}
}).error(function() {
alert('failed to initialize');
});
I had trouble trying directly from the management.
file://c:/example.html
To do a better test you should leave your index.html on a local test server.
What I did was install the web server plugin for chrome and it worked for me.
I hope it'll help you.
regards

Specify directory name with HapiJS

I want to include my local CSS/JavaScript file in res.response () of hapiJS. I am not able to load my local file. How can I load my local file in the response of Hapi? How to specify directory name?
module.exports = function (req, res) {
Router.run(routes, req.url.path , function (Handler) {
var content = React.renderToString(React.createElement(Handler, { state: '' }));
var head = <link href="/css/app.caz.css" rel="stylesheet"/></script> <script src="js/app.caz.js"></script>;
var page = ` <!DOCTYPE html> <html> ${head} <body> </body> </html>`;
res.response(page);
});
};

Why I get "Uncaught ReferenceError: require is not defined"?

I want to use lolapi, so I went with my terminal to folder where project is and did npm install lolapi.
My code is a really simple cordova app:
HTML:
<body>
<div class="app">
<h1> Lol App</h1>
</div>
<script type="text/javascript" src="js/index.js"></script>
<script type="text/javascript" src="js/lolJ.js"></script>
</body>
JavaScript (lolJ.js):
var options = {
useRedis: true,
hostname: '127.0.0.1',
port: 6379,
cacheTTL: 7200
};
var lolapi = require('lolapi')('***-***-***-***-***', 'euw', options);
lolapi.setRateLimit(10, 500);
var summonerName = 'Wickd';
lolapi.Summoner.getByName(summonerName, function (error, summoner) {
if (error) throw error;
/* summoner object
{ Wickd:
{
id: 71500,
name: 'Wickd',
profileIconId: 613,
summonerLevel: 30,
revisionDate: 1408199475000
}
} */
console.log(summoner);
console.log(summoner[summonerName]);
var summonerId = summoner[summonerName].id;
lolapi.Summoner.getRunes(summonerId, function (error, runes) {
if (error) throw error;
// do something with runes
})
});
I replaced Wickd with my lol username, but still nothing happens.
As you can see I'm really new to this, so please, any guide will be great
Thanks
The require syntax is what's referred to as CommonJS, the default way of how you load modules within Node.js environments.
In order to use the require syntax in a browser environment you'd need to use tools like Browserify which handles this for you by bundling your application together with your dependencies.

Categories

Resources