COMMUNITY

Nodejs - to a web app

Hello everyone. I have a nodejs web app with manifest.json for android. How can i hear from you to have working with haxe latest version?

Good rest of day easter.

Can i hear you soon…

Hey @vic3t3chn0, I think we need a few more details to help – what troubles are the having when you try to use the latest haxe version?

To make a new node.js app with haxe, after you’ve installed haxe, then you can install the haxe node.js externs with haxelib install hxnodejs which let you use the node.js API.

Compile your code with

haxe --library hxnodejs --js index.js --dce full YourMainClass

Haxe just generates javascript (much like TypeScript) and will work just the same if you use a manifest.json for a portable web app so no need to worry about that

Are you looking for a tutorial to build a haxe web app from scratch?

Hello @haxiomic i have a nodejs website, and i am trying to port it. Instance i have my manifest and package.json also an jwt token api. my idea is to port it. With this great community. I want to port my nodejs and php to haxe. Learn first before helping community.

Thank you.

Gotcha, ok – does it use any node.js libraries like express? (Could you paste your package.json here?)

I’ll try to make a little tutorial for this

Getting Setup

  • First download and install the latest haxe (if you haven’t already)
  • Install Visual Studio Code and then install the haxe plugin
  • Next, make a new directory to hold the project and create the following:
    • build.hxml (empty – this will hold our haxe build options)
    • src/Main.hx (empty – this will hold our haxe source code)
    • copy your package.json file
    • make a folder called .haxelib/ this is like node_modules but for haxe
  • Then we’re going to try haxe hello-world to check everything works:

In src/Main.hx add the folloing:

function main() {
    trace('hello world!');
}

In build.hxml add

# tell haxe to look in the src directory for source code
--class-path src
# set the entry point to our Main file
--main Main
# set dead-code-elimination to full for cleaner js code
--dce full
# generate javascript output
--js bin/index.js

Now we’re ready to test. Open this directory in vscode with the haxe plugin installed. Compile the program using TerminalRun Build Task. Alternatively, on the command-line run haxe build.hxml.

This will create a new file: bin/index.js that will contain your generated javascript. Run it with
node bin/index.js. It should return

src/Main.hx:2: hello world!

Porting Node.js Server Code

To use the node.js APIs we first need the node.js haxe externs. From the command line run:

haxelib install hxnodejs

This will install the files into that .haxelib/ folder we created earlier

Next to tell haxe it can use this library when compiling, add --library hxnodejs to build.hxml. You can add on any line but I recommend adding it at the top of the file

Now we can try to use the node.js API to make a minimal web server. I am translating the node.js getting-started example.

In JavaScript this looks like so:

const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

We can almost copy and paste this into Main.hx, but we need to make some changes:

  • In haxe we only use import, so const http = require('http'); becomes import js.node.Http;
  • In haxe const is final
  • Arrow functions use -> rather than =>
  • for console.log we can use trace
  • Haxe doesn’t have backtick strings ` (it doesn’t need them; regular strings have always allowed for multi-lines. Replace those with single-quotes which enables string interpolation
  • Finally, haxe requires an entry point function called main, whereas javascript doesn’t. So we want to put our startup code in there.

Back in our src/Main.hx, we can replace it with the following:

import js.node.Http;

final hostname = '127.0.0.1';
final port = 3000;

final server = Http.createServer((req, res) -> {
	res.statusCode = 200;
	res.setHeader('Content-Type', 'text/plain');
	res.end('Hello World');
});

function main() {
	server.listen(port, hostname, () -> {
		trace('Server running at http://${hostname}:${port}/');
	});
}

Compile again (TerminalRun Build Task or run haxe build.hxml)

Now we can test our server:

node bin/index.js
src/Main.hx:32: Server running at http://127.0.0.1:3000/

Opening http://127.0.0.1:3000/ should show Hello World

Here is a working example: https://github.com/haxiomic/dts2hx/files/6255393/haxe-server-example.zip

When porting, you can use autocomplete to help you figure out where the node.js APIs are – just start typing the name of the API you want to use (e.g. ‘http’) and it will suggest js.node.Http (among others)

Using a node.js library: express

If you use a framework like express, you’ll want to get externs for those too. This is the same process that typescript uses, but we need to convert the typescript externs to haxe with a tool called dts2hx. To install express and the express externs, you can run the following commands:

npm install express 
npm install @types/express
npm install dts2hx
npx dts2hx express

This will install express externs to .haxelib/. Again add --library express to the top of build.hxml so we can use the externs.

Now we’re ready to write a webserver using express, here’s a basic example, you can read more about how this example was ported in this thread How does one use Routes in Express?

final app = Express.call();
final port = 3000;

final router = express.Router.call_();

function main() {
	app.get('/', (req, res, next) -> res.send('Hello World! <a href="/birds">/birds</a>'));
	app.listen(port, () -> trace('Example app listening at http://localhost:${port}'));

	app.get('/route', (req, res, next) -> res.send('Example route'));

	// middleware that is specific to this router
	router.use(function timeLog (req, res, next) {
		trace('Time: ' + Date.now());
		(next: () -> Void)();
		return null;
	});

	// define the home page route
	router.get('/', (req, res, next) -> {
		res.send('Birds home page');
	});

	// define the about route
	router.get('/about', (req, res, next) -> {
		res.send('About birds');
	});

	app.use('/birds', router.call);
}

For other libs you can use a similar process so long as typescript externs are available, however if they’re not available and you don’t want to make them yourself, you can call javascript code directly.

Calling js code without externs

For example, say we want to call console.log. There are externs defined for this (Node.console.log('hello');) but say there weren’t. We can use the untyped keyword to disable typing:

untyped {
  console.log('hello');
  console.error('example');
}

To use require() directly, we can do

final http = js.Lib.require('http');

(or use untyped like before)

Or to inject raw javascript, you can write

js.Syntax.code('console.log("hello");');

Life is a lot nicer if you have or write externs but these options can save you some time while porting

Good luck! Let me know how you get on!

10 Likes

Hi.

I am facing an error called type not found. On each examples, type not found Main.

I got it. My name filename was hxml instead of hx. By the way thanks a lot for the help. Now i keep my work.

my package.json is :slight_smile:
{
“version”: “1.0.0”,
“name”: “web”,
“app-name”: “web”,
“package-name”: “webview”,
“project-type”: “webview”,
“icon”: “./assets/icon/icon.png”,
“dist-path”: “./dist”,
“permission”: [
“android.permission.INTERNET”
],
“description”: “”,
“main”: “main.js”,
“scripts”: {
“start:dev”: “node .”,
“build”: “androidjs build”
},
“author”: “”,
“license”: “ISC”,
“dependencies”: {
“androidjs”: “^2.0.2”
},
“project-name”: “web”,
“theme”: {
“fullScreen”: true
}
}

Thanks a lot.