Self-hosted phaser 3 library: this is undefined? - javascript

I am absolutely new with phaser 3.
I have installed the library with npm. Then I naively fetch the bundled file from node_modules.
<body>
<script src="./node_modules/phaser/dist/phaser-arcade-physics.js"></script>
<script src="./js/start.js"></script>
</body>
When I load index.html in the browser as file, it works fine. But now I have created a little v-host in my Apache and let it serve the files. This works too, but phaser yells at me:
Uncaught TypeError: this.texture is undefined
setFrame http://game.localhost/personwar/node_modules/phaser/dist/phaser-arcade-physics.js:138726
setTexture http://game.localhost/personwar/node_modules/phaser/dist/phaser-arcade-physics.js:138699
Image http://game.localhost/personwar/node_modules/phaser/dist/phaser-arcade-physics.js:29328
<anonymous> http://game.localhost/personwar/node_modules/phaser/dist/phaser-arcade-physics.js:168386
create http://game.localhost/personwar/js/start.js:34
[...]
DOMContentLoaded http://game.localhost/personwar/node_modules/phaser/dist/phaser-arcade-physics.js:86811
Game http://game.localhost/personwar/node_modules/phaser/dist/phaser-arcade-physics.js:154945
<anonymous> http://game.localhost/personwar/js/start.js:17
I have stolen start.js from the beginner tutorial and here it all starts:
function create () {
console.log('this', this);
this.add.image(0, 0, 'bg').setOrigin(0, 0);
...
}
I don't understand, why this.texture changes when the library is self hosted, compared to being delivered by file://. What do I need to change here?
It might be a timing problem, maybe I need to setup smth else before calling this.add.image in the create callback.
I will go on with investigating, what texture actually is.
Issue were Header, which was set by server: Content-Security-Policy
The rule "default-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'none'"
blocked this call
blob:http://game.localhost/b6ac3ad7-e25b-4b82-8d07-8f4ce6c331c3
which was the call for one of our images. This is weird and I don't get it. But the point is: no image loaded -> no texture.

Well I don't know which file your are linking. the main phaser file is called phaser.js or phaser.min.js. I think this is the root of your problem.
The easy solution is to download the phaser javascript file into your webfolder, or link it from a cdn. (https://phaser.io/download/stable)
If you (want to) use npm you will need a bundler like webpack, parcel, ... there are serval templates out there. (like this one https://github.com/photonstorm/phaser3-project-template).
btw.: I'm no expert, but I would in general never have the node_modules directory in a webserver accessible folder (if not really needed, and if you are running apache, it is probably not needed), since this could create be a potential security risk.

Related

Why JS scripts of type "module" need a web server to work? [duplicate]

Alright, I have looked on this site and have found several different answers, none of which have worked for me.
Basically had a js file that had many functions in it along with the main code for the app. I wanted to move all my functions to another js file so that I could clean up my code a little. I am fairly new to js but I know in python it was as simple as saying "import (module) as (nickname) from (path)"
anyways let's say I have a function named show message in my functions.js module.
export function show_message(){
alert("Hello");
}
and then I at the top of my main.js file I did
import { show_message } from './functions.js'
//I have also tried to import like this:
import * as func from './functions.js'
//And then I call it
show_message();
//I have also tried
func.show_message();
I know this is something simple, but as I said everywhere I have looked I have seen different answers, none of which work for me. I am using Firefox btw. I am also getting an error in the console saying that my import declarations need to be at the top of my module, I fixed that by specifying the type in my HTML link (script src="/static/main.js" type="module")
The error went away but is now saying "same origin policy disallows reading the remote resource at the file (path) (reason: cors request not HTTP)."
And the other error says "module source URI is not allowed in this document".
which makes me think maybe my syntax for importing is right and the error is in my HTML code?
Any help is appreciated.
0. The short answer
You need to install and run a local web server. - For a suggestion on how,
read on.
1. The basics
I tried a simple HTML file – index.html – as follows:
<!-- index.html - minimal HTML to keep it simple -->
<html>
<head>
<meta charset="UTF-8">
<link rel="shortcut icon" href="#">
</head>
<body>
<h1>Hello world!</h1>
<p>Experimenting with JavaScript modules.</p>
<script type="module" src="js/functions.js"></script>
</body>
</html>
In the subfolder js I put the JavaScript file functions.js:
// js/functions.js
alert('Hello');
When double-clicking index.html, my default web browser – Firefox 89.0
(64-bit) – shows the following, after pressing F12.
Notice how the JavaScript code is not running:
The error message:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at file:///C:/stackexchange/reproduce/jsModule/moduleNW/basics/js/functions.js. (Reason: CORS request not http).
A cheating "solution" is to (temporarily) remove type="module" from the HTML
code.
The alert then displays without errors.
But I want to run the JavaScript code as a module, so I put back
type="module" in the HTML.
2. Install and run a local web server
To run it as a module, it needs to run on a web server.
Thus, if you want to run the code on your own computer, you will need to
(install and) start a local web server.
One currently popular alternative is live-server.
Here is what worked for me.
Open a terminal. (On Windows: cmd.exe.)
Type npm and hit Enter to see if Node.js is installed.
If you get command not found, download at https://nodejs.org/en/download/
and install. 1
(On Ubuntu, you can try sudo apt install -y nodejs.)
Install live-server: npm install live-server -g.
Change directory to where your page lives: cd <path-to-index.html>.
Start the server: live-server .
(Should open localhost:8080 in your default browser and show the alert.
See below.)
Note 1.
I am on Windows 10, but the above instructions should work fine on Linux and
macOS too.
Note 2.
Here I used Firefox 89.0, but I have tried Google Chrome 91.0 as well.
The only notable difference is the CORS error message, which in Chrome reads:
Access to script at 'file:///C:/stackexchange/reproduce/jsModule/basics/js/functions.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.
3. Exporting and importing
Next I create a new folder demo2 containing the following demo2.html:
<!-- demo2.html - even shorter HTML for simplicity -->
<body>
<h1>Hello world!</h1>
<p>Javascript modules.</p>
<script type="module" src="js/main.js"></script>
</body>
I also create the following three JavaScript files in the subfolder js:
// js/module1.js
export function hi () { console.log('Hi from module 1.'); }
and
// js/module2.js
export function howdy () { console.log('Howdy from module 2!'); }
and
// js/main.js
import { hi } from './module1.js';
import { howdy } from './module2.js';
hi();
howdy();
Now I run live-server from the terminal in the folder where demo2.html
resides.
This time I start by typing
live-server --port=1234 --entry-file=demo2.html
and hitting Enter. Screenshot:
References:
Installing Node.js live-server
The live-server docs
Live-server can't find the file specified
Export and Import
1 On Windows 10, I once needed to
repair the installation.
On the script tag you are using to load the js in the browser you need to add the attribute
type="module"
It will look like the following:
<script type="module">
import {addTextToBody} from './utils.mjs';
addTextToBody('Modules are pretty cool.');
</script>
utils.mjs:
export function addTextToBody(text) {
const div = document.createElement('div');
div.textContent = text;
document.body.appendChild(div);
}
This is if you are not using a bundler like webpack and working directly in the browser.
Source of code: https://jakearchibald.com/2017/es-modules-in-browsers/
You might want to use broswerify instead. It allows you to write NodeJS-style modules and then compiles them into a single browser-friendly JavaScript file, allowing you to get all the performance benefits of loading only a single file. It also means you can easily use the same code both server side and client side.
If you want to stick with separate files, it looks like you are well on your way. Unlike regular JavaScript files, modules are subject to Cross-Origin Resource Sharing (CORS) restrictions. They have to be loaded from the same origin, and cannot be loaded from the local filesystem. If you are loading them from the local file system, move them to a server. If you are already hosting them on a server, add the Access-Control-Allow-Origin: * header to the response that serves the module file.
Lots more gotchas and solutions here and here.
function show_message(){
alert("Hello");
}
export { show_message };
and
import { show_message } from './functions'
i think this should do the trick. this is a named export/import technique. you can under this name find more information if you desire it.
Shortcut for Accepted answer
In case you are using Visual Studio Code just install the Live Preview extension by Microsoft.
In any HTML file click the Show preview icon. It will automatically run a local server and show up in the code editor. After every edit you make it refreshes. You can also show it in your default browser.
No need for command line anymore!
JavaScript has had modules for a long time. However, they were implemented via libraries, not built into the language i.e. you can't import or export part of those modules into your js files (whole library needs to be loaded). ES6 is the first time that JavaScript has built-in modules.
Please refer Here for more info about ES modules.
But things have changed and ES modules are now available in browsers! They're in…
Safari 10.1+, Chrome 61+, Firefox 60+, Edge 16+, etc,.
Now, you need to create your JS file using a new extension .mjs, like,
// utils.mjs
export function addTextToBody(text) {
const div = document.createElement('div');
div.textContent = text;
document.body.appendChild(div);
}
and then, you can import that file into your html page like,
<script type="module">
import {addTextToBody} from './utils.mjs';
addTextToBody('Modules are pretty cool.');
</script>
Please refer Here for more info about using ES module in browsers.
Consider going through this url some extension might be causing an issue with the loading of modules:
This blog might be an answer to what you're expecting.
You should first check if browser accepts type="module" and use fallback if it doesn't like this:
<script type="module" src="module.mjs"></script>
<script nomodule src="fallback.js"></script>
This might be the main reason for the CORS error as written here:
Unlike regular scripts, module scripts (and their imports) are fetched
with CORS. This means cross-origin module scripts must return valid
CORS headers such as Access-Control-Allow-Origin: *
So you need to add CORS header to the module file
Consider this blog for CORS issue. You should add CORS header ie. Access-Control-Allow-Origin: * to the server config most probably.
Using JS modules in the browser
On the web, you can tell browsers to treat a element as a module by setting the type attribute to module.
<script type="module" src="main.mjs"></script>
<script nomodule src="fallback.js"></script>
More on
https://developers.google.com/web/fundamentals/primers/modules
If you're using webpack and babel and want to import the code into your bundle, I guess it should be one of the following:
export default function show_message(){
alert("Hello");
}
and then in your code:
import show_message from 'path/to/show_message.js'
// or
import { default as someOtherName } from 'path/to/show_message.js'
Or if you'd like to export several functions:
const show_message = function(){
alert("Hello");
}
export { show_message };
and then in your code:
import { show_message } from 'path/to/show_message.js'
// or
import { show_message as someOtherName } from 'path/to/show_message.js'
Hope that helps.
I know this old thread but I just fixed this problem myself by using Parcel to launch my website Parcel index.html, in my situation I was using Live server and it didn't work until I switched to parcel .
Instead of using .js, try using .mjs.
Let's say your module file is /modules/App.js, just change it to /modules/App.mjs.
And ofcourse, make sure you have added type="module" in script tag, like this - <script type="module" src="./index.js" defer></script>
My folder structure -
index.html
index.js
modules/App.mjs
This worked for me!

Can I monkeypatch a function in another webpack bundle at runtime?

I am writing a plugin for a third-party web application, whose code I can see but can't modify. I'm running it in Chrome. The main webapp and the plugin are both (separate) webpack bundles. At runtime when the page loads, the webapp fetches the plugin bundles from the same server, and initialises them.
My objective is to make my plugin patch/wrap a function in the third-party application, in the module webapp/utils/target.tsx, such that calls to that function from within the webapp have my modified behaviour. Something like this:
// somehow import the `target` module (this is the problem, see below...)
oldFunc = target.targetFunc;
target.targetFunc = function targetFunc(args) {
// do extra stuff here
return oldFunc(args);
}
But I don't know how to import the target module or whether this is possible. Specifically:
I can't just import target, because application/webapp is not a dependency of my plugin
Plugins are meant to access limited entrypoints that get attached to window by the webapp, so they have no direct dependency on the webapp
I don't think I can add application/webapp as a dependency because
it's not a published package (perhaps I can add it as a github link?) and
I don't want webpack to include it in the bundle, so I think I'd have to specify it as an external dependency, but I don't know how to do that...
I can't modify application to do any extra things in its webpack (like exposing target in a different way)
I thought perhaps I could import it dynamically at runtime:
import(/*webpackIgnore: true*/ '/application/webapp/utils/target').then({
...
})
This gives me the error Expected a JavaScript module script but the server responded with a MIME type of "text/html".
If it helps, when the page is fully loaded and the app has loaded my plugin, in Chrome developer tools under Sources -> Page, I see a tree structure like this:
- localhost:port
- .
- com.mydomain.myplugin
- <modules for my plugin>
- application
- webapp
- .
- <other modules>
- utils
- target.tsx
- <other files>
- webpack
Meanwhile the original html page source seems to load the webapp via this tag in the header:
<script defer="defer" src="/static/main.c4e2eaf1d8c47b01fa6c.js"></script>
The Chrome devtools say "Source map detected".
Is it even possible to do what I'm trying to do?
From what i understand, you can import the module object, edit with the Object. library and return the edited module. If you don't understand nothing but knows the core, these references should helpful to solve this.
https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Statements/import
https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Statements/export
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties

How can I use "import something from package" in script starting from electron-quick-start

I am new to electron. So far I can run electron-quick-start but I get stuck when try using
import {somthing} from "package"
Here is what I did from electron-quick-start.
Edit ./renderer.js as
import { TitleBar } from "electron-react-titlebar";
import "electron-react-titlebar/assets/style.css";
ReactDOM.render(<TitleBar />, document.querySelector("title-bar"));
index.html:
...
<head>
<meta http-equiv="Content-Security-Policy" content="script-src https://www.google-analytics.com 'self' file://* 'unsafe-inline' 'unsafe-eval'">
</head>
<body>
<title-bar></title-bar>
...
main.js (seems I need to change loadFile to loadURL)
...
mainWindow.loadURL(`File://${__dirname}/index.html`);
// Open the DevTools.
mainWindow.webContents.openDevTools();
...
After this I get an error
renderer.js:7 Uncaught SyntaxError: Cannot use import statement outside a module
I did some research by setting
"type": "module"
in package.json, and this gets errors about module/commonjs.
I then find other projects when importing modules they write requires in
<script>require("./renderer")</script>
but I got
index.html:17 Uncaught ReferenceError: require is not defined
Then I tried babel / browserify and many other things only to find my simple test project messed up.
I googled for ES6-react-electron sample minimal projects but they are too out-dated that I find many deprecated packages. These projects still get errors
So, can someone make a modernized minimal example which starts from electron-quick-start and
1. use "import" in script
2. (optional) somehow use "require" to import other modules in index.html
I believe the example should be quite simple but I just missed some points.
Best if somebody can just post a GitHub repo that everybody else can starts happy coding from just pulling it! Thanks!

How to include minified library version in RequireJS optimization

My situation is as follows:
My project based on RequireJS.
I am using RequireJS Optimizer for to create a single JS file.
Some of the module use a certain third party library as a dependency.
The third party is NOT included in the optimized file (libName: empty
in the build config).
RequireJS is configured through var require = {} object which appears
on EACH PAGE, right above the RequireJS. The object defines a path to
the unminifed version of the library, among other things.
What i'd like to achieve:
Use the same config file in both development and production (the require={} object is included with tag on each page). During development I'd like modules to use the UNMINIFIED version of the third party.However, after optimization occurs, i would like all the modules to use the minified version of that third party.
I did think of a solution in theory, but it seems a bit messy and Im hopeful cleaner solution exists:
To have the runtime config point to unminified version
var require = {
paths:{
'thirdParty':'lib/thirdParty'
}
}
Create a module which execute (lets call it "PathRewrite" Module):
requirejs.config({
paths:{
'thirdParty':'lib/thirdParty.min'
}
})
In runtime configuration, define path to "PathRewrite" as empty
var require = {
paths:{
'thirdParty':'lib/thirdParty',
'PathRewrite':'empty'
}
}
In the build configuration file define a real Path to "PathRewrite" in order for it to be included in the "main" file (concatenated file after build).
Include "PathRewrite" as a dependency of a module which is executed first.
What I hope that will happen is that during dev, when optimized file is not used, PathRewrite is will not be used, hence the path to unminified third party in the runtime config will be used.
When the project is optimized, PathRewrite will be included and executed. According to RequireJS documentation, it is possible to run RequireJS configuration twice and the configuration will be appended/overwritten. PathRewrite execution will overwrite the path to "thirdParty" to minified, which will thus be used by all the modules.
Hopefully i've provided enough information. I'd be glad hear of other ways to get this done. Thanks in advance.
This topic appears to have been explored a bit in this answer:
Loading min.js files Generated by TypeScript with Require
Don't let the title discourage you. Typescript is not the core issue of the question being answered there. Unfortunately, the discussion reveals that the RequireJS optimizer may be the only way to get decent minification to work, as it seems incapable of selecting alternate paths properly.
Why don't you want to use inbuilt RequireJs optimizer? You may just include this option
optimize : "uglify2"
and all your and third-party code will be minified after concatenation. In this case you don't need to use minified versions of third-party libraries.

common.js is not fount in Canvas lms production environment

When i am trying to run my canvas lms on localhost then this type of error occur "common.js not fount" but file is still there. I don't know how to solve it
in your app/assets/application.js
= require 'common'
make sure common.js file is under app/assets/ or vendor/assets/

Categories