hapticx / happyx Goto Github PK
View Code? Open in Web Editor NEWMacro-oriented asynchronous web-framework written in Nim with ♥
Home Page: https://hapticx.github.io/happyx/
License: MIT License
Macro-oriented asynchronous web-framework written in Nim with ♥
Home Page: https://hapticx.github.io/happyx/
License: MIT License
Write copy of official nim lang site as Single page application for HappyX examples
This flag will generate static HTML files and one JavaScript file
Hi @Ethosa,
Would you like to participate to https://github.com/the-benchmarker/web-frameworks ?
Regards,
Simple syntax with SSG:
"/path/<arg>[m:MyModel]" -> get:
...
serve(...):
...
Simple syntax with SPA:
"/path/<arg>[m:MyModel]" -> page:
...
appRoutes(...):
...
Old syntax:
buildHtml(`div`)
New syntax:
buildHtml(`div`)
buildHtml(hDiv)
buildHtml(tagDiv)
component code
component Comp:
`template`:
tDiv:
slot
component usage
"/":
component Comp:
"Hello world"
in created component "Hello world"
will used instead of slot
statement
You can use return
statement for response:
"/path....":
return "Hello, world!"
"/...":
return buildHtml:
...
Minimal ex:
buildStyle:
.className:
color: red
background-color: rgba(255, 255, 255, 0.1)
body:
display: none
Make human readable errors
Minimal ex:
server.routes:
"/":
"Hello, world!"
Example:
type Language = enum
lNim = "nim",
lPython = "python",
lJavaScript = "javascript"
serve "127.0.0.1", 5000:
get "/language/{lang:enum(Language)}":
# lang is lNim by default
echo lang
Example syntax:
{{variableName}}
for variables{| if condition |} ... {| end |}
for if
stmt{| elif condition |} ... {| end |}
for elif
stmt{| else |} ... {| end |}
for else
stmt{| for item in array|} ... {| end |}
for for
stmt{{variableName + otherVariable}}
for evaluate{| func name(arg1, arg2, ...) |} ... {| end |}
and {{ name(arg1, arg2, ...)}}
for functionsWrite PURE JavaScript in PURE Nim 👀
It uses emit pragma
Simple syntax:
buildJs:
# translates into
# import { something } from "....";
import { something } from "...."
# translates into
# let name = 123;
var name = 123
# translates into
# const name1 = 123;
# const name2 = 123;
let name1 = 123
const name2 = 123
# translates into
# let arr = [2, 4, 3, 2, 1]
var arr = [2, 4, 3, 2, 1]
# translates into
# for (var i = 0; i < 10; ++i) { ... }
for i in 0..10:
...
# translates into
# function func(a, b, c, d) { ... }
function func(a, b, c, d):
# translates into
# console.log( ... )
console.log(...)
# translates into
# console.log( ... )
echo ...
# translates into
# class Rectangle extends Object { ... }
class Rectangle extends Object:
# translates into
# #privateField
privateField
# translates into
# publicField
pub publicField
# translates into
# constructor( ... )
constructor( ... ):
# translates into
# this.publicField = ...
self.publicField = ...
# translates into
# methodName(...)
methodName(...):
...
# Using nim variables:
echo ~nimVar
serve
command will build and serve your HappyX project at host and port that you need.
hpx serve --port 8000 --host 0.0.0.0
https://web-frameworks-benchmark.netlify.app/result?l=nim.
just found it became top of nim web frameworks at this round. from bottom to top. just wondering why
Hey, I hope you doing OK
I think it would be informative to have this in your readme, since jester
is well-known among Nim programmers.
May be anyone want to help me? 👀
Minimal ex:
app.routes:
"/":
"Hello, world"
Example syntax:
server.routes:
get("/"):
req answer "get method!"
post("/"):
req answer "post method!"
Example:
Make routing simple like routing in SSG
Describe the bug 🐛
hpx create crashes:
❯ hpx create
New HappyX project ...
Project name: syncio.nim(161) raiseEOF
Error: unhandled exception: EOF reached [EOFError]
To Reproduce 👨🔬
Steps to reproduce the behavior:
nimble install happyx
$ hpx create
Expected behavior 🤔
Asked to input project name
Tried to use HappyX today but I'm a bit confused. Basically I just wanted to try out a very simple SSG with some static HTML/CSS files and a route to catch the input from a form. I created my project using hpx create --name test --kind SSG
and it created the project structure for me. I dropped some files into the public
folder but the server doesn't seem to serve these files. Looked at the examples and the only one which appears to do this is the nim-lang
one and it appears to serve them with the public
prefix on, however trying that didn't make it serve my file either. So I'm not sure if I need to do something to make HappyX serve the files from the public
directory or not, it doesn't log requests either so I don't really know what's going on..
This was tested with the latest tagged version of HappyX (which is the 1.0.0 release)
The project structure is simply the one created by hpx create --name test --kind SSG
with an additional file added in the src/public
folder.
The code is exactly what was generated. I looked at the nim-lang site example which has a public folder but couldn't see any special handling of it.
Describe the bug 🐛
Whenever I run hpx dev
on my SPA project it gives this error:
oserr.nim(95) raiseOSError
Error: unhandled exception: No such file or directory
Additional info: nim [OSError]
Shutdown ...
To Reproduce 👨🔬
Steps to reproduce the behavior:
hpx create
cd
into the created folderhpx dev
Expected behavior 🤔
That hpx dev
would run my code
Desktop (please complete the following information): 💻
Additional context ✌
I have also been able to replicate this issue with the base https://Replit.com template ChooseNim and installing happyx.
Basic syntax:
...
server.routes:
"/regex/pattern{patternId:/[a-zA-Z0-9_]/}"
echo patternId
Export project from Figma and convert it into HappyX project via CLI.
hpx figma2hpx linkToProject
This needs Figma API token
Simple syntax:
regCORS:
credentials: true
origins: "*"
methods: "*"
headers: "*"
Is your feature request related to a problem? Please describe. 🤔
Component manipulation is limited. If components are objects, the meaning of the component tag should be to place any component into the document, no matter how it is produced or identified. One can declare a component that modifies its own state by referencing itself.
component HelloWorld:
y : int = 17
`template`:
tDiv:
"Hello, world {self.y}!"
tButton:
"change world"
@click:
self.y += 1
However, one cannot even bind a component to an identifier and then add it to the document by the identifier. If we say
var hw = initHelloWorld("hw", y=88)
then
hw
will fail to render anything, and 'component hw' will fail because the renderer currently assumes that we need to initialize a new component whenever we use the component
tag.
Describe the solution you'd like 💡
component hw
should render to the document in the same way component HelloWorld(y=88)
would.
In line with the goal of having methods and other things that modify component fields, any other changes required for the normal features of object declaration and field access to work should be implemented. I note, for example that one cannot declare exported fields with *
Describe alternatives you've considered 💁♀️
Since text gets rendered just by placing the text node, it might be argued that the component tag should not exist at all and that the macro should just render any statement that results in a component in the same way. However I don't think its likely to be worth the change in the documented API
One can wrap components in some other datatype that houses the state which can be publicly modified, but this would be a needless addition of a new type that the programmer needs to juggle. stateful components are the only datatype that the programmer will really want to deal with.
By default library will provide own template engine.
With flag -d:nimja
library will use Nimja
template engine
Describe the bug 🐛
The hpx program fails to read path and thus is unable to run nim for compilation.
To Reproduce 👨🔬
hpx build
on examples/todoExpected behavior 🤔
No crashes
Desktop (please complete the following information): 💻
Additional context ✌
🥱
Simple syntax:
mount MyMount:
"/path/<param>[modelname:SmthModel]":
...
Usage in SSG:
serve(...):
mount "/mount" -> MyMount
Usage in SPA:
appRoutes(...):
mount "/mount" -> MyMount
Commands:
create
: Creates a new project with happyx
.project/
├─ public/
├─ .gitignore
├─ README.md
├─ src/
├─ app.nim
dev
: Run hotreloader server for SPA
projectbuild
: Build standalone SPADescribe the bug 🐛
Component updating creates multiple instances of static content.
To Reproduce 👨🔬
Stick with
component HelloWorld:
y: int = 17
`template`:
tDiv:
"Hello, world {self.y}!"
tButton:
"change world"
@click:
self.y += 1
Then place component in app and run. Click the button to update the parameter. The component button gets duplicated , though the message itself is replaced normally.
Before latest commit to 1.9.0, it worked normally.
Desktop (please complete the following information): 💻
When user changing component he need to rerender page. But after solving problem component will renders only self
We need to smart JS renderer
HappyX have dev
command that provides hot code reloading to working with SPA
project.
I tried write some code to make HCR for SSG, but outputStream of ssg script Process is freezes.
Simple syntax:
pathParams:
arg? int[m] = 100 # means that param "arg" is optional mutable integer with default value 100
# We can use human readable syntax also
arg1 string:
optional
mutable
default = "Hello"
And in routes we just use:
"/user<arg>"
"/data<arg1>"
Is your feature request related to a problem? Please describe. 🤔
It's frustrating to always have strings piped through the various macro layers such as strformat. On the frontend, it's still going to be better sometimes to pass or accept data from external JS scripts that communicate with literal strings.
Describe the solution you'd like 💡
An equivalent idiom of Karax's verbatim, for direct injection of HTML->Dom would be nice.
In line with the idea of taking care of things under the hood, it would also be good to recognize the raw string literal types nnkStrLit..nnkTripleStrLit
from nim and never apply strformat to them.
Describe alternatives you've considered 💁♀️
text tags from karax are acceptable for me since I use code snippets, but the more macro intensive approach here seems to want to be more aggressive about minimizing keystrokes along with boilerplate
Additional context ✌
I don't know how much you've tried to squeeze out of Karax in its current state, but here are the idioms for JS scripts that I'm familiar with in the buildHtml environment there:
script(): text """
var params = {"appName": "graphing", "width": 800, "showTaskbar": true}
var myApp = new App(params,true)
myApp.inject("myID")
"""
Note that since JS is untyped, there can be some strange datatypes that are hard to exchange between nim and js. This means that some things from external libraries are better off implemented as pure JS commands, especially in an initial testing phase that needs to be quick. Another natural use case is talking about the literal syntax of code, which is one thing that one would naturally want to do on websites:
text """to properly template the string with the right user id and score, you type:"""
tdiv(class="code"):
text """ Your score is {{ fmt{score,0.2d} }}"""
There are many uses for a verbatim as well. One that I am familiar with is inputting mathematics. MathML is excessively verbose, so inputting latex is better. But both MathJax and katex (in auto-render mode) fight with Karax' control of the DOM at present and shut down Karax' reactivity. So the next best bet is to bind katex ability to render string to mathML and then inject it into the DOM verbatim
proc renderToStringKatex(s:kstring): kstring {.importjs: "katex.renderToString(@)" .}
proc renderKatex(s:kstring): VNode = buildHtml:
verbatim(renderToStringKatex(s))
Then build from there to interpolation of strings with inline latex. Note that this is considerable effort compared with having Katex' auto-render work correctly out of the box. One thing that your approach with routing on the front end seems to help with is giving a little bit more leeway to other reactive scripts while still getting its own job done!
Using routes on the front-end DSL should help a lot for writing code in a common source file while effectively managing user experience and computational resources.
Directory:
root/
dir/
file.png
other/
file.txt
Script:
...
server.roues:
staticDir "dir"
Now any API_URL/dir/...
will return file
Simple usage:
model MyModel:
password: string
login: string = "default value"
age: int
....
serve(...):
"/[model:MyModel]":
echo model.login
MyModel
is JSON body that should be sended to "/"
route
Minimal ex:
var
num = 3
html =
buildHtml(tDiv):
case num:
of 1:
h1
of 2:
h2
of 3:
h3
else:
h4
Make middleware in server.nim
Is your feature request related to a problem? Please describe. 🤔
I want to be able to download the file sent using answerFile instead of displaying it inline, and to do that you can add ("Content-Disposition", "attachment")
to the http headers, but answerFile does not expose its HttpHeaders
Describe the solution you'd like 💡
allow some way of allowing files to be sent as attachments instead of inline
Describe alternatives you've considered 💁♀️
Could alternatively allow passing an HttpHeaders argument like answer accepts and then append the content type if it doesn't exist or something.
Minimal ex:
var html = buildHtml(`div`):
button:
"Button text"
@click:
echo "Button clicked!"
Components will returns HTML
Minimal ex:
# You can use without "ComponentName"
# Then component name takes from file name
component "ComponentName":
`template`:
# buildHTML here with nim variables
`style`:
# Styles here with nim variables
`script`:
# Nim code here
Minimal ex:
var
count = remember 0
app = newApp()
app.routes:
"#/":
count = count + 1
buildHtml(`div`):
button()
app.start()
Simple syntax:
initServer:
var server = newServer()
server.routes:
"/":
req.answer "Hi"
server.start()
serve("127.0.0.1", 5000):
"/":
req.answer "Hi"
It's will be nice shortcut for
proc main() =
var server = newServer()
server.routes:
"/":
req.answer "Hi"
server.start()
main()
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.