Project tell
Pushup is an experiment. By strategy of the boost life cycle, it’ll restful be regarded as preview pre-free up tool: it is miles largely life like, most likely has essential bugs (together with doable for recordsdata loss) and/or subpar efficiency, but is upright for demos and testing. It has a factual unit test suite, together with fuzzing test cases for the parser. Construct no longer rely on it for the rest serious but, and inquire of considerable breaking changes.
- Pushup – a page-oriented net framework for Trip
Pushup is an experimental unique conducting that is exploring the viability of a brand unique
formulation to net frameworks in Trip.
Pushup seeks to produce building page-oriented, server-aspect net apps the usage of Trip
straightforward. It embraces the server, while acknowledging the actuality of as much as the moment net
apps and their enhancements to UI interactivity over outdated generations.
What is Pushup?
Pushup is a program that compiles initiatives developed with the Pushup markup
language into standalone net app servers.
There are three main aspects to Pushup:
- An opinionated conducting/app itemizing structure that enables file-basically based mostly totally
routing, - A light-weight markup various to venerable net framework templates
that combines Trip code for lend a hand watch over dart alongside with the movement and crucial, peep-controller-admire
code with HTML markup, and - A compiler that parses that markup and generates pure Trip code,
building standalone net apps on high of the Trip stdlibreceive/http
kit.
Pages in Pushup
The core object in Pushup is the “page”: a file with the .up
extension that
is a mix of HTML, Trip code, and a steady-weight markup language that glues them
together. Pushup pages take half in URL routing by virtue of their path in
the filesystem. Pushup pages are compiled into pure Trip which is then built
together with a skinny runtime into a standalone net app server (which is all
receive/http
beneath the hood).
The principle proposition motivating Pushup is that the page is the kindly stage of
abstraction for rather a lot of forms of server-aspect net apps.
The syntax of the Pushup markup language looks admire this:
The time is now ^time.Now().String().
^if time.Now().Weekday()==time.Friday {
It’s Friday! Enjoy the start to your weekend.
} ^else {
Have a great day, we’re glad you’re here.
}
“>
^import "time"
^{
title :="Good day, from Pushup!"
}
^title
The time is now ^time.Now().String().
^if time.Now().Weekday()==time.Friday {
Or no longer it is Friday! Accept pleasure from the open to your weekend.
} ^else {
Salvage a wide day, we're happy that you just need to well additionally very effectively be right here.
}
You need to well then predicament this code in a file somewhere in your app/pages
itemizing, admire hello.up
. The .up
extension is foremost and tells
the compiler that it is a Pushup page. When you originate and chase your Pushup app,
that page is robotically mapped to the URL path /hello
.
Getting began
To present a brand unique Pushup app, first set up the vital Pushup executable.
Installing Pushup
Requirements
- dart 1.18 or later
Make optimistic that the itemizing where the dart instrument installs executables is in your
$PATH
. It is $(dart env GOPATH)/bin
. That you can additionally test if right here is the case with:
echo $PATH | grep $(dart env GOPATH)/bin > /dev/null && echo yes || echo no
Install an reputable free up
Accumulate Pushup in your platform from the releases page.
Install by blueprint of git
git clone git@github.com:AdHocRandD/pushup.git
cd pushup
produce
dart set up
Install by blueprint of Make optimistic that you just’ve gotten Trip effect in (at least model 1.18), and sort:
dart set up github.com/adhocteam/pushup@most up-to-date
Increasing a brand unique Pushup conducting
To compose a brand unique Pushup conducting, use the pushup unique
order.
With none further arguments, it’ll are trying to compose a scaffolded unique
conducting within the most fresh itemizing. Nonetheless, the itemizing must restful be fully
empty, or the order will abort. To simulataneously produce a brand unique itemizing
and generate a scaffolded conducting, pass a relative path as argument:
The scaffolded unique conducting itemizing features a itemizing structure for
.up files and auxiliary conducting Trip code, and a dart.mod file.
Substitute to the unique conducting itemizing if foremost, then terminate a pushup chase
,
which compiles the Pushup conducting to Trip code, builds the app, and starts up
the server.
If all goes effectively, you’ll want to always restful search a message on the terminal that the Pushup app
is running and listening on a port:
↑↑ Pushup ready and listening on 0.0.0.0: 8080 ↑↑
By default it listens on port 8080, but with the -port
or -unix-socket
flags that you just need to well take your win listener.
Launch http://localhost: 8080/ in your browser to explore
the default structure and a welcome index page.
Example demo app
Inspect the instance itemizing for a demo Pushup app that demonstrates
many of the ideas in Pushup and implements just a few diminutive total patterns admire
some HTMX examples and a straightforward CRUD app.
Click on “peep source” on the underside of any page within the instance app to explore the
source of the .up page for that route, together with the source of the “peep
source” .up page itself. Here is a factual technique to explore be taught how to write Pushup
syntax.
Trip modules and Pushup initiatives
Pushup treats initiatives as their very win self-contained Trip module. The originate
path of assumes right here is the case by default. But it is miles that that you just need to well factor in to incorporate a
Pushup conducting as piece of a mother or father Trip module. Inspect the the -module
likelihood to
pushup unique
, and the -originate-pkg
likelihood to the pushup chase
order.
Project itemizing structure
Pushup initiatives win a explicit itemizing structure that the compiler expects
earlier than building. The most minimal Pushup conducting would explore admire:
app
├── layouts
├── pages
│ └── index.up
├── pkg
└── static
dart.mod
Pages
Pushup pages are the vital devices in Pushup. They are a mix of logic and
lisp material. It’s going to be essential to evaluate about them as both the controller and the peep
in a MVC-admire machine, but colocated together within the identical file.
They are also the foundation of file-basically based mostly totally routing: the name of the Pushup file,
minus the .up extension, is mapped to the percentage of the URL path for
routing.
Layouts
Layouts are HTML templates that passe on the total across rather a lot of pages. They are
factual HTML, with Pushup syntax as foremost. Every page renders its contents, and
then the structure inserts the page contents into the template with the
^outputSection("contents")
Pushup expression.
Static media
Static media files admire CSS, JS, and footage, can even be added to the app/static
conducting itemizing. These will most likely be embedded straight away within the conducting executable
when it is miles built, and are accessed by blueprint of a straightforward mapping beneath the
“/static/” URL path.
File-basically based mostly totally routing
Pushup maps file locations to URL route paths. So about.up
turns into
/about
, and foo/bar/baz.up
turns into /foo/bar/baz
. Extra TK …
Dynamic routes
If the filename of a Pushup page starts with a $
greenback ticket, the percentage
of the URL path that suits will most likely be readily available to the page by blueprint of the getParam()
Pushup API technique.
For example, to illustrate there is a Pushup page at app/pages/of us/$identity.up
.
If a browser visits the URL /of us/1234
, the page can entry it admire a named
parameter with the API technique getParam()
, as an illustration:
ID: ^getParam(req, "identity")
would output:
The name of the parameter is the be aware following the $
greenback ticket, as much as a dot
or a slice. Conceptually, the URL route is /of us/:identity
, where :identity
is the
named parameter that is substituted for the right price within the ask URL.
Directories can even be dynamic, too. app/pages/merchandise/$pid/diminutive print.up
maps
to /merchandise/:pid/diminutive print
.
A pair of named parameters are allowed, as an illustration, app/pages/users/$uid/initiatives/$pid.up
maps to /users/:uid/initiatives/:pid
.
Enhanced hypertext
Inline partials
Inline partials allow pages to denote subsections of themselves, and allow
for these subsections (the inline partials) to be rendered and returned to
the patron independently, and not using a have to render your complete enclosing page.
In total, partials in templating languages are saved in their very win files,
that are then transcluded into quite just a few templates. Inline partials, then over again, are
partials declared and outlined in-line a mother or father or together with template.
Inline partials are functional when blended with enhanced hypertext alternate strategies
(eg., htmx). The motive is that these sites produce AJAX
requests for partial HTML responses to replace parts of an already-loaded
doc. Partial responses assign no longer win enclosing markup corresponding to shocking
templates applied by the templating engine, since that will destroy the of the
doc they’re being inserted into. Inline partials in Pushup robotically
disable layouts in inform that partial responses win factual the lisp material they clarify.
The flexibility to rapid clarify partials, and no longer need to take care of complexities
admire toggling off layouts, makes it much less difficult to originate enhanced hypertext sites.
Overall net framework efficiency
All as much as the moment net frameworks must restful put in pressure a odd predicament of efficiency,
spanning from security to convenience. As of this writing, Pushup would no longer but
put in pressure all of them, but aspires to forward of any public free up.
Escaping
By default, all lisp material is HTML-escaped, so on the total it is miles secure to straight away
predicament user-provided recordsdata into Pushup pages. (Point out that the framework does
no longer (but) terminate this in your Trip code, recordsdata from make submissions and URL queries
must restful be validated and handled as unsafe.)
For example, within the occasion you wished to blow their own horns on the page the demand a user searched for,
right here is secure:
^{ demand :=req.FormValue("demand") }
You glance: ^demand
Pushup syntax
How it genuinely works
Pushup is a mix of a brand unique syntax consisting of Pushup directives and key phrases,
Trip code, and HTML markup.
Parsing a .up file continuously starts out in HTML mode, so that you just need to well factual effect
undeniable HTML in a file and that’s the reason an incredible Pushup page.
When the parser encounters a ‘^’ character (caret, ASCII 0x5e) while in
HTML mode, it switches to parsing Pushup syntax, which includes straightforward
directives, lend a hand watch over dart alongside with the movement statements, block delimiters, and Trip expressions. It
then switches to the Trip code parser. As soon because it detects the hand over of the directive,
assertion, or expression, it switches lend a hand to HTML mode, and parsing continues
in a identical vogue.
Pushup uses the tokenizers from the dart/scanner and
golang.org/x/receive/html packages, so it’ll restful be ready to take care of
any tremendous syntax from both language.
Directives
^import
Employ ^import
to import a Trip kit into the most fresh Pushup page. The syntax
for ^import
is the identical as a usual Trip import declaration
Example:
^import "strings"
^import "strconv"
^structure
Layouts are HTML templates that enclose the contents of a Pushup page.
The ^structure
directive instructs Pushup what structure to prepare the contents of
the most fresh page.
The name of the structure following the directive is the filename within the
layouts
itemizing minus the .up
extension. For example, ^structure main
would are trying to prepare the structure situated at app/layouts/main.up
.
^structure
is no longer foremost – whether it is no longer specified, pages robotically receive the
“default” structure (app/layouts/default.up
).
Example:
^structure !
– no structure
A page could per chance take to haven’t any structure applied – that is, the contents of the page
itself are despatched straight away to the patron and not using a enclosing template. In this case,
use the !
name:
Trip code blocks
^{
To encompass statements of Trip in a Pushup page, kind ^{
adopted by your
Trip code, terminating with a closing }
.
The scope of a ^{ ... }
within the compiled Trip code is equal to its surrounding
markup, so that you just need to well clarify a variable and straight away use it:
^{
name :="world"
}
Good day, ^name!
Since the Pushup parser is most efficient attempting for a balanced closing }
, blocks
can even be one-liners:
^{ name :="world"; greeting :="Good day" }
^greeting, ^name!
A Pushup page can win zero or many ^{ ... }
blocks.
^handler
A handler is corresponding to ^{ ... }
. The adaptation is that there’ll most likely be at most
one handler per page, and it is miles chase forward of any quite just a few code or markup on the
page.
A handler is the correct predicament to terminate “controller”-admire (within the MVC sense)
actions, corresponding to HTTP redirects and errors. In quite just a few phrases, any lend a hand watch over dart alongside with the movement
in accordance with the nature of the ask, as an illustration, redirecting after a a hit
POST to compose a brand unique object in a CRUD operation.
Example:
^handler {
if req.System=="POST" && formValid(req) {
if err :=createObjectFromForm(req.Construct); err==nil {
return http.Redirect(w, req, "/success/", http.StatusSeeOther)
return nil
} else {
// error facing
...
}
...
}
...
Point out that handlers (and all Pushup code) chase in a technique on a receiver that
implements Pushup’s Responder
interface, which is
interface Responder { Acknowledge(http.ResponseWriter, *http.Request) error }
To exit from a page early in a handler (i.e., forward of any odd lisp material being
rendered), return from the technique with a 0 (for success) or an error (which
will on the total answer with HTTP 500 to the patron).
Alter dart alongside with the movement statements
^if
^if
takes a boolean Trip expression and a block to conditionally render.
Example:
}”>
^if demand :=req.FormValue("demand"); demand !="" {
Search recordsdata from: ^demand
}
^for
^for
takes a Trip “for” assertion condition, clause, or range, and a block,
and over again and over again executes the block.
Example:
^for i :=0; i Number ^i
}
Expressions
Straightforward expressions
Straightforward Trip expressions can even be written with factual ^
adopted by the expression.
“Straightforward” formulation:
- variable names (eg.,
^x
) - dotted self-discipline name entry of structs (eg.,
^epic.name
) - characteristic and technique calls (eg.,
^strings.Repeat("x", 3)
) - index expressions (eg.,
a[x]
)
Example:
^{ name :="Paul" }
Good day, ^name!
Outputs:
Peep that the parser stops on the “!” on epic of it knows it is no longer piece of a
Trip variable name.
Example:
The URL path: ^req.URL.Route
Outputs:
p>The URL path: /foo/barp>
Example:
^import "strings"
^strings.Repeat("Good day", 3)
Outputs:
Instruct expressions
Instruct expressions are written with ^
and adopted by any tremendous Trip
expression grouped by parentheses.
Example:
^{ numPeople :=4 }
With ^numPeople of us there are ^(numPeople 2) arms
Outputs:
p>With 4 of us there are 8 armsp>
Format and templates
^piece
Pushup layouts can win sections real thru the HTML doc that Pushup pages
can clarify with their very win lisp material to be rendered into these locations.
For example, a structure will win a sidebar piece, and each page can predicament
its win sidebar lisp material.
In a Pushup page, sections are outlined with the keyword admire so:
^piece sidebar {
Here is my sidebar lisp material
Extra to return
}
Layouts can output sections with the outputSection
characteristic.
Layouts could produce sections no longer foremost, by first checking if a page has predicament a
piece with sectionDefined()
, which returns a boolean.
}”>
^if sectionDefined("sidebar") {
}
Checking for if a section was predicament by a page lets a structure dressmaker present
default markup that could even be overridden by a page.
} ^else {
}”>
^if sectionDefined("title") {
^outputSection("title")
} ^else {
Welcome to our assign
}
^partial
Pushup pages can expose and clarify inline partials with the ^partial
keyword.
...
Facets
^partial list {
- Ag
- Na
- C
}
...
A ask to the page containing the preliminary partial will render in most cases,
as if the block where no longer wrapped in ^partial list {
… }
.
A ask to the page with the name of the partial appended to the URL path
will answer with factual the lisp material scoped by the partial block.
For example, if the page above had the route /aspects/
, then a ask to
/aspects/list
would output:
ul>
li>Agli>
li>Nali>
li>Cli>
ul>
Inline partials can nest arbitrarily deep.
...
^partial leagues {
Leagues
^partial groups {
Groups
^partial gamers {
Gamers
}
}
}
...
To ask a nested partial, produce distinct the URL path is preceded by
each containing partial’s name and a forward slice, as an illustration,
/sports actions/leagues/groups/gamers
.
Vim syntax file
There is a vim plugin within the vim-pushup
itemizing. You’ve to be ready to symlink it into your plugin supervisor’s path. Alternatively, to set up it manually:
- Stumble on or compose a
syntax
itemizing in your vim config itemizing (In total~/.vim/syntax
for vim or~/.config/nvim/syntax
for neovim) - Reproduction
syntax/pushup.vim
into that itemizing - Stumble on or compose a
ftdetect
itemizing in your vim config itemizing (In total~/.vim/syntax
for vim or~/.config/nvim/syntax
for neovim) - Reproduction
ftdetect/pushup.vim
into that itemizing