Giter Site home page Giter Site logo

hapticx / happyx Goto Github PK

View Code? Open in Web Editor NEW
444.0 10.0 16.0 42.78 MB

Macro-oriented asynchronous web-framework written in Nim with ♥

Home Page: https://hapticx.github.io/happyx/

License: MIT License

Nim 87.68% HTML 0.62% Python 3.52% Batchfile 0.15% TypeScript 2.28% Java 4.87% Kotlin 0.84% Dockerfile 0.03%
nim web web-framework happyx open-source spa ssr backend frontend full-stack

happyx's People

Contributors

arikrahman avatar derekdai avatar ethosa avatar foxoman avatar horanchikk avatar levovix0 avatar mcrusher avatar moigagoo avatar monocoder avatar svenrdz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

happyx's Issues

Slots In Components ✨

component code

component Comp:
  `template`:
    tDiv:
      slot

component usage

"/":
  component Comp:
    "Hello world"

in created component "Hello world" will used instead of slot statement

Rerendering for components

When user changing component he need to rerender page. But after solving problem component will renders only self

State management in `SPA`

Minimal ex:

var
  count = remember 0
  app = newApp()

app.routes:
  "#/":
    count = count + 1
    buildHtml(`div`):
      button()

app.start()

CORS 🔥

Simple syntax:

regCORS:
  credentials: true
  origins: "*"
  methods: "*"
  headers: "*"

handle methods in `routes`

Example syntax:

server.routes:
  get("/"):
    req answer "get method!"
  post("/"):
    req answer "post method!"

Syntax Sugar For Routing 🔥

Simple syntax with SSG:

"/path/<arg>[m:MyModel]" -> get:
  ...

serve(...):
  ...

Simple syntax with SPA:

"/path/<arg>[m:MyModel]" -> page:
  ...

appRoutes(...):
  ...

Enums in path params🔥

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

Dev mode for `SSG` projects 🛠

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.

Components Life Cycle

Example:

  • create - call only one time at page loaded
  • beforeUpdate- call before every rerender
  • update - call every rerender
  • exit - call only one time at page exit

OSError on hpx dev 🐛

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:

  1. Create a new SPA project with hpx create
  2. cd into the created folder
  3. Run hpx dev
  4. Observe the error

Expected behavior 🤔
That hpx dev would run my code

Screenshots 🖼
image

Desktop (please complete the following information): 💻

  • OS: MacOS
  • Browser: N/A
  • Version: 0.17.0

Additional context
I have also been able to replicate this issue with the base https://Replit.com template ChooseNim and installing happyx.

Models For Requests🔥

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

stateful components should have easily manipulable internal state🔥

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 💡

  1. component hw should render to the document in the same way component HelloWorld(y=88) would.
    image

  2. 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.

`SSG` Syntax Sugar 🔥

You can use return statement for response:

"/path....":
  return "Hello, world!"
"/...":
  return buildHtml:
    ...

Assign path params before usage

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>"

Stylesheets ✨

Minimal ex:

buildStyle:
  .className:
    color: red
    background-color: rgba(255, 255, 255, 0.1)
  body:
    display: none

Template engine

By default library will provide own template engine.
With flag -d:nimja library will use Nimja template engine

`buildJs` macro 🔥

Write 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

Events in `buildHtml`

Minimal ex:

var html = buildHtml(`div`):
  button:
    "Button text"
    @click:
      echo "Button clicked!"

Lacking documentation for the `public` directory

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.

Found Bug 🐛

Describe 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.

image

Before latest commit to 1.9.0, it worked normally.
Desktop (please complete the following information): 💻

  • OS: [linux x64]
  • Browser [chrome version 113]

hpx create crashes 🐛

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

Write CLI for build and create projects

Commands:

  • create: Creates a new project with happyx.
    Generated project structure may be:
    project/
    ├─ public/
    ├─ .gitignore
    ├─ README.md
    ├─ src/
       ├─ app.nim
    
  • dev: Run hotreloader server for SPA project
  • build: Build standalone SPA

`serve` CLI command 🔥

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

make `initServer` and `serve` macros

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()

Own template engine 🤔

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 functions

raw / verbatim / literals

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.

Fixed UNIX path bug 🐛

Describe the bug 🐛
The hpx program fails to read path and thus is unable to run nim for compilation.

To Reproduce 👨‍🔬

  1. Use a UNIX machine
  2. attempt hpx build on examples/todo

Expected behavior 🤔
No crashes

Desktop (please complete the following information): 💻

  • OS: Arch Linux

Additional context
🥱

Add asAttachment argument to answerFile proc

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.

Components for `SPA`

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

Write More Docs 📕

  • Mounting 🔌
  • CORS ⚙
  • Request Models 🔨
  • SSG tutorial 📕
  • SPA tutorial 📕
  • Style Guide 🎴

May be anyone want to help me? 👀

Expanded Routing - Mouting🔥

Simple syntax:

mount MyMount:
  "/path/<param>[modelname:SmthModel]":
    ...

Usage in SSG:

serve(...):
  mount "/mount" -> MyMount

Usage in SPA:

appRoutes(...):
  mount "/mount" -> MyMount

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.